Files
Fuchs_Intranet/Fuchs/Docs/Decisions/0015-split-admin-user-management-module.md
T
StefanandClaude Sonnet 5 076290cbeb
Playwright Tests / test (push) Canceled after 0s
Split Admin module into Status and User Management under one sidemenu dropdown
Splits fn=admin into two independent modules: the original status
dashboard stays at fn=admin, user management moves to a new fn=usr
(IntranetController.AdminUsers.cs, fis.usr.js). Both are now reached
through a single "Administration" sidemenu dropdown (Systemüberwachung /
Benutzerverwaltung) gated by one shared fds_sys > 4 check, per ADR 0015
(supersedes 0014's "fold into one module" choice).

Also fixes the password-reset validation to check only a plain 6-char
minimum instead of silently also requiring ValidatePassword's default
2-uppercase/2-lowercase/2-digit composition, which contradicted the
"mind. 6 Zeichen" message shown to the admin.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 12:09:44 +02:00

5.5 KiB

status, date, applyTo, supersededBy
status date applyTo supersededBy
Accepted 2026-09-09
Fuchs/Controllers/IntranetController.Admin.cs
Fuchs/Controllers/IntranetController.AdminUsers.cs
Fuchs/js/intranet/modules/fis.admin*.js
Fuchs/js/intranet/modules/fis.usr*.js
Fuchs/js/intranet/modules/fis.usr.scss
Fuchs/js/intranet/fis_main_menu.js
Fuchs_Database/dbo/Functions/fis_admin_*.sql
Fuchs_Database/dbo/Stored Procedures/fis_admin_*.sql

0015 — Split Admin into separate "Status" (admin) and "User Management" (usr) modules, under one "Administration" sidemenu dropdown

Context

0014 folded user management into the existing admin module (one sidemenu button, one fn) to avoid provisioning a second admin-ish permission. In practice this meant one button opened two unrelated things — infrastructure diagnostics and user account administration. The user asked for these to be split into two distinct buttons, grouped under a single "Administration" sidemenu entry (an ocmsmenu dropdown, not two flat top-level buttons). This decision supersedes 0014's "fold into admin" choice; the parts of 0014 that are about SQL-layer behavior (dual auth axis, password-reset email, group-toggle semantics) are unaffected and still apply, just under fn=usr instead of fn=admin.

Decision

  • Two independent modules, exposed as a single "Administration" dropdown in the sidemenu with two entries — Benutzerverwaltung and Systemüberwachung — using ocmsmenu's existing nested-item support (itm: [...] on a menu entry renders it as a Bootstrap dropdown; see oci_main.js#$ocms.menu, subm/subi). Both modules stay gated by the same fds_sys > 4 server-side check (AdminMinAuthExclusive/GetSystemAdminAuthAsync, both defined once in IntranetController.Admin.cs and shared by both dispatchers):
    • fn=admin — unchanged status/diagnostics dashboard (Do_Process_Admin, fis.admin.js), reached via the "Systemüberwachung" dropdown entry.
    • fn=usr — new user-management module (Do_Process_AdminUsers in the new IntranetController.AdminUsers.cs, fis.usr.js/fis.usr_txt_de.js/fis.usr.scss), built as a self-contained list+ribbon module (Banking's iMn/eM pattern) rather than a card embedded in the dashboard, reached via the "Benutzerverwaltung" dropdown entry.
  • The still-true dual-authorization caveat from 0014 carries over unchanged, just renamed: fds_sys > 4 gates the usr module's endpoints; the fis_admin_* SQL objects they call separately require the caller's intranet_admin setting to be > 1 (fis_admin_getUserAuth). An account needs both to actually manage users. Fuchs/Docs/Concepts/admin-user-management.md now carries this note (split out of admin-system-status.md).
  • id values shortened now that the module name itself says "usr" (no more redundant user prefix): users→list, userpwdreset→pwdreset, useremail→email, usergroups→groups, usergroupset→groupset. Endpoints move from /do/admin/* to /do/usr/* accordingly.
  • One shared client-side auth check gates the whole dropdown: fis_main_menu.js#addAdminMenuButtonsIfAuthorized (renamed from addAdminMenuIfAuthorized) calls $fis.getAuth('fds_sys') once and, if authorized, pushes a single parent menu entry (id: 'm_admin_grp', label $t.m_admin = "Administration", no fnc of its own) whose itm array holds the two real entries (fnc: 'init:usr' / fnc: 'init:admin'). The parent has no navigation behavior — clicking it only opens/closes the dropdown; the two children navigate. Idempotency is checked on the parent id alone.

Consequences

  • Two bundle pairs now exist for what was one (fis.admin.de.js/.min.css and fis.usr.de.js/.min.css, both registered in bdlconfig.json) — a small duplication of the lazy-load/auth-check plumbing, acceptable for the clarity of separate concerns.
  • The in-module header text for the dashboard module changed from "Administration" to "Systemüberwachung" (fis.admin_txt_de.js#$adt.mdl) so it no longer collides with the parent dropdown's "Administration" label once both are visible on screen at once.
  • Any future admin-only feature should default to its own module, added as a new entry under the same "Administration" dropdown (or its own dropdown, if unrelated), unless it's genuinely part of the status dashboard's diagnostics — the original "fold everything into one Admin button" instinct from 0014 didn't hold up once a second real feature existed.
  • IntranetController.BuildPasswordResetEmail/NotifyAdminUserActionFailedAsync moved to IntranetController.AdminUsers.cs; Fuchs.Tests/AdminUserManagementTests.cs needed no change since it calls them through the (unchanged) IntranetController type.

Alternatives considered

  • Two flat top-level sidemenu buttons (no shared "Administration" parent). Rejected per explicit user direction — the request was specifically for both to live "within Administration" in the sidemenu, i.e. a single grouping entry with two children.
  • Keep one module, add an internal tab/sub-nav for user management. Rejected — a client-side tab within one fn would still route through one fn auth check per the frontend's per-fn auth-caching design (fis_main.js#$ocms.init), the same limitation 0014 already ran into when this was one module with two unrelated concerns; splitting into two real modules under a shared menu dropdown gets a clean navigation grouping without that limitation.