Files
Fuchs_Intranet/Fuchs/Docs/Decisions/0011-admin-module-system-status.md
T
Stefan 8a0ebeeb1e Add German localization and styling for administration module
- Introduced new JavaScript file `fis.admin_txt_de.js` for German translations of administration-related terms and messages.
- Created `fis.admin.css` for styling the administration interface, including layout, cards, and buttons.
- Added `fis.admin.de.js` for the main functionality of the administration module, implementing features such as system status checks and email testing.
- Minified version of the German JavaScript file created as `fis.admin.de.min.js`.
- Minified CSS file created as `fis.admin.min.css` for optimized loading.
2026-07-16 14:59:14 +02:00

4.0 KiB

status, date, applyTo, supersededBy
status date applyTo supersededBy
Accepted 2026-07-16
Fuchs/Controllers/IntranetController.Admin.cs
Fuchs/Services/SystemStatusService.cs
Fuchs/Services/ISystemStatusService.cs
Fuchs/Services/SystemStatusModels.cs
Fuchs/js/intranet/modules/fis.admin*.js
Fuchs/js/intranet/modules/fis.admin.scss

0011 — Admin module gated on fds_sys > 4

Context

Operators needed an in-app view of the running deployment's health: which host it runs on, whether SQL Server / Azure Key Vault / Azure Blob Storage / the MFR ERP are reachable, how the email service is configured (including the dev/test Fuchs:Email:OverrideRecipient redirect), and a way to send a test email. The StartupSelfTestService already probes most of these once at startup and writes the result to the log — but that is invisible to a logged-in operator and cannot be re-run on demand. This is privileged, infrastructure-revealing information (server names, account names, connectivity state) that must not be exposed to ordinary users.

Decision

  • Add an Admin module (admin) alongside the existing invoice/reminder/report/banking modules, following the same frontend module contract (init:adminadmin/auth returns { manage } → lazy-load /web/fis.admin.de.js + /web/fis.admin.cssinit2()).
  • Access is gated on the caller's fds_sys module authorization being strictly greater than 4 (fis_getModuleAuth('fds_sys', authuser) > 4). The menu button is only rendered, and the module script only fetched, for such users; every Admin data endpoint additionally re-checks the level server-side (defense in depth) and returns 401 otherwise. admin/auth is the sole endpoint that answers for unauthorized users too (it returns manage: 0), so the frontend can decide whether to render the module at all.
  • Backend diagnostics live in a new DI-registered ISystemStatusService (scoped). It exposes a passive GetInfo() snapshot and live, never-throwing connectivity probes (database, keyvault, blob, mfr) plus SendTestEmailAsync. The test email goes through the normal IComService pipeline, so the OverrideRecipient safety net applies exactly as for any other outbound mail.
  • The service never returns secrets — only presence flags and non-sensitive values (server/catalog/login name, storage account name, error text). Responses are serialized camelCase to match the frontend's lowercase convention.

Consequences

  • fds_sys is now a security-relevant authorization key: granting it a value > 4 exposes infrastructure status and the ability to send test emails. Provision it deliberately.
  • SystemStatusService is intentionally separate from StartupSelfTestService rather than a shared refactor: the startup service's probe methods are protected virtual and its tests override them, so folding both onto one probe surface would have broken that contract. The two therefore duplicate a little probe logic (Key Vault secret read, MFR GetEntities, SQL SELECT); keep them behaviourally aligned when either changes.
  • New probes (or new status facts) belong in SystemStatusService behind the same SystemProbeResult / SystemInfoSnapshot shapes; add the component id to SystemStatusService.Components and a card in fis.admin.js.
  • Blob connectivity is checked via a new IBlobStorageService.CheckConnectivityAsync (account-info request); it too never throws.

Alternatives considered

  • Reuse StartupSelfTestService directly. Rejected — see Consequences; its virtual/overridden probe surface is owned by its tests, and it is a one-shot BackgroundService, not a request-scoped query service.
  • Gate only in the frontend (hide the menu button). Rejected — the endpoints would still be reachable by crafting the POST. Server-side enforcement on every endpoint is required.
  • A separate fds_admin/new module-auth key. Rejected — fds_sys already models system-level privilege; reusing it avoids a parallel permission to provision.