diff --git a/adr/0015-konfigurationsgruppen-admin-auftragskatalog-ui.md b/adr/0015-konfigurationsgruppen-admin-auftragskatalog-ui.md new file mode 100644 index 0000000..fba8e53 --- /dev/null +++ b/adr/0015-konfigurationsgruppen-admin-auftragskatalog-ui.md @@ -0,0 +1,92 @@ +# ADR-0015: Konfigurationsgruppen im Admin-Auftragskatalog-UI + +**Status:** Beschlossen +**Datum:** 12.08.2026 + +## Kontext + +ADR-0012 brachte OEs/Gruppen samt Herkunfts-Anzeige ("via OE"/"via Gruppe") +im Auftragskatalog — nutzbar war das aber nur über das Kundenportal. Der +interne Admin-Bereich (`/admin/geraete`) teilt sich zwar dasselbe +Auftragskatalog-Template (`templates/auftragskatalog.html`) mit dem +Kundenportal und bekam die Herkunfts-Anzeige dadurch automatisch mit, aber: + +1. Die Admin-Geräteliste zeigte keine OE-Spalte und bot keine Möglichkeit, + ein Gerät zwischen OEs zu verschieben (die Kundenportal-Liste bekam das + bereits in der vorherigen Session). +2. "via OE"/"via Gruppe" war reiner Text ohne Sprungziel — welche konkrete + OE oder Gruppe verantwortlich ist, ließ sich aus der Anzeige nicht + erkennen, geschweige denn direkt dorthin wechseln. +3. Für Gruppen existierte bereits eine Admin-Detailseite + (`/admin/kunden/{org_id}/gruppen/{id}`), für OEs **keine einzige** + Admin-Ansicht — ein Link "via OE" hätte kein Ziel gehabt. + +Beim Umsetzen zusätzlich gefunden: `templates/auftragskatalog.html` +verdrahtete die Select-/Deselect-Formulare fest auf +`/geraete/{id}/auftragskatalog/...`, den Kundenportal-Pfad, statt den +mitgelieferten `zurueck_url`-Kontextwert zu nutzen (der in beiden Routern +— `routers/geraete.py` und `routers/admin_geraete.py` — bereits exakt den +richtigen Präfix trägt). Für einen Admin, der ein Gerät einer fremden +Organisation ansah, schlug Auswählen/Abwählen dadurch mit `404` fehl +(`find_device_in_organization()` prüft gegen `user.organization_id`, die +für einen Admin nie zur fremden Organisation passt) — ein latenter Bug seit +der gemeinsamen Template-Nutzung (ADR-0011), unabhängig von dieser +Entscheidung hier mitgefixt. + +## Entscheidung + +**Herkunft bekommt eine konkrete ID, nicht nur einen Typ.** +`resolve_katalog_overrides()` (`provisioning-server/app.py`) liefert +zusätzlich zu `quelle` ("oe"/"gruppe"/"geraet"/"workspace") die konkrete +`quelle_id` — bei OEs eindeutig die gewinnende OE in der Kette, bei Gruppen +eine der zustimmenden Gruppen (bei mehreren gleichzeitig zustimmenden +Gruppen wird bewusst nicht jede einzeln attribuiert, sondern nur eine +davon verlinkt — Sprungziel-Zweck, kein vollständiger Audit-Trail). Die +eigentliche "mehr gewinnt"-Auflösungslogik aus ADR-0012 ändert sich dadurch +nicht, nur die zusätzlich mitgeführte Information. + +**`fetch_all_devices()` bekommt denselben OE-Join** wie +`fetch_devices_for_organization()` aus der letzten Session — Grundlage für +OE-Spalte und Verschieben-Aktion in der Admin-Geräteliste, symmetrisch zum +Kundenportal. + +**Admin-OE-Ansicht bewusst minimal**, kein Pendant zum vollen Kundenportal- +Self-Service (`/struktur`): nur ein Merkmale-Editor +(`/admin/kunden/{org_id}/organisationseinheiten/{oe_id}/merkmale`), der als +Sprungziel für die Herkunfts-Links dient. Kein Anlegen/Umbenennen/Löschen +von OEs im Admin-Bereich — die OE-Struktur bleibt laut ADR-0012 bewusst +Kunden-Self-Service, das wird hier nicht revidiert. Für die +Merkmal-Bearbeitung selbst reichten die bereits für `/struktur` gebauten +anode-Endpunkte (`GET/POST /api/v1/organisationseinheiten/{oe_id}/merkmale +...`) unverändert aus — keine neuen anode-Endpunkte nötig, exakt das in +ADR-0012 für Gruppen vorhergesagte (und dort auch schon eingetretene) +Muster: Self-Service-Endpunkte sind von Anfang an so generisch, dass eine +zweite Oberfläche (hier: eine schlankere Admin-Ansicht statt vollem +Self-Service) sie ohne Backend-Änderung mitnutzen kann. + +**Bugfix ohne Verhaltensänderung für den Kundenportal-Pfad:** Die +Formular-Ziele in `auftragskatalog.html` nutzen jetzt `{{ zurueck_url +}}/{{ device.id }}/...` statt des festen `/geraete/...`-Präfixes. +`zurueck_url` war für beide Aufrufer bereits korrekt gesetzt (`/geraete` +bzw. `/admin/geraete`), nur ungenutzt — reine Fehlerbehebung, keine neue +Fähigkeit. + +## Konsequenzen + +Der Admin-Bereich hat jetzt für OEs zwei unterschiedlich mächtige +Zugriffswege (volle Selbstverwaltung nur über das Kundenportal als +eingeloggte Kund:in, minimale Merkmal-Bearbeitung über die neue +Admin-Seite) — bewusst asymmetrisch zu Gruppen (dort admin-verwaltbar seit +ADR-0012, inzwischen zusätzlich auch Kundenportal-Self-Service). Sollte +künftig doch ein vollständiges Admin-seitiges OE-CRUD gebraucht werden +(Support-Fall: Kund:in bittet den Betreiber, OEs für sie anzulegen), ist +das eine reine Ergänzung um Create/Rename/Delete-Routen nach dem +Gruppen-Vorbild in `routers/admin_kunden.py` — keine Datenmodell-Änderung. + +Der Bugfix betrifft ausschließlich den Admin-Pfad in der Praxis (der +Kundenportal-Pfad war korrekt, weil `zurueck_url` dort zufällig mit dem +zuvor hartkodierten Wert übereinstimmte) — kein Verhalten für bestehende +Kundenportal-Nutzer:innen ändert sich. + +Details zum Datenmodell und zur Grundentscheidung: ADR-0012, +`09-data-model-v1.md`.