Add Administration user management: list, password reset, email change, group assignments
Playwright Tests / test (push) Canceled after 0s
Playwright Tests / test (push) Canceled after 0s
Wires the previously-unused fis_admin_* user/group stored procs into the Admin module (fds_sys-gated), adds a users grid with a per-row ribbon (reset password, change email, manage group membership), and always emails a password reset result to the user rather than showing it to the admin. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
---
|
||||
status: Accepted
|
||||
date: 2026-09-09
|
||||
applyTo:
|
||||
- "Fuchs/Controllers/IntranetController.Admin.cs"
|
||||
- "Fuchs/js/intranet/modules/fis.admin*.js"
|
||||
- "Fuchs/js/intranet/modules/fis.admin.scss"
|
||||
- "Fuchs_Database/dbo/Functions/fis_admin_*.sql"
|
||||
- "Fuchs_Database/dbo/Stored Procedures/fis_admin_*.sql"
|
||||
supersededBy: ""
|
||||
---
|
||||
|
||||
# 0014 — Admin user management: folded into the `admin` module, dual auth axis, password always emailed
|
||||
|
||||
## Context
|
||||
An operator needs to see the list of non-deleted intranet user accounts (name + email), and
|
||||
per account reset the password, change the email address, and view/change group assignments.
|
||||
The database layer for this already existed (`fis_admin_getUserAccountList`,
|
||||
`fis_admin_getUserGroupList`, `fis_admin_setUserAccount`, `fis_admin_resetUserPassword`,
|
||||
`fis_admin_addGroupMember`/`remGroupMember`) but was completely unwired from any controller.
|
||||
Those procs gate on a **different** authorization mechanism than the rest of the app: a
|
||||
per-user `intranet_admin` setting read via `fis_admin_getUserAuth(@authaccount) > 1`, entirely
|
||||
independent of the `fis_getModuleAuth`/`fis_module_auth` mechanism the rest of the app
|
||||
(including the existing Admin module, see
|
||||
[0011](0011-admin-module-system-status.md)) uses.
|
||||
|
||||
## Decision
|
||||
- **Fold user management into the existing `admin` module** (`fn=admin`) rather than create a
|
||||
new top-level module. New `id` cases (`users`, `userpwdreset`, `useremail`, `usergroups`,
|
||||
`usergroupset`) sit in `Do_Process_Admin` alongside the system-status diagnostics, behind the
|
||||
**same** `fds_sys > 4` server-side gate as the rest of that module.
|
||||
- **Known, accepted gap: two independent authorization axes.** `fds_sys > 4` controls whether
|
||||
the endpoints are reachable at all; the underlying `fis_admin_*` SQL objects separately
|
||||
require the caller's `intranet_admin` setting to be `> 1` (`fis_admin_getUserAuth`). An
|
||||
account with `fds_sys > 4` but no `intranet_admin` setting will reach these endpoints but get
|
||||
empty result sets / no-op writes from SQL — not an error, just silently nothing. **Operational
|
||||
consequence:** any account meant to do user management must be provisioned with both
|
||||
`fds_sys > 4` and `intranet_admin >= 2` (via `fis_useraccounts_settings`). This was a deliberate
|
||||
simplicity trade-off (see Alternatives) rather than unifying the two permission systems.
|
||||
- **Password reset always emails the result; never displays it.** The ribbon's "Passwort
|
||||
zurücksetzen" action lets the admin either type a specific new password or leave the field
|
||||
blank to auto-generate one (`fis_admin_resetUserPassword` gained an optional `@newpassword`
|
||||
parameter for this). Either way, the resulting plaintext password is sent only to the target
|
||||
user's stored email address via `IComService` (respecting the `Fuchs:Email:OverrideRecipient`
|
||||
dev safety net) — the admin never sees it on screen.
|
||||
- **Change email reuses `fis_admin_setUserAccount`** (prefilling the other fields from the
|
||||
existing row, `@password = NULL` so the update path leaves the password untouched) instead of
|
||||
adding a narrower proc — its `WHEN MATCHED` branch never touches `password_enc`, and its
|
||||
existing duplicate-email `THROW 60001` is mapped to an HTTP 409 in the controller.
|
||||
- **New `fis_admin_getUserGroupMembership` function** returns every group plus a `member` bit
|
||||
for one target user (mirrors `fis_admin_getUserGroupList`'s auth-gate style) — needed for the
|
||||
per-user group checkbox dialog; toggling a checkbox calls `fis_admin_addGroupMember`/
|
||||
`remGroupMember` immediately (no separate save step, consistent with the rest of the module's
|
||||
ribbon actions).
|
||||
- Per the [exception-user-notification rule](0003-interrupting-exceptions-notify-the-user.md),
|
||||
a failed password reset, a failed reset-email delivery, or a target with no usable email all
|
||||
call `IEventService.UserIssueAsync` so the admin is never left believing an operation
|
||||
succeeded silently.
|
||||
|
||||
## Consequences
|
||||
- Deploying/onboarding an admin for user management is now a two-step provisioning task
|
||||
(`fds_sys` **and** `intranet_admin`), not obvious from the UI — document this whenever
|
||||
granting the permission.
|
||||
- `fis_admin_resetUserPassword`'s signature changed (added optional `@newpassword`) and its
|
||||
result set gained a `newpassword` column; it was previously unwired from any caller, so this
|
||||
is a safe in-place change.
|
||||
- The Admin module's frontend now mixes two concerns (system diagnostics + user management)
|
||||
under one ribbon/menu entry; if user management grows substantially, revisit splitting it into
|
||||
its own module (see Alternatives).
|
||||
|
||||
## Alternatives considered
|
||||
- **Unify the two authorization axes** (e.g. make `fis_admin_*` procs check `fis_getModuleAuth`
|
||||
instead of `fis_admin_getUserAuth`, or vice versa). Rejected for this change — it would touch
|
||||
every existing `fis_admin_*` proc/function (all already gate on `fis_admin_getUserAuth`) for a
|
||||
feature that only needed to wire up what already existed; revisit if a real conflict surfaces
|
||||
in practice.
|
||||
- **New standalone top-level module** (`fn=usr`) with its own menu button and its own
|
||||
`fis_admin_getUserAuth`-based gate. Rejected per explicit user direction — folding into the
|
||||
existing Administration module was preferred over a second admin-ish menu entry.
|
||||
- **Show the new/reset password on screen instead of emailing it.** Rejected per explicit user
|
||||
direction — the password must only ever reach the user's own inbox, never be visible to the
|
||||
admin performing the reset.
|
||||
Reference in New Issue
Block a user