--- status: Active lastUpdated: 2026-09-17 applyTo: - "Fuchs/Controllers/IntranetController.Specialties.cs" - "Fuchs/js/intranet/modules/fis.specialties*" - "Fuchs/js/intranet/fis_main_menu.js" - "Fuchs/js/intranet/fis_main_go.js" relatedDecisions: - "0027-admin-invoice-file-backup-and-clear.md" --- # Admin "Specialties" page (`/specialties`) ## Summary An admin-only page that surfaces the otherwise hidden maintenance actions as cards, each a small form. It exists so support does not need SSMS or a hand-crafted POST for actions like resetting an invoice's stored PDF. It is a regular lazily loaded frontend module (`fn = specialties`), gated like the rest of the Administration menu (`fds_sys > 4`), and reachable both from the menu (Administration → Spezialfunktionen) and by opening the URL `/specialties` directly. ## How it works - **Module load** follows the standard contract (see `admin-system-status.md`): the menu item `init:specialties` → `$ocms.init('specialties')` → `POST /do/specialties/auth` → when `manage > 0`, import `web/fis.specialties.de.js` + `fis.specialties.css` and call `init2`. `IntranetController.Specialties.cs` answers only that auth probe (same `GetSystemAdminAuthAsync` gate as the Admin module) and 401s everything else. - **Deep link.** `IntranetController.Index` renders the same SPA shell for every `/{fn}` URL and ignores `fn`; there is no client router. `fis_main_go.js` therefore calls `$fis.openModuleFromPath()` once the admin menu has settled: it takes the first path segment and calls `$ocms.init(fn)` **only if the user's menu offers an `init:` item** (admin dropdown included). A non-admin opening `/specialties` sees the dashboard, as before; arbitrary paths never trigger a module load. - **Cards.** `fis.specialties.js` keeps an array `cards` of builder functions. Each card is `title + description +
+ result box`; `$spc.submit(c, { button, confirm, run, report })` wires HTML5 validation, a `confirm()`, the `postXT` call (`run(values)` returns the request) and the inline result (`report(response)` → `{ ok, lines }`). The card calls the action's **real** endpoint — every such endpoint enforces the admin gate itself; the page adds no authority. - **Current cards** - *Rechnungsdatei zurücksetzen (Soft-Delete)* → `POST /do/admin/backupclearinvoicefile/` (ADR 0027). Shows the outcome and the blob backup URI, or the German text for the service's `reason` (`invoice_not_found`, `not_final`, `external`, `no_file`, `db_error`). An invoice without a stored file (`hasFile` from `fds__getInvoice`) is answered `no_file` before any blob copy, so repeated clicks leave no spare `backup_*` blobs. - **Adding a card:** append a builder to `cards`, add its texts to `fis.specialties_txt_de.js`, run `npx gulp min`. No server change is needed unless the action itself is new. - **Build:** bundle entries in `Fuchs/bdlconfig.json` (`intranet:specialties`); generated files under `wwwroot/web/`. ## Key files - `Fuchs/Controllers/IntranetController.Specialties.cs` — auth probe. - `Fuchs/Controllers/IntranetController.cs` — `"specialties"` case in `Do`. - `Fuchs/js/intranet/modules/fis.specialties.js` / `_txt_de.js` / `.scss`. - `Fuchs/js/intranet/fis_main_menu.js` — menu item + `openModuleFromPath`. - `Fuchs/js/intranet/fis_main_go.js` — deep link after menu settles. - `Fuchs/js/intranet/fis_texts_gui_de.js` — `m_specialties` label. ## Related decisions - [0027 — Admin invoice-file backup-and-clear action](../Decisions/0027-admin-invoice-file-backup-and-clear.md)