Bei Talentera (der Bayt.com B2B-Recruitment-Plattform) habe ich ein paar Jahre damit verbracht, Multi-Tenant-Workflows zu architektonieren, die Unternehmen und Behörden auf einer gemeinsamen Codebase bedienen. Das Datenmodell sah am Tag eins gut aus — und hat, was noch überraschender ist, jahrelange Mandanten-spezifische Anforderungen überlebt. Der Trick war, Identity + Access Control als First-Class- Designachse zu behandeln, nicht als Middleware-Anliegen, das nach dem Schreiben der Business-Logik draufgeschraubt wird. Dieser Post ist die Kurzversion dessen, was ich jedem Engineer empfehlen würde, der 2026 eine Multi-Tenant-Plattform baut.
Die Form des Problems
Multi-Tenant-Recruitment ist fast ein Worst-Case für Access Control:
- Mehrere Klassen von Mandanten. Unternehmen, kleine Betriebe, Regierungs- ministerien — dieselbe Plattform, wildly verschiedene Erwartungen daran, was “Isolation” bedeutet.
- Shared Staff. Recruiter, die dieses Quartal für eine Agentur arbeiten und nächstes Quartal für eine andere. Ihre History darf nicht leaken. Ihre Credentials sollen portierbar sein.
- Kandidaten sind eine Cross-Tenant-Primitive. Ein Kandidat bewirbt sich auf Stellen bei zehn Unternehmen. Diese Unternehmen sollten die Interaktionen der anderen mit diesem Kandidaten nicht sehen.
- Government-Contracts kommen mit Audit-Anforderungen. Nicht “wir loggen Dinge.” Formale Anforderungen, mit regelmäßigen Audits, mit rechtlichen Konsequenzen bei Verstößen.
Jeder dieser Punkte ist zuerst ein Identity- / Access-Control-Problem. Der Rest der Plattform ist eine dünne Schicht darüber.
Das Modell, das funktioniert hat
Das Modell, das geshipt wurde und überlebt hat, wurde um vier Primitiven gebaut:
1. Mandant als First-Class, Non-Nullable-Entity
Jede Zeile in der Datenbank hatte eine Mandanten-Spalte, durch Datenbank-Level- Constraints durchgesetzt. Kein App-Level-Filter. Kein “wir erinnern uns, es hinzuzufügen.” Row-Level Security in Postgres (oder equivalent in anderen Stores). Wenn ein Engineer eine Query schrieb, die den Mandanten-Filter nicht enthielt, hat die Datenbank einen Fehler geworfen.
Der Tradeoff war, dass jede Query leicht ausführlicher aussah. Der Gewinn war, dass ein Bug in der App niemals einen Cross-Tenant-Leak verursachen konnte, weil die Datenbank geweigert hat, den Request zu bedienen.
2. Subject / Relationship / Resource, nicht User / Role
Das Off-the-Shelf-Modell — User haben Rollen, Rollen haben Berechtigungen, Berechtigungen schützen Ressourcen — ist für einfache Apps gut. Es bricht in einem Multi-Tenant-Recruitment-Kontext, weil die Rolle eines Users davon abhängt, in welchem Mandanten er operiert. Ein Recruiter, der bei Agentur A “Admin” ist, ist bei Agentur B “Guest” und bei Agentur C “nichts”.
Das Modell, das wir verwendeten, war näher am Zanzibar-Stil (bevor Zanzibar ein Haushaltsname in der Engineering-Community war): Subject hat eine Relationship zu einer Ressource, vermittelt durch den aktuellen Mandanten-Kontext. Eine einzige Query antwortete auf “kann dieses Subject diese Aktion auf dieser Ressource in diesem Kontext ausführen?”, und die Antwort wurde aus dem Relationship-Graph berechnet, nicht aus einem Role-Enum.
Diese eine Änderung hat Dutzende von Produkt-Features freigeschaltet, die im Role-Enum-Modell bespoke Berechtigungs-Code erfordert hätten.
3. Shared Identity, Scoped Session
User hatten eine einzige Identity — ihren Login. Wenn sie sich authentifizierten, bekamen sie ein Session-Token, das auf einen bestimmten Mandanten gescopet war. Mandanten zu wechseln bedeutete, eine neue Session auszustellen, nicht die bestehende zu mutieren. Die Session trug die Mandanten-ID, die für diesen Mandanten relevanten Relationships des Subjects und den audit-sichtbaren Identifier der Session selbst.
Das bedeutete, dass jede auditierte Aktion trivial zu (subject, tenant, session, timestamp) zurückverfolgt werden konnte — und Fragen von Auditoren wie “wer hat was für wen getan” zu einer Ein-Query-Antwort wurden.
4. Audit als Append-Only-Domain-Event
Jede Mutation im System hat ein Domain-Event an ein Append-Only-Audit-Log emittiert. Das Audit-Log war ein First-Class-Teil des Anwendungsschemas, kein Ops- Nachgedanke. Als ein Regierungsauditor fragte “zeig mir alle Lebenslauf-Ansichten dieses Recruiters im März”, war die Antwort eine Query — keine mehrwöchige Übung in Log-Korrelation.
Das von Anfang an zu bauen ist 3× billiger als es nachzurüsten. Das weiß ich, weil ich beides getan habe.
Die Fehler
Zwei Dinge, die ich falsch gemacht habe:
1. Die erste Version der Rollenvererbung war zu flach. Wir hatten eine Admin- User-Contributor-Hierarchie, und das war es. Unternehmen wollten Sub-Admins. Wir mussten nachträglich Rollenkomposition hinzufügen, was bedeutete, eine Reihe von Annahmen zu entwirren, dass “Admin diese Dinge alle bedeutet.” Der richtige Zug wäre gewesen, Komposition von Anfang an zu bauen — aber ich habe den Bedarf erst bei Kunde Nr. 20 gesehen.
2. Das Multi-Tenancy-Modell ließ sich nicht sauber auf Analytics ausweiten. Für transaktionale Queries war das Row-Level Tenant-Scoping kugelsicher. Für BI- / Reporting-Workloads wurde es schnell teuer. Wir landeten bei einer separaten Analytics-Pipeline, die die Mandanten-Grenze auf Pipeline-Ebene durchsetzte, nicht auf Query-Ebene. Das funktionierte — aber es war viel Klempnerarbeit, die zweimal zu bauen war, und ich würde es anders machen, wenn ich von vorne anfinge.
Was ich 2026 anders machen würde
Vier Jahre später, von Grund auf neu anfangend, würde ich:
- Von Tag eins nach OPA (Open Policy Agent) oder einem ähnlichen Policy-Engine greifen, statt die Permission-Evaluation-Engine selbst zu bauen. Günstiger, auditiert, gut getestet, und das konzeptuelle Modell ist dasselbe.
- Postgres Row-Level Security oder eine äquivalente harte Grenze verwenden. Nicht “wir filtern in der App.” Der Perimeter muss auf Datenbankebene sein.
- Ein strukturiertes Audit-Event-Schema wählen, bevor der erste Mutations- Endpoint geschrieben wird. Jedes Event ist (actor, subject, action, resource, tenant, timestamp, outcome, diff). Wenn ein neues Feature eine Event-Form braucht, die das Schema nicht unterstützt, ist das ein Schema-Gespräch, kein “log einfach irgendwas.”
- Open ID Connect + einen dedizierten Identity-Provider statt selbst gerollter Auth verwenden. Pocket ID, Keycloak, Auth0, Ory — die guten Optionen sind billiger als die DIY-Kosten.
Das Pattern, das generalisiert
Nichts davon ist recruitment-spezifisch. Jedes B2B-SaaS, jede Multi-Tenant-Plattform, jedes regierungsnahe System hat dieselbe Form. Der Grund, warum die meisten davon ein Durcheinander sind, ist, dass Identity und Access Control als Middleware behandelt werden — draufgeschraubt, unterspecifiziert, nie die Priorität. Die, die gut altern, behandeln Identity als Produktdimension: Teil des Domain-Modells, Teil der Design- Reviews, Teil der Roadmap.
Wenn du gerade eine Multi-Tenant-Plattform baust: Das Identity-Modell ist die tragendste Design-Entscheidung, die du im ersten Jahr treffen wirst. Du kannst es nicht billig nachrüsten. Mach es richtig. Investiere die Zeit. Lies das Zanzibar- Paper. Sprich mit Leuten, die das gemacht haben. Es addiert sich.