Alle Artikel
12. September 2026
7 mins

Mandantenfähigkeit nachrüsten

Von Tim Rutte, Cloud & Software ArchitectThemaBackend & Plattformen

Sechs gleiche Vorratsgläser in einer Reihe; aus einem läuft blaue Farbe auf das Nachbarglas.

Der Anlass ist fast immer derselbe und immer eine gute Nachricht: Ein zweiter Kunde will genau das, was der erste hat. Die Anwendung ist über Jahre für einen gebaut worden, und jetzt soll sie für zwei da sein.

Der naheliegende Weg ist, sie ein zweites Mal aufzusetzen. Das funktioniert, es ist an einem Tag erledigt, und es ist die teuerste Entscheidung in dieser Geschichte. Bei drei Kunden ist es noch beherrschbar. Bei zwölf ist jedes Upgrade ein Vorhaben, jede Fehlerkorrektur zwölfmal auszurollen, und niemand weiß mehr, welche Instanz welche Sonderanpassung trägt.

Dieser Artikel beschreibt, wie Mandantenfähigkeit nachträglich in ein System kommt, das nicht dafür gebaut wurde, und vor allem die Stellen, an denen sie regelmäßig undicht bleibt.

Drei Modelle, und die Wahl fällt nicht nach Geschmack

Es gibt drei Wege, Mandanten zu trennen, und sie unterscheiden sich nicht in der Qualität, sondern darin, wofür sie passen.

Eine Datenbank je Mandant. Die härteste Trennung, und die einzige, die ohne Vertrauen in den eigenen Code auskommt: Ein Programmierfehler kann keine fremden Daten zeigen, weil sie nicht erreichbar sind. Der Preis ist der Betrieb. Jede Schemaänderung läuft so oft, wie es Mandanten gibt, und ein fehlgeschlagener Lauf bei Mandant sieben ist ein eigener Vorfall. Richtig bei wenigen, großen Kunden mit hohen Anforderungen an Trennung, etwa im Gesundheitswesen oder bei öffentlichen Auftraggebern.

Ein Schema je Mandant in einer Datenbank. Der Mittelweg, und meistens der schlechteste: Man hat den Betriebsaufwand vieler Schemata und trotzdem eine gemeinsame Datenbank als Engpass. Es gibt Fälle dafür, aber sie sind seltener, als die Beliebtheit dieses Wegs vermuten lässt.

Eine gemeinsame Struktur mit einer Mandantenspalte. Der Weg für viele Kunden, und der einzige, bei dem eine Schemaänderung ein einziger Lauf bleibt. Die Trennung liegt dann im Code, und genau davon handelt der Rest dieses Artikels.

Eine Zwischenform ist praktisch oft die beste: gemeinsame Struktur, aber die Möglichkeit, einen einzelnen großen Mandanten in eine eigene Datenbank auszulagern. Das ist derselbe Gedanke wie beim Sharding, nur nach Kunde geschnitten statt nach Schlüsselbereich, und es hält die Tür offen, ohne sie am Anfang zu öffnen.

Die Spalte ist der einfache Teil

Beim Nachrüsten ist das Hinzufügen der Mandantenspalte ein Nachmittag. Der schwere Teil ist die Zusicherung, dass ab jetzt jede einzelne Abfrage danach filtert, und die lässt sich nicht durch Sorgfalt herstellen.

Ein System mit achthundert Abfragen braucht achthundert richtige Entscheidungen, und es reicht eine falsche. Die Stelle, an der es passiert, ist nie die Hauptabfrage, sondern der Bericht, den jemand vor vier Jahren geschrieben hat.

Deshalb gehört der Filter eine Ebene tiefer, wo er nicht vergessen werden kann. In der Datenbank heißt das zeilenbasierte Sicherheit:

-- Der Filter liegt in der Datenbank, nicht im Code. Eine
-- vergessene WHERE-Klausel liefert dann keine fremden Zeilen,
-- sondern gar keine.
ALTER TABLE bestellung ENABLE ROW LEVEL SECURITY;

CREATE POLICY nur_eigener_mandant ON bestellung
  USING (mandant_id = current_setting('app.mandant')::int);

-- Wichtig: auch fuer den Besitzer der Tabelle erzwingen.
-- Ohne diese Zeile umgeht die Anwendung ihre eigene Regel,
-- wenn sie mit dem Eigentuemerkonto verbunden ist.
ALTER TABLE bestellung FORCE ROW LEVEL SECURITY;

Die letzte Zeile ist der häufigste Fehler bei dieser Einrichtung, und sie fällt nicht auf: Die Regel ist da, sie greift im Test mit einem eigenen Konto, und in Produktion ist sie wirkungslos, weil die Anwendung als Eigentümer verbunden ist.

Wo die Datenbank das nicht bietet, übernimmt die Zugriffsschicht dieselbe Aufgabe. In Doctrine ist es ein Filter, der bei jeder Abfrage eine Bedingung ergänzt; in Eloquent ein globaler Bereich. Das ist schwächer als die Datenbankregel, weil roher Code daran vorbeikommt, und immer noch um Größenordnungen besser als achthundert Einzelentscheidungen.

Der Test, der die Lecks findet

