Files
Fuchs_Intranet/Fuchs/Docs/Concepts/admin-system-status.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

6.7 KiB

status, lastUpdated, applyTo, relatedDecisions
status lastUpdated applyTo relatedDecisions
Active 2026-09-09
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
Fuchs/js/intranet/fis_main_menu.js
0011-admin-module-system-status.md
0015-split-admin-user-management-module.md

Admin / System-Status module

Summary

The Admin module gives a privileged operator a live, in-app view of the running deployment's configuration and health, plus a test-email tool. It answers "which host am I on, can this instance reach SQL Server / Key Vault / Blob Storage / the MFR ERP, how is email wired up (including the OverrideRecipient redirect), and does sending actually work". Access is restricted to users whose fds_sys module authorization is greater than 4.

How it works

Authorization (two layers)

  1. Menu visibility — at page load fis_main_menu.js#addAdminMenuButtonsIfAuthorized calls $fis.getAuth('fds_sys') once (shared with the separate usr user-management module, see 0015); only when the level is > 4 does it push a single "Administration" dropdown entry into $ocms.ocmsmenu — containing this module's "Systemüberwachung" (init:admin) item alongside usr's "Benutzerverwaltung" (init:usr) item — and re-render #mainmenu. Users below the threshold never see the dropdown and never fetch either module's script.
  2. Server-side gate — every /do/admin/* endpoint resolves fis_getModuleAuth('fds_sys', authuser) and returns 401 unless it is > 4. The only exception is admin/auth, which returns { manage: 0 } for unauthorized users so the frontend can cleanly decline to render. This is defense in depth: hiding the button is not a security control on its own.

Request flow

click "Administration"  → $ocms.init('admin')
  POST /do/admin/auth   → { manage, level }         (manage>0 ⇒ authorized)
  load /web/fis.admin.de.js + /web/fis.admin.css
  $ocms.admin.init2()   → init3() renders the page
    POST /do/admin/status → { info, probes }         full snapshot + all probes
  per-card "Aktualisieren" → POST /do/admin/probe/<component> → { probe }
  "Test-E-Mail senden"     → POST /do/admin/testmail (to/subject/body) → { result }

Backend (ISystemStatusService / SystemStatusService, scoped)

  • GetInfo() — passive snapshot, no network calls: host (machine/OS/framework/environment/ test-deployment/uptime), database (server/catalog/login parsed from the connection string — never the password), email (mailer enabled/base-url/account/server-id/token-present + OverrideRecipient), blob (enabled/configured/containers), MFR (host/creds-present/sync), Key Vault (vault-uri/app-prefix/managed-secret-count/client-registered).
  • Probes (database, keyvault, blob, mfr) each return a SystemProbeResult (status = ok/error/disabled/unconfigured, ok, message, detail, durationMs, optional metrics). They never throw — failures are captured in the result. database runs SELECT @@SERVERNAME, DB_NAME(), SUSER_SNAME(); keyvault reads the first managed secret via the DI SecretClient; blob calls IBlobStorageService.CheckConnectivityAsync (account-info request plus a per-container blob count for the invoice/reminder containers, surfaced as metrics and totalled in the message); mfr calls IMfrClientFactory.Create().GetEntities(). The generic metrics (label/value pairs) is how a probe reports extra facts for display — the blob probe uses it for the file counts.
  • SendTestEmailAsync(to, subject, body) HTML-encodes the body and sends via IComService, so the Fuchs:Email:OverrideRecipient redirect applies exactly as for any other mail; the result reports the requested recipient and, when active, the override target.
  • Every probe emits the fuchs.systemstatus.probes counter tagged by component + status and an systemstatus.probe activity span.

Startup-checks widget (non-refreshable)

StartupSelfTestService runs the boot self-test once (Key Vault / Database / MFR / PDF-license / mailer, gated by Fuchs:StartupChecks:*). It now also writes its outcome to the singleton StartupCheckReporter, which GetInfo() returns as StartupChecks. The Admin page renders it as a single non-refreshable card (there is no per-check retry — the live connectivity probes above cover on-demand re-testing; the startup card is a historical record of the boot run). When the self-test is disabled (Enabled=false, the appsettings default) or has not completed, the card shows a "nicht ausgeführt" note. Each item shows OK / Fehler / übersprungen (a disabled check reports enabled=false).

Frontend (fis.admin.js + fis.admin_txt_de.js + fis.admin.scss)

Standard lazy-loaded module (same contract as inv/rep/bam). Renders a system card plus a responsive grid of status cards; connectivity cards carry a colored status pill and a per-card refresh button, the email card carries the test-email dialog. The topbar has an "Alle prüfen" button that reloads the whole snapshot. Admin responses are serialized camelCase (the DTOs are PascalCase) so the JS reads probe.status, info.database.server, etc.

Key files

  • Fuchs/Controllers/IntranetController.Admin.cs — Do_Process_Admin dispatch + shared auth gate/camelCase JSON helper (also used by the separate usr module, see 0015).
  • Fuchs/Services/ISystemStatusService.cs, SystemStatusService.cs, SystemStatusModels.cs — diagnostics service + DTOs.
  • Fuchs/Services/StartupCheckReport.cs (StartupCheckReporter singleton) + StartupSelfTestService.cs — boot self-test result captured for the non-refreshable widget.
  • Fuchs/Services/IBlobStorageService.cs / AzureBlobStorageService.cs — CheckConnectivityAsync + BlobConnectivity.
  • Fuchs/js/intranet/modules/fis.admin*.js, fis.admin.scss — the module, texts, styles (bundled via bdlconfig.json).
  • Fuchs/js/intranet/fis_main_menu.js (addAdminMenuButtonsIfAuthorized) + fis_main_go.js — conditional menu buttons (this module and usr).
  • Fuchs.Tests/SystemStatusServiceTests.cs — service tests.

User account/group management moved to its own module and concept doc — see admin-user-management.md.