Files
proxmox/docs/04-configuration/MIM4U_UX_UI_TECHNICAL_REVIEW.md
defiQUG 4f97e27f69
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
MIM4U: nginx install/deploy/backup scripts, rate limit, CSP, docs; submodule pointer; txpool retry script
Made-with: Cursor
2026-02-26 22:35:24 -08:00

220 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MIM4U (mim4u.org) — Technical UX/UI Review & Punch List
**Last Updated:** 2026-02-26
**Document Version:** 1.0
**Status:** Active — Dev handoff
**Context:** Hosted LXC content — VMID 7810 (mim-web-1), VMID 7811 (mim-api-1), NPMplus proxy
---
## Scope
This document captures a technical UX/UI review of **mim4u.org** (Miracles in Motion) based on publicly indexable content. The site is largely JS-rendered (client-rendered), so the review focuses on patterns that commonly affect UX on modern marketing/nonprofit builds. It is intended as a **prioritized punch list** for the dev team working on the **miracles_in_motion** codebase and the LXC-hosted deployment.
**Hosting (this repo):**
| Asset | Detail |
|-------|--------|
| **Web frontend** | VMID 7810 (mim-web-1) — Nginx + static/SPA |
| **API backend** | VMID 7811 (mim-api-1) — Azure Functions (port 3001) |
| **Domains** | mim4u.org, www.mim4u.org, secure.mim4u.org, training.mim4u.org |
| **Proxy** | NPMplus → `http://192.168.11.37:80` (see [NPMPLUS_SERVICE_MAPPING_COMPLETE.md](./NPMPLUS_SERVICE_MAPPING_COMPLETE.md)) |
| **App source** | Submodule: [miracles_in_motion](https://github.com/Order-of-Hospitallers/miracles_in_motion) |
**Related docs:**
- [MIM4U_502_ERROR_RESOLUTION.md](./MIM4U_502_ERROR_RESOLUTION.md) — 502 resolution (nginx/service on 7810)
- [MIM4U_FIRST_PARTY_ANALYTICS.md](./MIM4U_FIRST_PARTY_ANALYTICS.md) — First-party `/api/events` endpoint for ad-blocker-resistant analytics
- [NPMPLUS_SERVICE_MAPPING_COMPLETE.md](./NPMPLUS_SERVICE_MAPPING_COMPLETE.md) — Domain → VMID mapping
---
## Whats Working (UX Thats Technically Sound)
- **Clear information architecture + task-first nav**: Top-level items (Stories, Volunteers, Corporate, Get Help, Portals, Donate) map cleanly to user intents.
- **Strong primary CTAs above the fold**: Donate now, Volunteer, Read stories — reduce decision friction and support conversion.
- **Trust + transparency blocks**: “Where your donation goes (85/10/5)”, “Average grant: $48 / $72”, partners list, impact-report mention — good for credibility and SEO when implemented as real text (not only images).
- **Process clarity**: “Designed with counselors… verified same-day… approved within 24 hours… no uploads required” — step-by-step flow that can reduce form abandonment.
---
## Technical UX Risks (Common on Client-Rendered Builds)
### 1) Performance (Core Web Vitals)
- **LCP risk**: Hero sections often use large background images/video + web fonts; unoptimized they cause “blank screen” lag on mobile/slow networks.
- **CLS risk**: Late-loading fonts, cookie banners, or impact counters can shift layout (conversion-negative).
- **INP risk**: Heavy script bundles (analytics, donation widgets, sliders) can delay taps/scroll.
**Actions:**
- Hero image: responsive (`srcset`), compressed, and preloaded if its the LCP element.
- Defer non-critical JS (chat, A/B, extra trackers).
- Use `font-display: swap` and consider self-hosting fonts.
### 2) Accessibility (WCAG/ADA)
From the visible structure (multiple CTAs, sections, cookie banner):
- Keyboard: full tab flow through Donate / Get Help / Portals without traps.
- Visible focus states on links/buttons (especially CTAs).
- One H1, logical H2/H3.
- Color contrast on hero text/buttons.
- Cookie banner: fully operable by keyboard + screen reader; no blocking without focus management.
**Actions:**
- Add “Skip to content” link.
- Ensure CTAs have accessible names (avoid repeated “Learn more” without context).
- ARIA labels on nav/menu toggles (mobile).
### 3) Forms / “Get Help” Workflow
Copy promises speed and dignity (“one-page referral, no uploads required”). Technically this depends on:
- Inline, specific validation (not generic red banners).
- Auto-save / resilience on mobile.
- Spam protection that doesnt punish legitimate users (avoid hostile CAPTCHAs).
- Confirmation loop (“we confirm support reached the student”) — ensure privacy disclosures reflect data handling.
### 4) Security & Privacy (Especially “Portals”)
Portals imply authenticated access:
- HTTPS everywhere + HSTS.
- Strong session cookie flags: `HttpOnly`, `Secure`, `SameSite`.
- Content Security Policy (CSP) to reduce XSS (e.g. from embedded donation tools).
- No PII in URLs/query strings (referrals, student needs).
- Cookie choices must persist; dont load marketing tags before consent.
### 5) SEO + Discoverability
Key content is client-rendered; indexing can be inconsistent. Homepage text is indexable — maintain and improve:
- Prefer SSR or static generation for public pages where feasible.
- Clean metadata (title/description per page/section).
- Structured data: Organization + DonateAction.
- “Impact report” as a crawlable page (not only a modal).
---
## High-Impact Quick Wins
1. **Run Lighthouse on mobile** and fix:
- LCP image optimization + preload
- Reduce unused JS
- Eliminate layout shift (banner/fonts)
2. **Accessibility pass**: keyboard flow, focus visibility, heading hierarchy.
3. **CTA instrumentation**: track Donate / Get Help / Volunteer separately; verify events fire with ad blockers in mind.
4. **Portals hardening**: CSP, secure cookie configuration, rate limiting on auth endpoints.
---
## Concrete Technical Checklist (Dev Handoff)
| Area | Target / Requirement |
|------|----------------------|
| **Core Web Vitals** | LCP < 2.5s, CLS < 0.1, INP < 200ms (mobile) |
| **Images** | Responsive, compressed, lazy-load below fold |
| **Fonts** | `font-display: swap`, limit variants, preconnect if external |
| **JS** | Defer non-critical, minimize third-party scripts |
| **A11y** | Skip link, focus states, ARIA labels, contrast, form error messaging |
| **Security** | HSTS, CSP, secure cookies, no PII in URLs, audit third-party embeds |
| **SEO** | SSR/SSG for public pages where possible, metadata, sitemap/robots, schema.org Organization |
---
## Implemented (2026-02-26)
- **A11y**: Skip-to-content link (focus-only, targets `#content`), focus-visible on hero CTAs and mobile nav links, ARIA labels on Donate/Get Help.
- **SEO**: Canonical/OG URLs and schema.org base URL set to `https://mim4u.org`; DonateAction JSON-LD added alongside Organization.
- **Performance**: Font preload for Inter (critical weights) in `index.html`; preconnect already present; `display=swap` in font URL.
- **Deploy (proxmox)**: `scripts/deployment/deploy-transaction-mirror-and-pmm-pool-after-txpool-clear.sh` retries pool deploy on “Replacement transaction underpriced” with gas bump (up to 4 attempts) and short wait after first tx.
- **www.mim4u.org**: Added to `update-npmplus-proxy-hosts-api.sh` (same backend as mim4u.org). Nginx server block includes `server_name mim4u.org www.mim4u.org ...` so both hosts are served. Optional: NPMplus Redirect for www → apex.
- **HSTS/CSP**: Nginx snippet in MIM4U_502_ERROR_RESOLUTION.md adds X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy, Content-Security-Policy. HSTS enabled via NPMplus SSL tab when terminating HTTPS.
- **Cookie consent**: Banner persists choice in `localStorage` (`mim_cookie_consent`); analytics/tracking only run when consent is `accept` (see `src/utils/analytics.ts`). Cookie banner is keyboard-accessible and links to legal/cookie policy.
- **Get Help form**: Inline, field-level validation with specific error messages; draft auto-saved to `localStorage` (debounced); draft cleared on successful submit; `aria-invalid` and `aria-describedby` for errors.
- **CTA instrumentation**: Hero Donate and Get Help fire `cta_clicked` with `button` and `location`; analytics only run when cookie consent is “accept”.
- **SEO**: `robots.txt` and `sitemap.xml` use canonical `https://mim4u.org`; sitemap lists main routes (/, #/donate, #/request-assistance, #/volunteers, #/stories, #/legal).
- **502 fix script**: `scripts/mim4u-install-nginx-and-fix-502.sh` installs nginx on VMID 7810, applies security headers + SPA + /api proxy; run from host that can SSH to Proxmox.
---
## Tech stack (documented)
- **Frontend**: Vite + React + TypeScript; hash-based routing (`#/donate`, `#/request-assistance`, etc.); Tailwind CSS; Framer Motion.
- **Backend**: Azure Functions (API on VMID 7811, port 3001).
- **Hosting**: Static build served by nginx on VMID 7810 (LXC); NPMplus reverse proxy; optional Cloudflare Tunnel.
## Next Steps for Dev
1. **Lighthouse**: Run Lighthouse (mobile) and attach report JSON or screenshots to turn this into a **prioritized punch list with exact fixes** (what to change, where, how to validate).
2. **Infra**: Run `./scripts/mim4u-install-nginx-and-fix-502.sh` from a host that can SSH to Proxmox (r630-02) to install nginx on VMID 7810 and apply config — see [MIM4U_502_ERROR_RESOLUTION.md](./MIM4U_502_ERROR_RESOLUTION.md).
---
## Further recommendations and suggestions
### Performance & Core Web Vitals
- **Lighthouse (mobile)**
Run regularly; fix LCP (hero image `srcset`/preload), CLS (reserve space for cookie banner/fonts), INP (reduce main-thread work). See [Concrete Technical Checklist](#concrete-technical-checklist-dev-handoff) for targets.
- **Self-host fonts**
Consider serving Inter (or critical subset) from your origin to avoid Google Fonts latency and improve LCP; keep `font-display: swap`.
- **Defer non-critical JS**
Lazy-load or defer chat widgets, A/B scripts, and non-essential trackers so they dont block INP.
- **Images**
Use `LazyImage` (or equivalent) with `sizes`/`srcset` for any hero or above-the-fold images; compress and prefer modern formats (e.g. WebP with fallback).
### SEO & discoverability
- **Impact report as a real page**
Add a crawlable route (e.g. `#/impact` or `#/impact-report`) and link “See the impact report” to it; add to sitemap. Avoid impact content only in a modal or PDF link so crawlers and users get a proper page.
- **SSR/SSG (longer-term)**
For key public pages (home, donate, get help, impact), consider SSR or static generation to improve indexing and first-paint; Vite SSR or a static export for critical routes is one option.
- **Structured data**
Organization and DonateAction are in place; add `WebPage` or `FAQPage` where it fits (e.g. Get Help or Legal).
### Forms & Get Help workflow
- **Spam protection**
Add a lightweight mechanism (e.g. honeypot field, or time-based check) so the form isnt trivial to bot; avoid hostile CAPTCHA for school/counselor users.
- **Confirmation & privacy**
Ensure legal/cookie policy and Get Help copy clearly state how “we confirm support reached the student” works and where data is stored/processed; keep PII out of URLs and query params.
- **Offline / resilience**
Consider a simple “Save draft” affordance in addition to auto-save, and a clear message if submit fails (retry, contact number).
### Security & Portals
- **Session cookies**
For Portals (and any auth), use `HttpOnly`, `Secure`, and `SameSite=Lax` (or `Strict`) on session cookies; set at the API/auth layer (Azure Functions / Entra config or backend).
- **Rate limiting**
Apply rate limits on `/api/*` and auth endpoints (e.g. login, token). With **Cloudflare** in front: use WAF/custom rules (e.g. rate limit /api/ and auth paths). With **LXC/nginx only**: add `limit_req_zone` / `limit_req` in nginx for `/api/` and proxy to API.
- **CSP**
Nginx and staticwebapp.config already send security headers; keep CSP tight and avoid broad `unsafe-inline`/`unsafe-eval` where possible (may require build-time nonce or hashes for scripts).
### Analytics & instrumentation
- **Volunteer CTA**
Add `cta_clicked` (or equivalent) for “Volunteer” / “Volunteers” in nav and hero so Donate, Get Help, and Volunteer are tracked consistently; keep respecting cookie consent.
- **Events with ad blockers**
Document or test that key events (donation, form submit, CTA clicks) still fire when analytics is blocked (e.g. fallback to server-side or minimal first-party logging) so funnels are measurable.
### Operations & hosting
- **Deploy real app to 7810**
After nginx is in place, build the MIM4U frontend and deploy to `/var/www/html` (or the path nginx uses) so the live site replaces the placeholder.
- **Backup**
Back up nginx config and `/var/www/html` (or app deploy path) on 7810; include in any host/container backup runbook.
- **Health check**
Add a simple health URL (e.g. `/health` or `/.well-known/health`) that returns 200 for monitoring or load balancers; optional JSON with version or build id.
- **Cloudflare (optional)**
If mim4u.org is behind Cloudflare: use Full (strict) SSL, WAF rate limits for `/api/`, cache static assets; see `miracles_in_motion/docs/deployment/CLOUDFLARE_SETUP.md` for patterns.
### General best practices
- **Repo-wide**
Security, backups, monitoring, and script patterns in [OPTIONAL_RECOMMENDATIONS_INDEX.md](../OPTIONAL_RECOMMENDATIONS_INDEX.md) and [RECOMMENDATIONS_AND_SUGGESTIONS.md](../10-best-practices/RECOMMENDATIONS_AND_SUGGESTIONS.md) apply to MIM4U hosting (credentials, backups, monitoring, testing). Run `./scripts/mim4u-backup-7810.sh` periodically to back up nginx + app on 7810.
- **Cloudflare checklist (optional)**
When using Cloudflare in front of mim4u.org: Full (strict) SSL; WAF rate limit for `/api/` (e.g. 100 req/min); cache static assets; see `miracles_in_motion/docs/deployment/CLOUDFLARE_SETUP.md`.
- **Lighthouse**
Run performance audits where Chrome is available: `npm run lighthouse` (headless) or `npm run lighthouse:local` (interactive). In environments without Chrome (e.g. WSL without Chrome), run from a host with Chrome or use CI; fix any LCP/CLS/INP issues reported.
---
**Source:** External technical UX/UI review of mim4u.org (publicly indexable content).
**Hosting context:** Proxmox LXC — VMID 7810 (mim-web-1), VMID 7811 (mim-api-1); NPMplus; miracles_in_motion submodule.