Eine Zusicherung, die nicht geprüft wird, hält bis zur nächsten Änderung. Die Prüfung dafür ist erstaunlich einfach und in einem Tag gebaut.

Die Testdatenbank bekommt zwei Mandanten, und beide bekommen Daten, die sich unterscheiden lassen. Dann läuft die vorhandene Testsuite als Mandant A, und danach prüft ein Test, dass in keiner Antwort eine Kennung von Mandant B vorkam.

Der wirksamste Zusatz dazu kostet fünf Zeilen: Der zweite Mandant bekommt die höheren Kennungen, und ein Test ruft jede Detailseite mit der Kennung eines fremden Datensatzes auf. Die richtige Antwort darauf ist „nicht gefunden". Wer stattdessen „kein Zugriff" antwortet, verrät, dass es den Datensatz gibt, und das ist bei Mandanten, die einander nicht kennen sollen, schon eine Auskunft.

Was außer der Datenbank noch mandantenfähig werden muss

Hier liegt der Teil, der in Planungen fehlt und die Hälfte des Aufwands ausmacht. Mandantenfähigkeit endet nicht an der Datenbank.

Die Zwischenspeicher. Der gefährlichste Punkt der ganzen Liste, weil er still ist. Ein Schlüssel wie bericht_2026_11 liefert dem zweiten Mandanten die Zahlen des ersten, und niemand bemerkt es, weil kein Fehler entsteht. Jeder Schlüssel trägt ab jetzt die Mandantenkennung, ohne Ausnahme.

Dateien und Anhänge. Getrennte Ablagepfade, und Zugriff nie über eine erratbare Adresse. Ein Anhang, der unter einer laufenden Nummer liegt, ist ein Leck mit Ansage.

Der Suchindex. Entweder ein Index je Mandant oder ein Pflichtfilter in jeder Suchanfrage. Ein Index ohne Mandantenfeld ist die zweite stille Stelle nach den Zwischenspeichern.

Hintergrundläufe. Jeder Auftrag trägt den Mandanten in seiner Nutzlast, und der Arbeiter setzt ihn, bevor er etwas tut. Ein nächtlicher Lauf, der „alle Bestellungen" verarbeitet, ist nach der Umstellung eine andere Aussage als vorher.

Ausgehende E-Mail. Absender, Vorlagen, Fußzeile und Impressum gehören zum Mandanten. Das ist keine Technik, sondern die Stelle, an der ein Kunde merkt, dass er auf einer geteilten Plattform sitzt.

Protokolle und Kennzahlen. Beide bekommen den Mandanten als Merkmal, sonst ist die erste Frage nach einem Vorfall nicht zu beantworten: Betraf das alle oder einen?

Die Vorarbeit dafür ist dieselbe wie beim Vermehren einer Anwendung: Sessions, Uploads, Konfiguration.

Der laute Nachbar

Mit dem zweiten Kunden entsteht ein Problem, das es vorher nicht gab: Einer kann dem anderen die Anwendung lahmlegen, ohne etwas Verbotenes zu tun.

Der Export über drei Jahre, der Import mit zweihunderttausend Zeilen, der Bericht, den jemand alle zehn Sekunden neu lädt: Alles legitim, und alles verbraucht Kapazität, die den anderen fehlt.

Die Antwort ist keine Architektur, sondern zwei Vorkehrungen. Erstens Grenzen je Mandant statt je Nutzer, weil die Rechnung auf der Ebene des Kunden aufgemacht wird. Zweitens getrennte Warteschlangen für lange Arbeiten, damit ein Mandant mit fünfhundert wartenden Aufträgen nicht die Aufträge aller anderen hinter sich staut. Beides ist in einer Woche eingerichtet und verhindert den Vorfall, den man sonst erst kennenlernt.

Warum die stillen Verweise im Schema dabei so viel Arbeit machen, steht in Das eigentliche Legacy ist Ihr Datenbankschema.

Die Reihenfolge der Umstellung

Beim Nachrüsten gibt es einen Ablauf, der das Risiko klein hält, und sein Kern ist, dass der bestehende Kunde zuerst Mandant wird, lange bevor ein zweiter dazukommt.

Zuerst bekommt jede Tabelle die Spalte und jeder vorhandene Datensatz den Wert eins. Dann wird der Mandant im Kontext gesetzt und die Filterung eingeschaltet, während es weiterhin nur einen gibt: Fehler zeigen sich jetzt als fehlende Daten, nicht als fremde. Dann folgt die Liste aus dem vorigen Abschnitt, Punkt für Punkt. Und erst danach wird ein zweiter Mandant angelegt, zunächst mit Testdaten.

Der Aufwand liegt für ein mittleres System bei sechs bis zehn Wochen, wobei die Datenbank der kleinere Teil ist. Und die eine Regel, die den Zustand danach hält, ist dieselbe wie bei jeder anderen Zusicherung: Sie muss geprüft werden, sonst ist sie nach drei Monaten eine Behauptung. Wie ich mandantenfähige Plattformen baue, steht auf einer eigenen Seite.

Dieser Artikel gehört zu einer Reihe über Systeme, die es schon gibt. Der Rückblick ordnet alle Artikel der Reihe nach Anlass.