fix(admin): protect administrator access
Reject final-admin demotion and deletion at the API boundary. Require explicit confirmation before any administrator role removal.
This commit is contained in:
@@ -649,3 +649,23 @@
|
||||
- **Consequences:** list state remains mounted while the overlay is open, direct workspace/section URLs and Back/Forward work, and a full-page link remains. Complete URL-backed filters and unsaved-edit guards are separate required increments before JOBS-002 can leave progress.
|
||||
- **User approval required:** No; this is approved repository implementation with mocked local data and no production/provider action.
|
||||
- **Reversible:** Revert the JOBS-002 overlay commit; no schema, dependency or stored-data change is involved.
|
||||
|
||||
## DEC-066 — Make theme preference independent of authentication
|
||||
|
||||
- **Date:** 2026-08-15
|
||||
- **Decision:** Supersede DEC-033's account-scoped storage portion with one canonical browser key, `jobtracker.themeMode`. Migrate the current legacy value once, apply the same resolution in the pre-paint script, and ignore auth-user changes for theme state.
|
||||
- **Reason/evidence:** the user-visible preference is application chrome, while the auth-derived key is resolved asynchronously and can differ across startup paths. Tying these together retained competing sources of truth and allowed refresh to change scheme. Focused persistence/migration/provider tests and production TypeScript build pass.
|
||||
- **Alternatives considered:** add route-specific theme effects; keep user/anonymous fallback ordering; let MUI own a second storage key. These preserve the race or reintroduce multiple owners.
|
||||
- **Consequences:** theme remains stable through login/logout/navigation/refresh on a browser. Former account keys remain readable for one-time migration but are no longer written.
|
||||
- **User approval required:** No; this corrects the requested persistence defect without schema, dependency or production change.
|
||||
- **Reversible:** Remove the canonical read/write and restore auth-key subscriptions; legacy values were not deleted.
|
||||
|
||||
## DEC-067 — Protect the final administrator at the API boundary
|
||||
|
||||
- **Date:** 2026-08-15
|
||||
- **Decision:** Refuse demotion or deletion of the final Admin in `UsersController`; expose current-user and removal-safety state to the admin UI; require an app-owned destructive confirmation for any demotion and stronger copy for self-demotion/self-deletion. Preserve unrelated roles during an Admin toggle.
|
||||
- **Reason/evidence:** confirmation alone cannot protect direct API calls or concurrent UI versions. Existing MUI confirm/prompt primitives already match the application and avoid a second dialog dependency. Four controller and three UI tests cover final-admin protection, other-admin demotion, self cancel and self confirm.
|
||||
- **Alternatives considered:** SweetAlert2; silently forbid every self-demotion; UI-only warning. These duplicate the design system, prevent legitimate handover, or fail to enforce the invariant.
|
||||
- **Consequences:** the final administrator cannot be removed by supported API paths. A self-demotion remains possible only when another administrator exists and the user explicitly confirms.
|
||||
- **User approval required:** No; this is requested safety hardening with no production mutation.
|
||||
- **Reversible:** Revert the controller/UI change; no stored data or schema changed.
|
||||
|
||||
Reference in New Issue
Block a user