Skip to content

SCRUM-258 — AdminUI onboarding and TOTP enrollment screens

Plan ref: UI-13 (docs/11-admin-plane-plan.md). Needs the admin-auth fix in SCRUM-258 (backend, PR #80) so onboarding answers with the MFA policy. Stacked on SCRUM-257.

What exists

Piece Notes
/onboard (public) the token comes from the URL fragment (/admin/onboard#token=…, never sent to a server), is removed from the address bar with replaceState at once, and is never stored; shows who is invited and at what role (or "reset your password"), the expiry; password + confirm with a strength meter (the server's policy message is authoritative); invalid/expired → "ask an admin for a new one"
Outcomes tokens → signed in; mfa_required → the code screen (which also takes a recovery code); mfa_enrollment_required → enrollment. Login routes mfa_enrollment_required the same way
/login/enroll explains why; QR code (qrcode, PNG with token colours), the secret grouped by four with a copy button, a 5-minute countdown, code → confirm
Recovery codes ten codes, Copy all, Download .txt, "I have saved these codes" required before Continue
Dependencies qrcode 1.5.4 + @types/qrcode (lockfile hand-merged), pre-bundled in dev

Known limit: after confirm the session exists, so the app shell is already visible behind the recovery-codes screen; the "saved" checkbox is a nudge, not a hard gate.

How to verify

cd services/adminui
npm run typecheck && npm run lint && npm run format:check && npx vitest run && npm run build
npx playwright test
Mock: /admin/onboard#token=mock-admin-invite (admin → enrollment; secret JBSWY3DPEHPK3PXP, code 123456), mock-liveops-invite, mock-expired.

Results at time of writing

  • typecheck, lint, prettier, vitest (468 tests), build: pass; Playwright 39/39 on the first full run, onboarding spec 4/4 on its own (full back-to-back runs still show the suite's random 30 s timeouts, SCRUM-261). Screenshots checked for all three screens.

How it was built

DeepSeek run scoped (Landlock) to services/adminui (625 s, ~56k output tokens, reasoning effort low); Claude added qrcode beforehand. Claude review: token handling (fragment only, stripped, never stored) checked; while preparing this ticket Claude found the onboarding MFA bypass fixed in the backend part.