customer-presentation/CHECKLIST.md
2026-04-22 14:39:16 +02:00

5.5 KiB

Checklist

Run the relevant section after every change before considering it done. Items are ordered: if an earlier one fails, stop and fix before testing the rest.

Notation: run on the VPS unless marked [local] or [browser].


A. After any code change (minimum viable smoke test)

  • sudo systemctl status fenjaactive (running)
  • sudo journalctl -u fenja -n 20 shows [mail] SMTP relay reachable and [bifrost] listening, no red errors
  • [local] curl -I https://project-bifrost.fenja.ai/ → 200, with X-Frame-Options: DENY and Content-Security-Policy headers
  • [local] curl -I https://project-bifrost.fenja.ai/timeline.js → 302, Location: /
  • [browser, private window] Open https://project-bifrost.fenja.ai/ → entrance page renders (not timeline)

If all five pass, the site is up and the gate holds.


B. After changes to auth, sessions, cookies, middleware, or src/

Do section A, then:

  • [browser, private] Enter invited email → receive code in inbox (not spam) within 60s
  • [browser] Type code → redirected to / showing the timeline (not the entrance)
  • [browser] Hard-refresh (Ctrl+Shift+R) → stays on the timeline (cookie persists)
  • [browser, new private window] Visit / → entrance appears (no cookie leak between sessions)
  • [browser] Click logout → lands on entrance → visiting / stays on entrance
  • [browser] Visit /timeline.js or /vendor/d3-array.min.js directly while logged out → redirects to /
  • DevTools → Application → Cookies: fenja_session shows HttpOnly ✓, Secure ✓, SameSite=Lax

C. After changes to the entrance form, code input, or email

  • Submit a non-invited address → still advances to code screen (enumeration protection intact)
  • Submit a malformed email (foo, foo@, empty) → inline error appears, no request sent
  • Type a wrong 6-digit code → "doesn't match" error, cells highlight red, can retry
  • Type 5 wrong codes → get "too many attempts" message; requesting a new code resets the counter
  • Request a code, wait 11 minutes, try to use it → rejected

D. After changes to the timeline / protected pages

  • [browser] Timeline loads fully: globe visible, 23 event cards, dot-nav at bottom, fonts render as true italic (not system oblique)
  • [browser] Scroll works smoothly, card reveal animations fire
  • [browser] Dot-nav switches between Timeline / Overview / Archive views
  • DevTools console: no CSP violations, no 404s for fonts/vendor files
  • DevTools network tab: all /vendor/* and /fenja/fonts/* requests return 200

E. After changes to CSP, security headers, or Nginx

Do section A with extra attention to:

  • Response headers on / include all six: X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, Content-Security-Policy, Strict-Transport-Security
  • CSP contains at minimum: default-src 'self', script-src 'self' (no unsafe-inline on scripts), frame-ancestors 'none'
  • sudo nginx -t → "syntax is ok" and "test is successful"
  • [local] Open timeline in a browser → no red CSP violations in DevTools console
  • curl.exe -I https://project-bifrost.fenja.ai/auth/request-code -X POST returns quickly (rate-limit zone is functioning)

F. After dependency or Node.js upgrades

  • sudo -u fenja npm ci --omit=dev completes without errors
  • sudo -u fenja npm audit reports no high/critical vulnerabilities in production deps
  • Run section A, then section B (full auth flow)
  • Check node --version on the VPS is still 20+

G. After Nginx config changes specifically

  • sudo nginx -t before reloading (catches 95% of errors)
  • ls /etc/nginx/sites-enabled/ contains only project-bifrost (no shadow configs)
  • After reload, curl -I https://project-bifrost.fenja.ai/ includes X-Powered-By: Express (proves Nginx is still proxying to Node, not serving static files)
  • Rate-limit zone still exists: grep -r "limit_req_zone" /etc/nginx/

H. After data/DB changes (schema, migrations)

  • Fresh boot creates schema cleanly: stop service, mv data/fenja.sqlite data/fenja.sqlite.bak, restart, verify it comes up healthy
  • Restore the backup (mv it back) before inviting further users
  • Take a manual backup before deploying: sudo -u fenja sqlite3 /opt/fenja/data/fenja.sqlite ".backup /opt/fenja/data/pre-change-$(date +%F).sqlite"

I. Deploy readiness (before any push to production)

  • Ran locally: npm install && npm run dev, walked full flow end-to-end
  • No uncommitted .env file in the rsync source
  • No data/*.sqlite in the rsync source
  • On the VPS after deploy: section A passes
  • On the VPS after deploy: section B passes
  • Tailed journalctl -u fenja -f for 30s while refreshing the site → no errors

Red flags that always mean stop

  • curl -I / returns 200 without X-Powered-By: Express → Nginx is serving static, not proxying to Node. Site is broken.
  • curl -I /timeline.js returns 200 → the auth gate is down. Do not invite anyone.
  • Any Set-Cookie: fenja_session=... header that lacks HttpOnly or Secure (in prod) → cookie hardening regression.
  • journalctl -u fenja showing repeated crashes → something's wrong, systemctl restart fenja won't fix it.
  • The entrance page submits the form as a GET with ?email= in the URL → JS isn't running (usually CSP blocking a newly-added inline script).

If any of these happen, revert to the last known-good commit and investigate offline.