ADR-0051: Sysadmin legt Organisationen an; Control-DB nur Metadaten
- Status: accepted
- Datum: 2026-09-02
- Phase: Multi-Tenant
- Bezug: ADR-0031, ADR-0032
- Ändert: ADR-0032 (Selbstanlage, impliziter Plattform-Operator)
Kontext
ADR-0032 band den Konto-Lebenszyklus an Selbstanlage: ein User ohne tenant_id legt per POST /tenants eine Organisation an und wird Org-Admin. Der Plattform-Operator war nur role=admin plus tenant_id null. Lokal setzte LINETRA_SHARED_DB=true tenants.dbname auf die Control-DB linetra, sodass GIS, Projekte und föderierte Entities neben app_users landeten.
Gewollt ist: ein Bootstrap-Sysadmin (Env) legt Organisationen an und bestimmt Org-Admins; Org-Admins verwalten nur die eigene Orga; die Control-DB hält nur Web-Metadaten.
Entscheidung
app_users.is_system_administ das Plattform-Flag. Org-Rolle bleibtrole(admin/editor/readerplus Fachrollen).- Bootstrap: leere
app_users→ ein Sysadmin ausLINETRA_BOOTSTRAP_ADMIN_*. Leerer Tenant-Katalog (oder eine Shared-dev-Zeile) → Organisation Nasarek Data Engineering, Slugnasarek, DBlinetra_nasarek. Der Bootstrap-User ist Sysadmin und Org-Admin; Person Robert Nasarek lebt in der Org-DB. POST /tenantsnur Sysadmin. Body enthält den ersten Org-Admin (Username, Passwort, Vorname, Nachname, E-Mail). Keine Selbstanlage.- Weitere Sysadmins legt nur ein Sysadmin an (
POST /usersmitis_system_admin). Der letzte aktive Sysadmin bleibt unantastbar. - Mitgliedschaft bleibt 1:1 (
app_users.tenant_id). Sysadmins dürfentenant_idnull haben und per Session /X-Tenant-Ideine Orga wählen. - Control-DB
linetra:tenants,app_users,editor_access_tokens,client_cert_grants. Fachdaten (Projekte, GIS, Schema-CMS, föderierte Records, Akteure) nur inlinetra_<slug>. - Kein stilles Shared-Fallback außerhalb von Tests:
tenant.dbname == POSTGRES_DBist ein Fehler, wennLINETRA_SHARED_DBaus ist. Pytest behält Shared-DB.
Begründung (für dieses Setup)
Zwei Ebenen (Plattform / Organisation) reichen: Isolationseinheit bleibt die Orga-DB (ADR-0030/0031). Ein explizites Sysadmin-Flag verhindert, dass jeder Org-Admin Plattformrechte erbt. Personfelder am Org-Admin gehören in persons der Tenant-DB, nicht auf app_users. Die bestehende Tenant-Session (get_db_session) schreibt Fachdaten bereits gegen tenants.dbname — die Lücke war Shared-DB, nicht die Route.
Verworfene Alternativen
| Alternative | Warum verworfen |
|---|---|
| Selbstanlage (ADR-0032 Punkt 2) | Orgs entstehen durch Sysadmins, nicht durch den ersten Login |
role=system_admin statt Flag |
Bootstrap-User ist Sysadmin und Org-Admin derselben Orga |
| M:N User ↔ Org | Ein Mitarbeiter gehört einer Orga |
| Drei Ebenen Tenant → Orgs | Organisation = Tenant = eine DB |
| Casbin / Oso | Vier klare Stufen, Principal existiert schon |
| RLS / Schema-pro-Tenant | Isolation war ADR-0030/0031 |
Namensfelder auf app_users |
Vorname/E-Mail sind Akteur (persons) |
| Control-Alembic-Geschichte umschreiben | Fach-DDL bleibt historisch; neue Fach-DDL nur unter alembic/tenant/ |
Folgen
- ADR-0032 Punkte 2 und 7 gelten nicht mehr. Föderierter Stamm und GIS-
project_idbleiben. - Principal:
can_manage_tenants/can_view_platform_settingsnur Sysadmin;can_manage_usersfür Org-Admin oder Sysadmin;can_create_projectfür Org-Admin oder Sysadmin im Org-Kontext. - Settings → System (Sysadmin): weitere Sysadmins, Org-Katalog. Settings → Organisation: kein Selbst-Create.
- QGIS
/auth/me.qgis_connection.databaseistlinetra_<slug>, nichtlinetra. - Optionaler Ops-Schritt nach dem Cutover:
scripts/strip_control_fachdaten.sh(Keep-Liste inkl.client_cert_grants). - Teardown (Sysadmin):
GET /tenants/{id}/backupliefert ZIP (pg_dump+ Control-Metadaten + Projektdateien) und HeaderX-Deletion-Token.DELETE /tenants/{id}mitconfirm_slug+ Token droppt Control-Zeilen,linetra_<slug>, Rollen und Dateiblobs. Bootstrap-Org undLINETRA_SHARED_DB=truesind nicht löschbar. Restore bleibt manuell aus dem ZIP.