customer-presentation/CHECKLIST.md
Arlind Ukshini 88863183e1 update docs: minimal env, WSL deploy, join tracking, rsync excludes
- align auth docs with the simplified POST /auth/login flow
- drop CODE_PEPPER / SMTP / MAIL_FROM / mail.js / request-code references
- document the bifrost_joins table and bin/joins.js CLI
- OPERATIONS.md: WSL setup, exclude data/.env/node_modules on promote rsync
- INSTALL.md: 3-value /etc/fenja/env, drop SMTP prereq

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 17:10:08 +02:00

6.4 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 [bifrost] listening on 127.0.0.1:3000, no red errors (there is no [mail] SMTP relay reachable line anymore — the mail stack was removed)
  • [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 → session cookie issued immediately, welcome step appears (no 6-digit code flow anymore)
  • [browser] Click "Learn more" on the welcome step → redirected to /timeline showing the timeline page
  • [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 /timeline redirects to /
  • [browser] Visit /timeline.js or /vendor/d3-array.min.js directly while logged out → redirects to /
  • DevTools → Application → Cookies: fenja_session shows HttpOnly ✓, Secure ✓ (prod only), SameSite=Lax

C. After changes to the entrance form or login endpoint

  • Submit a non-invited address → inline "not invited" message, no session issued
  • Submit a malformed email (foo, foo@, empty) → inline error appears, no request sent
  • Submit > 30 login attempts from the same IP in an hour → rate-limit response (429)

D. After changes to the timeline / protected pages

  • [browser] Timeline loads fully: globe visible, 12 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 -X POST https://project-bifrost.fenja.ai/auth/login -H 'Content-Type: application/json' -d '{"email":"nobody@example.com"}' returns quickly (rate-limit zone is functioning; expect 403 not_invited on a real email not on the list)

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/

H1. After changes to the Join-CTA tracking (bifrost_joins)

  • [browser, logged in] Click the final "Join Project Bifrost" CTA → confirmation panel renders (staggered checkmarks appear)
  • DevTools network tab: POST /api/bifrost-join returns 200 with {clicked_at: <ms>}
  • sudo -u fenja node /opt/fenja/bin/joins.js list shows a new row with your email and a current timestamp
  • Click the CTA a second time (refresh the page first): a second row appears — the log is per-click, not per-user
  • sudo -u fenja node /opt/fenja/bin/joins.js summary groups by email with correct click_count
  • sudo -u fenja node /opt/fenja/bin/joins.js stats totals match what you see in list
  • Logged out: curl -X POST https://project-bifrost.fenja.ai/api/bifrost-join → 401 (auth gate holds)

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.