4.3 KiB
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_idals 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
Platform
└── Tenant
└── Kunde
└── Verträge
└── Domains
└── Hostingpakete
└── Tickets
└── Dokumente
Später möglich:
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:
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:
tenant_id
Beispiele:
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.:
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:
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_idsofort 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