Files
kaffeekasse-saas/docs/backoffice.md
T
clemensandClaude Sonnet 5 cbe6547f3a Back-Office: globaler Platform-Admin-Zugang ueber alle Mandanten
Neue, bewusst von tenant_memberships/saas_user_has_role() komplett
getrennte Platform-Admin-Ebene (neue Tabelle platform_admins), damit die
bestehende, automatisiert getestete Mandanten-Isolation
(check-m8-tenant-isolation.php, check-m8-role-matrix.php) unangetastet
bleibt - Platform-Admin-Rechte wirken ausschliesslich auf den neuen
backoffice-*.php-Seiten.

- backoffice.php: Uebersicht aller Mandanten (Status, Teilnehmerzahl,
  Saldensumme).
- backoffice-mandant.php: reine Leseansicht eines Mandanten (Einstellungen,
  Mitglieder/Rollen, letzte Buchungen, letzte Admin-Aktionen). Bewusst
  kein Schreibzugriff von hier aus.
- backoffice-export.php: nutzt dieselbe app_export_tenant_data() wie der
  Selbstbedienungs-Export, ausgeloest durch den Platform-Admin fuer
  beliebige Mandanten.
- scripts/grant-platform-admin.php: CLI-only Bootstrap fuer den ersten
  Platform-Admin, bewusst keine Web-UI dafuer.
- Jede Back-Office-Ansicht/-Export wird im Audit-Log DES BETROFFENEN
  MANDANTEN protokolliert (Transparenzpflicht), nicht nur beim Betreiber.

Der bestehende Selbstbedienungs-Export (datenexport.php aus M8) bleibt
zusaetzlich bestehen statt ersetzt zu werden: der Mandant ist im AV-
Verhaeltnis Verantwortlicher, Art. 15/20/28 DSGVO verpflichten den
Auftragsverarbeiter zur Unterstuetzung bei Ausk''unfts-/Portabilitaets-
rechten - ein jederzeit verfuegbarer Mandanten-Export erfuellt das direkt.
Details und Begruendung in docs/backoffice.md.

Live getestet: Back-Office zeigt alle Mandanten korrekt (inkl. echter
Bestandsmandanten), Detail/Export fuer Test-Mandant funktioniert,
Audit-Log korrekt geschrieben. Kritischer Test bestanden: derselbe
Platform-Admin sieht auf normalen Mandanten-Seiten weiterhin nur seinen
eigenen Mandanten; ein eingeloggter Nicht-Platform-Admin bekommt 403.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 22:18:48 +02:00

