Admin-only user management: list, create, edit role/permissions/status,
reset password, and disable/delete, against the v2 users API.
- Admin-gated three ways: AdminRoute on /users (calm access-denied panel
for non-admins, no redirect loop or data fetch), Sidebar hides the nav
item, and every mutation relies on the server AdminUser 403 as the real
authority. isAdmin is derived from the server-validated user, not the
client token.
- Users table: role badge (admin/operator/viewer), permissions summary,
enabled/disabled status, created, last-login. Sticky header, skeleton,
empty/error states. Self row tagged "You".
- Create/edit use the real roles and permission strings
(view/control/transfer/manage_users/manage_clients); admin permissions
are server-implicit and shown locked. Passwords: typed or Web Crypto
generated (rejection-sampled, copy-once reveal), type=password +
autoComplete=new-password, cleared from state on open/close/success,
never logged/persisted/in-URL; blank on edit means unchanged.
- Self-lockout guards: cannot disable, delete, or demote your own admin
account (controls disabled + submit-handler checks, matched on the
authoritative user id). Server mirrors self-disable/self-delete; the
self-demotion guard is client-side (server todo filed).
- useUpdateUser sequences user-update then permissions-set; invalidates
["users"] on settled so the table reconciles after a partial failure,
with an actionable message if only permissions failed.
Passed Code Review (no blockers after fixes) and local gates
(tsc/lint/build green). Completes the v2 dashboard view set.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>