Pre-launch hardening code complete: H2 login timing, H1 CSP (report-only), M2 requireRole, M5 safe logger, Auth.js E2E suite (password-reset, email-verify, account-link, integration-api-keys). Production CSP enforce after staging soak is the only spun-out ops step.
Status: done (2026-05-24) · Source: [[Projects/personal-finance-notion/decisions/adr-2026-05-18-authjs-migration|ADR 2026-05-18]]
DUMMY_HASH in src/auth.ts authorize(); [x] loginTimingEqualization.test.tsnext.config.mjs policy + report-only default; [ ] production enforce → [[Projects/personal-finance-notion/backlog/p2-csp-enforce-production|p2 CSP enforce]]requireRole.ts + adminProbe + /api/admin/probe; [x] role stripped in updateUser; [x] requireRole.test.ts; [x] ADR addendum 2026-05-25logger.error (logger.test.ts)password-reset.spec.ts, email-verify.spec.ts, account-link.spec.ts, integration-api-keys.spec.ts, auth.spec.ts (Auth.js flows); minor: admin-guard E2E TODO in auth.spec.ts (non-blocking)CSP_ENFORCE=truenpm audit --production clean