108 lines
6.3 KiB
Markdown
108 lines
6.3 KiB
Markdown
# 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 fenja` → `active (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, 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 -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/`
|
|
|
|
## 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.
|