- public/admin-ui.js (new, self-contained): on boot fetches GET /api/me and
stores window.__codemanUser; installs a fetch interceptor that opens a
change-password modal on any 403 PASSWORD_CHANGE_REQUIRED (and on boot when
mustChangePassword is set); for a multi-user admin, injects a "Users" tab into
the existing App Settings modal (create/reset/disable/enable/promote/demote/
grant-bypass/delete with typed confirm + one-time-password reveal). No header
button, so the mobile-header policy stays green; nothing renders in single-user
mode.
- me-routes: GET /api/me returns a `multiUser` flag so the UI distinguishes a
single-user admin (no admin UI) from a multi-user admin.
- index.html: load admin-ui.js after settings-ui.js, before session-ui.js.
Tests: test/admin-ui.test.ts (JSDOM: identity boot, Users-tab injection gating by
role/mode, forced change-password modal, script-order wiring). Backend verified
end-to-end by test/admin-routes.test.ts against a live server. A full Playwright
pass is recommended before merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>