Files
2026-05-18 04:37:23 +00:00

163 lines
4.3 KiB
Markdown

# ADR 0004 — Tenancy-Modell
## Status
Accepted
## Kurz erklärt
Tenancy bedeutet Mandantenfähigkeit.
Ein Mandant ist z. B. ein Anbieter, eine Agentur oder später ein Reseller, der seine eigenen Kunden, Verträge, Domains und Rechnungen verwaltet.
Das Tenancy-Modell legt fest, wie Daten verschiedener Mandanten technisch voneinander getrennt werden.
## Kontext
Hosting-Backoffice soll zunächst einfach nutzbar sein, später aber mandantenfähig und ggf. resellerfähig erweitert werden können.
Die bisherige Planung enthielt die Begriffe `tenant_id` und `organisation_id`, ohne deren Verhältnis eindeutig zu definieren.
Das wurde im Architekturreview als kritisches Risiko bewertet, da eine nachträgliche Mandantenfähigkeit sehr teuer und fehleranfällig wäre.
## Entscheidung
Hosting-Backoffice verwendet von Beginn an ein mandantenfähiges Datenmodell mit:
- `tenant_id` als zentrale Mandantenreferenz
- Shared Database Modell
- PostgreSQL als bevorzugte Datenbank
- Tenant Scope auf Anwendungsebene
- Row Level Security als spätere zusätzliche Sicherheitsschicht
`organisation_id` wird vorerst nicht als separates Standardfeld verwendet.
Falls später eine Organisationshierarchie benötigt wird, wird diese über das Tenant-Modell abgebildet.
## Gewähltes Modell
```text
Platform
└── Tenant
└── Kunde
└── Verträge
└── Domains
└── Hostingpakete
└── Tickets
└── Dokumente
```
Später möglich:
```text
Platform
└── Tenant
└── Reseller-Tenant
└── Kunden
```
Dafür kann später ein Feld wie `parent_tenant_id` in der Tenant-Struktur ergänzt oder vorbereitet werden.
## Begründung
Ein Shared-Database-Modell mit `tenant_id` ist für den Start sinnvoll, weil:
- V1 klein bleiben soll
- alle Daten zentral verwaltbar bleiben
- Migrationen einfacher sind
- Betrieb und Backups weniger komplex sind
- spätere Mandantenfähigkeit vorbereitet wird
- Resellerstrukturen später möglich bleiben
PostgreSQL wird bevorzugt, weil es Row Level Security unterstützt.
Row Level Security bedeutet:
```text
Die Datenbank selbst kann verhindern,
dass Mandant A Datensätze von Mandant B sieht.
```
Das ist eine zusätzliche Sicherheitsschicht neben der Anwendung.
## Konsequenzen
### Positiv
- Mandantenfähigkeit wird nicht später „angeklebt“
- bessere Grundlage für spätere SaaS-/Resellerfähigkeit
- klare Datenisolation
- bessere Sicherheitsarchitektur
- weniger Refactoring-Risiko
### Negativ
- jede mandantenbezogene Tabelle braucht `tenant_id`
- alle Abfragen müssen tenant-aware sein
- Entwickler müssen von Anfang an sauber mit Tenant-Kontext arbeiten
- Tests müssen Mandantenisolation prüfen
## Technische Leitlinien
Alle mandantenbezogenen Tabellen erhalten:
```text
tenant_id
```
Beispiele:
```text
customers.tenant_id
contracts.tenant_id
domains.tenant_id
hosting_packages.tenant_id
tickets.tenant_id
documents.tenant_id
```
Nicht mandantenbezogene Tabellen können global sein, z. B.:
```text
system_settings
module_registry
global_permissions
```
## Anwendungsebene
Laravel soll sicherstellen, dass mandantenbezogene Daten nur im aktuellen Tenant-Kontext geladen werden.
Dafür vorgesehen:
- Tenant Context
- Eloquent Global Scopes
- Policies
- Tests gegen Tenant-Leaks
Tenant-Leak bedeutet:
```text
Ein Benutzer oder Prozess sieht versehentlich Daten eines anderen Mandanten.
```
## Datenbankebene
PostgreSQL Row Level Security soll als spätere zweite Schutzschicht vorbereitet werden.
V1 kann zunächst mit sauberem Tenant Scope in Laravel starten.
RLS sollte jedoch nicht durch Datenmodellentscheidungen blockiert werden.
## Offene Punkte
Noch zu klären:
- genaue Tenant-Tabelle
- ob `parent_tenant_id` sofort angelegt wird
- ob V1 technisch bereits echtes Multi-Tenant-Login erlaubt
- wie Plattform-Admins mandantenübergreifend arbeiten dürfen
- wie Tenant-Offboarding später funktioniert
## Nicht entschieden
Diese ADR entscheidet noch nicht:
- ob Hosting-Backoffice später SaaS oder nur self-hosted wird
- ob einzelne Mandanten später eigene Datenbanken erhalten können
- ob Resellerstrukturen bereits in V1 aktiv sichtbar sind
## Verwandte ADRs
- ADR 0005 — Datenbankwahl
- ADR 0006 — Auth-Strategie
- ADR 0009 — Core-Grenzen
- ADR 0011 — GoBD-Verantwortlichkeit