Skip to content

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.