SCRUM-257 — AdminUI user management page¶
Plan ref: UI-12 (docs/11-admin-plane-plan.md), rules D3/D4. Uses admin-auth's user
management API (SCRUM-206) and MFA reset (SCRUM-262). Stacked on SCRUM-256.
What exists¶
| Piece | Notes |
|---|---|
/users "Users" |
nav group Admin, admin only: a live_ops or viewer user never sees it and is denied the URL |
| Users table | name (root badge), email, roles, status, MFA enrolled, last login; per-row Actions menu |
| Actions offered only when D3 allows | no role/disable/MFA/reset on your own row or on root; the admin role offered only when the caller is root (derived from the caller's own row in the list, since /me does not carry the root flag). The server still enforces and its refusals are shown |
| Invite | email, name, role → one-time link with copy button, expiry, and "shown once; send it privately" warning; gone when closed |
| Pending invites | email, role, invite/reset, expiry, created by; Revoke with confirmation |
| Reset link / Reset MFA | reset link in the same one-time panel; MFA reset explains the effect (factor and codes cleared, sessions signed out, an admin enrolls again) |
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
Results at time of writing¶
- typecheck, lint, prettier, vitest (443 tests), build: pass.
- Playwright: users, service-detail and sign-in specs 13/13 three times in a row; full suite 35/35 on its last run. Full runs on this machine intermittently time out on a different, older test each time (logs pill, service-detail reload), each passing on rerun — suite flakiness under load, to be addressed in SCRUM-261.
- Screenshots checked: users table, invite dialog.
How it was built¶
DeepSeek run scoped (Landlock) to services/adminui (852 s, ~66k output tokens,
reasoning effort low). Claude review: action-visibility rules checked against D3;
the sign-in e2e change (email instead of the now-ambiguous "Admin" text) is legitimate.