111 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Back-Office (Platform-Admin)
Stand: 2026-07-16
Ergänzung außerhalb der ursprünglichen M0M9-Meilensteine: ein
Betreiber-Zugang, der mandantenübergreifend alle Kunden einsehen kann
getrennt von der normalen, streng mandantengebundenen Rollenlogik.
## Design-Entscheidung: getrennt von `tenant_memberships`
Platform-Admin-Rechte sind bewusst **kein** Teil von
`saas_user_has_role()`/`tenant_memberships`, sondern eine eigene, komplett
separate Tabelle `platform_admins` (`user_id``users.id`). Das ist
kein Zufall: Alle bestehenden Mandanten-Seiten und die automatisierten
Isolationstests (`scripts/check-m8-tenant-isolation.php`,
`scripts/check-m8-role-matrix.php`) verlassen sich darauf, dass ein
Login niemals automatisch mandantenübergreifenden Zugriff bekommt. Ein
Platform-Admin-Flag direkt in `tenant_memberships` oder `users` einzubauen
hätte dieses Fundament unterlaufen können. Stattdessen prüft
ausschließlich der neue Code-Pfad in `app/platform-admin.php`
(`app_require_platform_admin()`) auf Back-Office-Seiten die
Platform-Admin-Eigenschaft; alle bestehenden Seiten sind unverändert und
bleiben strikt mandantengebunden.
## Umgesetzte Dateien
```text
database/migrations/0013_saas_platform_admins.sql
app/platform-admin.php
scripts/grant-platform-admin.php
backoffice.php
backoffice-mandant.php
backoffice-export.php
```
## Erster Platform-Admin
Es gibt bewusst **keine Weboberfläche**, um den ersten Platform-Admin zu
setzen das wäre ein öffentlich erreichbarer "werde Admin"-Endpunkt und
ein erhebliches Risiko. Stattdessen: Person registriert sich normal als
Mandant (oder nutzt einen bestehenden Login), danach per Shell-Zugriff auf
dem Server:
```bash
php scripts/grant-platform-admin.php person@example.com
```
Das Skript prüft, dass der Account existiert, und legt nur dann den
`platform_admins`-Eintrag an. Zugang entziehen aktuell nur per direktem
`DELETE FROM platform_admins WHERE user_id = ?` (keine UI dafür aus
demselben Grund wie beim Setzen).
## Funktionsumfang
- `backoffice.php`: Übersicht aller Mandanten mit Kürzel, Status,
Erstelldatum, Teilnehmerzahl (aktiv/gesamt) und Saldensumme.
- `backoffice-mandant.php?tenant_id=X`: reine Leseansicht eines einzelnen
Mandanten Einstellungen, Mitglieder mit Rolle, letzte 20 Buchungen,
letzte 20 Admin-Aktionen. Absichtlich **kein** Schreibzugriff auf
Mandantendaten von hier aus, um das Risiko einer versehentlichen
Fremdänderung auszuschließen.
- `backoffice-export.php`: nutzt dieselbe `app_export_tenant_data()`-
Funktion wie der Selbstbedienungs-Export, aber ausgelöst durch den
Platform-Admin für einen beliebigen Mandanten.
## Verhältnis zum Selbstbedienungs-Export (`datenexport.php`)
Bewusste Entscheidung: Der bestehende Selbstbedienungs-Export für
Mandanten-Owner/Admin (`datenexport.php`, aus M8) bleibt zusätzlich
bestehen, statt ihn durch das Back-Office zu ersetzen. Begründung: Der
Mandant ist im Auftragsverarbeitungs-Verhältnis der Verantwortliche
(Controller), der Betreiber dieser App der Auftragsverarbeiter
(Processor). Art. 15/20 DSGVO geben den betroffenen Personen ein
Auskunfts-/Portabilitätsrecht, und Art. 28 DSGVO verpflichtet den
Auftragsverarbeiter, den Verantwortlichen bei der Erfüllung dieser
Rechte zu unterstützen sowie Daten am Vertragsende zurückzugeben ein
jederzeit verfügbarer Selbstbedienungs-Export erfüllt genau das. Das
Back-Office ergänzt das um einen Betreiber-seitigen Zugriff für Support,
Migrationen oder eigene Nachweispflichten, ersetzt den
Mandanten-Selbstexport aber nicht.
## Audit-Trail
Jede Back-Office-Ansicht und jeder Back-Office-Export wird im Audit-Log
**des betroffenen Mandanten** protokolliert
(`backoffice.tenant_viewed`, `backoffice.tenant_exported`, mit dem
Platform-Admin als `actor_user_id`). Ein Mandant sieht damit über sein
eigenes Protokoll (`mandant-einstellungen.php`), wann der Betreiber auf
seine Daten zugegriffen hat Transparenzpflicht statt stiller
Einsicht.
## Prüfstatus
- `scripts/check-m8-tenant-isolation.php`: weiterhin grün mit 10
Assertions das Back-Office berührt die geprüften Pfade nicht.
- `scripts/check-m8-role-matrix.php`: weiterhin grün mit 55 Assertions.
- HTTP-Smoke: grün mit 30 geprüften Seiten (zwei neue Login-Schutz-Checks
für `backoffice.php`/`backoffice-mandant.php`).
- Golden Master: grün mit 104 Assertions.
Live getestet: eigens angelegter Test-Mandant, per CLI-Skript zum
Platform-Admin gemacht, Back-Office-Übersicht zeigt korrekt alle
Mandanten (inklusive der echten Bestandsmandanten), Detailansicht und
Export für den eigenen Test-Mandanten funktionieren, Audit-Log-Einträge
korrekt geschrieben. Kritischer Isolationstest bestätigt: derselbe
Platform-Admin sieht auf regulären Mandanten-Seiten (`kaffeeliste.php`)
weiterhin ausschließlich seinen eigenen Mandanten. Ein zweiter,
eingeloggter, aber nicht privilegierter Testnutzer bekommt auf
`backoffice.php` korrekt `403 Forbidden`. Alle Testdaten anschließend
vollständig entfernt.