MIM4U: nginx install/deploy/backup scripts, rate limit, CSP, docs; submodule pointer; txpool retry script
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
Made-with: Cursor
This commit is contained in:
@@ -219,12 +219,12 @@ The following VMIDs have been permanently removed:
|
||||
| 7811 | 192.168.11.36 | mim-api-1 | ✅ Running | Web: 80, 443, API: Various | MIM4U service (web + API) |
|
||||
|
||||
**Public Domains** (NPMplus config):
|
||||
- `mim4u.org` → Routes to `http://192.168.11.36:80` (VMID 7811)
|
||||
- `www.mim4u.org` → Redirects to `mim4u.org` (via NPMplus redirect)
|
||||
- `secure.mim4u.org` → Routes to `http://192.168.11.36:80` (VMID 7811)
|
||||
- `training.mim4u.org` → Routes to `http://192.168.11.36:80` (VMID 7811)
|
||||
- `mim4u.org` → Routes to `http://192.168.11.37:80` (VMID 7810 mim-web-1)
|
||||
- `www.mim4u.org` → Routes to `http://192.168.11.37:80` (VMID 7810; optional NPMplus redirect www → apex)
|
||||
- `secure.mim4u.org` → Routes to `http://192.168.11.37:80` (VMID 7810)
|
||||
- `training.mim4u.org` → Routes to `http://192.168.11.37:80` (VMID 7810)
|
||||
|
||||
**Note**: All MIM4U domains route to VMID 7811 at 192.168.11.36. `www.mim4u.org` redirects to `mim4u.org` to save on proxy host configurations.
|
||||
**Note**: All MIM4U domains route to VMID 7810 (mim-web-1) at 192.168.11.37. nginx on 7810 proxies `/api/` to VMID 7811 (192.168.11.36:3001).
|
||||
|
||||
---
|
||||
|
||||
@@ -467,10 +467,10 @@ This section lists all endpoints that should be configured in NPMplus, extracted
|
||||
| `dbis-api-2.d-bis.org` | `192.168.11.156` | `http` | `3000` | ❌ No | DBIS API Secondary (VMID 10151) |
|
||||
| `secure.d-bis.org` | `192.168.11.130` | `http` | `80` | ❌ No | DBIS Secure Portal (VMID 10130) - Path-based routing |
|
||||
| **MIM4U Services** |
|
||||
| `mim4u.org` | `192.168.11.36` | `http` | `80` | ❌ No | MIM4U Main Site (VMID 7811) |
|
||||
| `www.mim4u.org` | `Redirect` | `-` | `-` | ❌ No | Redirects to `mim4u.org` (no separate proxy host) |
|
||||
| `secure.mim4u.org` | `192.168.11.36` | `http` | `80` | ❌ No | MIM4U Secure Portal (VMID 7811) |
|
||||
| `training.mim4u.org` | `192.168.11.36` | `http` | `80` | ❌ No | MIM4U Training Portal (VMID 7811) |
|
||||
| `mim4u.org` | `192.168.11.37` | `http` | `80` | ❌ No | MIM4U Main Site (VMID 7810 mim-web-1) |
|
||||
| `www.mim4u.org` | `192.168.11.37` | `http` | `80` | ❌ No | MIM4U (VMID 7810; optional redirect www → apex) |
|
||||
| `secure.mim4u.org` | `192.168.11.37` | `http` | `80` | ❌ No | MIM4U Secure Portal (VMID 7810) |
|
||||
| `training.mim4u.org` | `192.168.11.37` | `http` | `80` | ❌ No | MIM4U Training Portal (VMID 7810) |
|
||||
| **Sankofa Phoenix Services** |
|
||||
| `sankofa.nexus` | `192.168.11.51` | `http` | `3000` | ❌ No | Sankofa Portal - Company Website (VMID 7801) ✅ **Deployed** |
|
||||
| `www.sankofa.nexus` | `192.168.11.51` | `http` | `3000` | ❌ No | Sankofa Portal (VMID 7801) ✅ **Deployed** |
|
||||
|
||||
@@ -47,6 +47,17 @@
|
||||
|
||||
The container needs nginx installed and running to serve the web application.
|
||||
|
||||
**Option A — run the fix script (recommended):** From a host that can SSH to the Proxmox node (r630-02):
|
||||
|
||||
```bash
|
||||
./scripts/mim4u-install-nginx-and-fix-502.sh
|
||||
# Or dry-run: ./scripts/mim4u-install-nginx-and-fix-502.sh --dry-run
|
||||
```
|
||||
|
||||
The script installs nginx, writes the security-enabled config (including rate limits in `/etc/nginx/conf.d/mim4u-rate-limit.conf` and the default site), ensures `/var/www/html` exists, and reloads nginx.
|
||||
|
||||
**Option B — manual steps:**
|
||||
|
||||
```bash
|
||||
# SSH to Proxmox host
|
||||
ssh root@192.168.11.12
|
||||
@@ -68,16 +79,17 @@ Check what IP NPMplus is routing to:
|
||||
|
||||
1. **Access NPMplus Web UI**:
|
||||
- URL: `https://192.168.0.166:81` or `https://192.168.11.166:81`
|
||||
- Navigate to: Proxy Hosts → `mim4u.org`
|
||||
- Navigate to: Proxy Hosts → `mim4u.org` (and `www.mim4u.org`)
|
||||
|
||||
2. **Verify Configuration**:
|
||||
- Forward Hostname/IP: Should be `192.168.11.37`
|
||||
- Forward Port: Should be `80`
|
||||
- Forward Scheme: Should be `http`
|
||||
- **www.mim4u.org**: Same backend so both apex and www work. Optional: create a Redirect host for `www.mim4u.org` → `https://mim4u.org` in NPMplus to canonicalize to apex.
|
||||
|
||||
3. **If incorrect, update to**:
|
||||
- Forward Hostname/IP: `192.168.11.37`
|
||||
- Forward Port: `80`
|
||||
3. **Security (HSTS / SSL)**:
|
||||
- Enable **SSL** and **Force SSL** for mim4u.org (and www, secure, training) so HTTPS is used.
|
||||
- Enable **HSTS** in the proxy host’s SSL tab so browsers get `Strict-Transport-Security`. NPMplus adds the header when terminating SSL.
|
||||
|
||||
### Step 3: Deploy MIM4U Web Application (When Ready)
|
||||
|
||||
@@ -97,22 +109,31 @@ If you need the site working immediately, you can:
|
||||
2. **Configure basic nginx** to serve a default page:
|
||||
|
||||
```bash
|
||||
# Basic nginx config (temporary)
|
||||
# Basic nginx config (temporary) — server_name includes www so www.mim4u.org works; security headers (HSTS when on HTTPS via NPMplus, CSP)
|
||||
pct exec 7810 -- bash -c 'cat > /etc/nginx/sites-available/default << EOF
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
server_name mim4u.org www.mim4u.org secure.mim4u.org training.mim4u.org _;
|
||||
root /var/www/html;
|
||||
index index.html;
|
||||
|
||||
# Security headers (HSTS added by NPMplus when terminating SSL; CSP reduces XSS)
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Content-Security-Policy "default-src '\''self'\''; script-src '\''self'\'' '\''unsafe-inline'\'' '\''unsafe-eval'\''; style-src '\''self'\'' '\''unsafe-inline'\'' https://fonts.googleapis.com; font-src '\''self'\'' https://fonts.gstatic.com; img-src '\''self'\'' data: https:; connect-src '\''self'\'' https://mim4u.org; frame-ancestors '\''self'\'';" always;
|
||||
|
||||
location / {
|
||||
try_files \$uri \$uri/ =404;
|
||||
try_files \$uri \$uri/ /index.html =404;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://192.168.11.36:3001;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
}
|
||||
}
|
||||
EOF'
|
||||
@@ -148,5 +169,24 @@ curl -I https://mim4u.org/
|
||||
|
||||
---
|
||||
|
||||
## Optional: Rate limiting for /api/
|
||||
|
||||
To rate-limit `/api/` at nginx, the `limit_req_zone` directive must live in the **http** block (e.g. in `/etc/nginx/nginx.conf`), not in the server block. Example:
|
||||
|
||||
```nginx
|
||||
# In http { ... } in nginx.conf
|
||||
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=30r/m;
|
||||
```
|
||||
|
||||
Then in your server block (or in the snippet above), inside `location /api/` add:
|
||||
|
||||
```nginx
|
||||
limit_req zone=api_limit burst=5 nodelay;
|
||||
```
|
||||
|
||||
Alternatively, use Cloudflare WAF rate limiting in front of mim4u.org (see [CLOUDFLARE_SETUP](../../miracles_in_motion/docs/deployment/CLOUDFLARE_SETUP.md)).
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-01-18
|
||||
**Status**: ⚠️ nginx installation needed on VMID 7810
|
||||
|
||||
49
docs/04-configuration/MIM4U_FIRST_PARTY_ANALYTICS.md
Normal file
49
docs/04-configuration/MIM4U_FIRST_PARTY_ANALYTICS.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# MIM4U First-Party Analytics Endpoint
|
||||
|
||||
**Purpose:** Allow key events (page views, CTA clicks, form submissions) to be measured even when ad blockers block Google Analytics. The frontend sends a copy of each event to a first-party endpoint.
|
||||
|
||||
## Frontend behavior
|
||||
|
||||
When cookie consent is **accept**, the app sends events to:
|
||||
|
||||
- **Google Analytics** (when `gtag` is available)
|
||||
- **First-party fallback:** `POST /api/events` (fire-and-forget, `keepalive: true`)
|
||||
|
||||
Request body is a JSON object:
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "page_view",
|
||||
"properties": {
|
||||
"page": "/",
|
||||
"title": "Miracles In Motion | ...",
|
||||
"timestamp": "2026-02-26T12:00:00.000Z",
|
||||
"url": "https://mim4u.org/"
|
||||
},
|
||||
"userId": null
|
||||
}
|
||||
```
|
||||
|
||||
Example event names: `page_view`, `cta_clicked`, `donation_completed`, `form_submission`, `volunteer_signup`.
|
||||
|
||||
## Backend (API on VMID 7811)
|
||||
|
||||
The API behind `/api/` (proxied from 7810 to 7811) should implement:
|
||||
|
||||
**`POST /api/events`**
|
||||
|
||||
- **Auth:** Optional; if you require auth, use a short-lived token or same-origin only (no CORS for other origins).
|
||||
- **Body:** JSON as above.
|
||||
- **Response:** `204 No Content` or `200 OK` (no body required).
|
||||
- **Side effects:** Log to disk, forward to a server-side analytics pipeline (e.g. GA4 Measurement Protocol, Plausible, or internal DB). Do not expose PII in logs unless compliant with privacy policy.
|
||||
|
||||
If the endpoint is not implemented, the frontend `fetch` will 404; the app ignores failures and continues.
|
||||
|
||||
## Rate limiting
|
||||
|
||||
Nginx on 7810 applies `limit_req zone=api burst=5 nodelay` to `/api/`. Ensure `/api/events` is included in that path so abuse is limited.
|
||||
|
||||
## See also
|
||||
|
||||
- [MIM4U_502_ERROR_RESOLUTION.md](./MIM4U_502_ERROR_RESOLUTION.md) — nginx and proxy
|
||||
- [MIM4U_UX_UI_TECHNICAL_REVIEW.md](./MIM4U_UX_UI_TECHNICAL_REVIEW.md) — analytics recommendations
|
||||
30
docs/04-configuration/MIM4U_SESSION_COOKIES.md
Normal file
30
docs/04-configuration/MIM4U_SESSION_COOKIES.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# MIM4U Portals — Session Cookie Configuration
|
||||
|
||||
**Purpose:** Ensure Portals (and any auth) use secure session cookies: `HttpOnly`, `Secure`, `SameSite`.
|
||||
|
||||
## Where to configure
|
||||
|
||||
- **Azure Static Web Apps / Entra (Azure AD):** If MIM4U uses Azure for auth, session cookies are typically set by the platform. In Azure Portal → App registrations → your app → Authentication, ensure:
|
||||
- Redirect URIs use `https://mim4u.org` (and `https://secure.mim4u.org` if used).
|
||||
- Implicit grant and legacy options are off unless required.
|
||||
- **Custom API (VMID 7811):** If the API issues its own session cookies (e.g. JWT in cookie or session id), set when setting the cookie:
|
||||
- `HttpOnly=true`
|
||||
- `Secure=true` (only over HTTPS)
|
||||
- `SameSite=Lax` or `Strict`
|
||||
- `Path=/` or the minimal path needed
|
||||
|
||||
## Example (Node/Express-style)
|
||||
|
||||
```javascript
|
||||
res.cookie('session', token, {
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
maxAge: 24 * 60 * 60 * 1000
|
||||
})
|
||||
```
|
||||
|
||||
## NPMplus / nginx
|
||||
|
||||
NPMplus terminates SSL; it does not set application session cookies. Cookie flags are set by the application (Azure or API on 7811).
|
||||
219
docs/04-configuration/MIM4U_UX_UI_TECHNICAL_REVIEW.md
Normal file
219
docs/04-configuration/MIM4U_UX_UI_TECHNICAL_REVIEW.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# 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
|
||||
|
||||
---
|
||||
|
||||
## What’s Working (UX That’s 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 it’s 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 doesn’t 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; don’t 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 don’t 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 isn’t 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.
|
||||
@@ -68,10 +68,11 @@ All these services can be accessed by NPMplus over the internal network, regardl
|
||||
| Domain | Target | VMID | Host | Port | Notes |
|
||||
|--------|--------|------|------|------|-------|
|
||||
| `mim4u.org` | 192.168.11.37:80 | 7810 | r630-02 | 80 | mim-web-1 (frontend) |
|
||||
| `www.mim4u.org` | 192.168.11.37:80 | 7810 | r630-02 | 80 | mim-web-1 (same backend) |
|
||||
| `secure.mim4u.org` | 192.168.11.37:80 | 7810 | r630-02 | 80 | mim-web-1 |
|
||||
| `training.mim4u.org` | 192.168.11.37:80 | 7810 | r630-02 | 80 | mim-web-1 |
|
||||
|
||||
**Updated**: MIM4U routes to VMID 7810 (mim-web-1) at 192.168.11.37, not 7811.
|
||||
**Updated**: MIM4U routes to VMID 7810 (mim-web-1) at 192.168.11.37, not 7811. nginx on 7810 proxies `/api/` to 7811 (192.168.11.36:3001).
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user