# ADR-0012: Organisationseinheiten und Gruppen als Konfigurationsvererbung **Status:** Beschlossen **Datum:** 12.08.2026 ## Kontext Die Geräteliste im Kundenportal (siehe ADR-0011) kennt bislang nur eine einzige organisatorische Ebene unterhalb der Organisation selbst: gar keine. Jedes Gerät hängt lediglich an `organization_id` und optional an einer Bereitstellungsvorlage (Install-Rezept, siehe `03-organization-model.md`). Für Kund:innen mit mehreren Gebäuden, Jahrgangsstufen oder Klassen fehlt eine Möglichkeit, Geräte organisatorisch zu gruppieren und Konfiguration (Auftragskatalog-Merkmale, siehe ADR-0010) für eine solche Gruppe statt geräteweise vorzugeben — ein aus anderen MDM-Systemen bekanntes Bedürfnis (Organizational Units). In der Diskussion kristallisierten sich zwei fachlich unterschiedliche Gruppierungsbedürfnisse heraus, die sich nicht in einem einzigen Konzept abbilden lassen: 1. **Organisatorische Verortung** (z. B. „Gebäude A" → „Klasse 5a"): jedes Gerät gehört zu genau einem Ort, Orte können ineinander verschachtelt sein, und Konfiguration soll von einem allgemeineren zu einem spezifischeren Ort vererbt werden können — klassische OU-Semantik. 2. **Querschnitts-Zuordnung** (z. B. „Lehrer", „Schulleitung"): ein Gerät (bzw. dessen Nutzer:in) kann mehreren solcher Zuordnungen gleichzeitig angehören, die Zuordnungen selbst sind nicht hierarchisch. Beide Bedürfnisse mit einem einzigen, verschachtelbaren Gruppen-Konzept mit Mehrfachmitgliedschaft abzudecken, hätte bedeutet, dass die "zutreffenden Gruppen" eines Geräts keine einzelne Vorfahrenkette mehr sind, sondern die Vereinigung mehrerer, unabhängiger Vorfahrenpfade — mit entsprechend unklarer Konfliktauflösung selbst für den einfachen, hierarchischen Fall. Die beiden Bedürfnisse wurden deshalb bewusst als zwei getrennte Konzepte modelliert. ## Entscheidung **Organisationseinheiten (OEs)** bilden pro Organisation einen Baum (`parent_id`-Selbstreferenz). Ein Gerät gehört zu **genau einer** OE — exklusive Mitgliedschaft wie bei einem Ordner. Dadurch hat jedes Gerät eine eindeutige, einzelne Vorfahrenkette von seiner eigenen OE bis zur Organisation, und Vererbung ist unzweideutig: eine explizite Einstellung der spezifischsten OE in dieser Kette gewinnt über eine allgemeinere. Jede Organisation besitzt automatisch eine geschützte Standard-OE **„Neue Geräte"** (`ist_standard = true`, `parent_id = NULL`) — der Landeplatz für neu aktivierte Geräte (`load_or_create_device()`) sowie für alle Organisationen, die vor dieser Änderung angelegt wurden (per einmaligem Backfill-Script). Damit besitzt `devices.oe_id` nie einen NULL-Sonderfall im laufenden Betrieb; jedes Gerät zeigt immer auf eine echte OE. Die Standard-OE ist gegen Löschung geschützt, kann aber selbst Konfiguration tragen oder von ihrer (impliziten) Wurzel — der Organisation — nichts weiter erben als den Workspace-Default. Organisationseinheiten sind Self-Service durch die Kund:in selbst verwaltbar (Kundenportal, `/struktur`) — anders als bei Bereitstellungsvorlagen (installationszeitlich, technisch) ist die OE-Struktur eine rein organisatorische Entscheidung, die die Kund:in selbst am besten kennt. **Gruppen** sind dagegen bewusst flach (keine Verschachtelung) — ein Gerät kann **mehreren Gruppen gleichzeitig** angehören. Gruppen sind in dieser ersten Ausbaustufe nur intern verwaltbar (`/admin/kunden/{id}`), nicht Self-Service: bei der aktuellen, kleinen Kundenzahl sind die Bedürfnisse dem Betreiber bekannt genug, um sie direkt zu pflegen; künftige, heterogenere Kundschaft (KMUs) wird das wahrscheinlich einmal brauchen. Backend-seitig ist die Gruppen-API identisch zur OE-API aufgebaut (gleiche Endpunkt-Struktur für Merkmal-Overrides), sodass Self-Service später ohne Datenmodell-Umbau nachgezogen werden kann — nur die Kundenportal-Routen fehlen dafür noch. **Konfigurationsvererbung:** Sowohl OEs als auch Gruppen können — wie ein Gerät selbst über `device_merkmale` (ADR-0010) — einzelne katalogfähige Merkmale explizit auf `aktiv` oder `inaktiv` setzen (`oe_merkmale`, `gruppen_merkmale`; jeweils sparsam, nur bei tatsächlich abweichender Meinung eine Zeile). Die Auflösungsreihenfolge für ein Gerät ist: 1. **Workspace-Default** (wie bisher, ADR-0010): Teil des zugewiesenen Workspace → `present`, sonst `absent`. 2. **OE-Kette**: von der eigenen OE des Geräts zur Wurzel laufend gewinnt die erste explizite Einstellung (spezifischer schlägt allgemeiner — klassische Vererbung). 3. **Gruppen**: Das Ergebnis aus Schritt 2 zählt hier als eine weitere, gleichberechtigte Stimme neben den Einstellungen aller Gruppen, denen das Gerät angehört. Bei Widerspruch gewinnt **„mehr gewinnt"**: sobald irgendeine zutreffende Stimme `aktiv` sagt, ist das Ergebnis `aktiv`. Diese Regel wurde bewusst einer manuellen Prioritätsordnung zwischen Gruppen vorgezogen — bei Gruppen wie „Lehrer" und „Schulleitung" gibt es keine natürliche, für jedes Merkmal gültige Rangfolge, und „mehr gewinnt" ist ohne zusätzliche Konfiguration deterministisch und einfach erklärbar. Sie passt außerdem zur Art der heutigen Merkmale (Komfort-/Funktionsfeatures wie Browser oder Office-Programme, keine Sicherheits-Schalter) — ein künftiges, tatsächlich sicherheitsrelevantes Merkmal könnte stattdessen am Merkmal selbst eine abweichende Konfliktregel hinterlegt bekommen; das ist hier bewusst nicht vorweggenommen. 4. **Geräte-Override** (`device_merkmale`, ADR-0010, unverändert): gewinnt immer, unabhängig davon, was OE-Kette oder Gruppen sagen — die expliziteste, gerätespezifischste Entscheidung bleibt die letzte Instanz. Die Herkunft der wirksamen Einstellung (`workspace`, `oe`, `gruppe`, `geraet`) wird im Kundenportal sichtbar gemacht, statt die Auflösung als reine Blackbox zu präsentieren — Transparenz statt stiller Automatik. ## Konsequenzen `devices.oe_id` ist eine Pflichtangabe (`NOT NULL`, `ON DELETE RESTRICT`); jede Organisation muss vor dem ersten Gerät bereits ihre Standard-OE besitzen. `create_organization()` legt sie automatisch mit an; für die Bestandsdaten (Organisationen vor dieser Änderung) übernimmt ein einmaliges Backfill-Script (`scripts/backfill_organisationseinheiten.py`) das nachträglich, bevor die NOT-NULL-Migration angewendet wird. Das Löschen einer OE mit Kind-OEs oder zugeordneten Geräten sowie das Löschen der Standard-OE selbst wird anwendungsseitig verweigert (freundliche Fehlermeldung statt rohem DB-Fehler) — eine OE muss erst leergeräumt werden, bevor sie verschwinden kann. Die Auflösungsfunktion für den Auftragskatalog (`fetch_auftragskatalog_state()`/`fetch_auftragskatalog_listing()`, siehe ADR-0010) braucht für jedes Gerät zusätzlich die vollständige OE-Kette und Gruppenmitgliedschaft. Das wird bewusst in Python statt per rekursivem SQL gelöst (im gesamten `provisioning-server` bislang keine CTEs) — ein OE-Baum im Umfang einer Schule passt vollständig in den Speicher, eine einmalige Abfrage aller OEs einer Organisation reicht. Gruppen sind vorerst ein rein interner Verwaltungsmechanismus. Sollte künftig Self-Service für Gruppen nötig werden, ist das ein reiner Kundenportal-Routing-Zusatz (analog zu `routers/struktur.py`), keine Backend- oder Datenmodell-Änderung. Details zum Datenmodell: `09-data-model-v1.md`. Details zur bestehenden Auftragskatalog-Grundlage: ADR-0010, `12-feature-blueprint-model.md`.