SaaS-Plattformentwicklung
Mandantenfähige SaaS-Entwicklung mit Laravel
Die Isolationsentscheidung fällt einmal und entscheidet alles danach - was ein lauter Kunde seine Nachbarn kostet, und ob die Sicherheitsprüfung eines Großkunden das Gespräch beendet.
Jedes mandantenfähige Produkt trifft früh eine Entscheidung, die es kaum rückgängig machen kann: wo die Wand zwischen Kunden steht. Alles andere – was ein Ausfall kostet, wie lange eine Wiederherstellung dauert, ob die Sicherheitsprüfung eines Großkunden gut ausgeht – folgt daraus.
Die Entscheidung fällt meist implizit, durch denjenigen, der die erste Spalte
company_id hinzufügt, und wird zwei Jahre später entdeckt, wenn sie anfängt
wehzutun.
Die drei Modelle, und für wen sie passen
Ein Schema, eine Mandantenspalte auf jeder Tabelle. Am billigsten zu bauen und zu betreiben. Eine Datenbank, eine Migration, ein Verbindungspool. Passt zu Produkten mit vielen kleinen Konten und ohne einen Kunden, der groß genug ist, etwas anderes zu verlangen.
Die Schwäche ist, dass Isolation eine Eigenschaft Ihres Codes ist statt der Infrastruktur. Ein fehlender Filter ist eine Datenpanne, eine Wiederherstellung für einen Kunden heißt, seine Zeilen aus dem Backup aller zu ziehen, und die schwere Abfrage eines lauten Mandanten spüren alle.
Eine Datenbank pro Mandant. Isolation, auf die man in einer Sicherheitsprüfung zeigen kann. Sicherung und Wiederherstellung sind pro Kunde, eine Löschanfrage ist eine gelöschte Datenbank, und Anforderungen an den Datenstandort sind pro Konto erfüllbar.
Der Preis ist betrieblich und real: Migrationen laufen N-mal und können beim vierundneunzigsten scheitern, Verbindungen vervielfachen sich, und „wie viele Mandanten haben wir" wird zu einer Frage über Infrastruktur statt zu einer Zählung.
Beides, nach Stufe. Standardmäßig geteilt, dediziert für Kunden, die dafür zahlen. Das ist es, was die meisten erfolgreichen Produkte am Ende betreiben, und früh dafür zu bauen kostet wenig, wenn die Mandantengrenze explizit ist – die Anwendung fragt nach einer Verbindung, statt eine anzunehmen.
Was wir in jedem Fall bauen
Einen Mandanten, einmal am Rand aufgelöst. Aus der Domain, der Subdomain oder dem angemeldeten Nutzer – an einer Stelle, früh in der Anfrage, damit nichts weiter unten es noch einmal herausfinden muss. Jobs führen ihn explizit mit, denn ein Queue-Job hat keine Anfrage, aus der er ihn lesen könnte, und hier entstehen mandantenübergreifende Fehler tatsächlich.
Isolation durch das Modell durchgesetzt, nicht durch Disziplin. Ein
globaler Scope bedeutet, dass eine vergessene where-Bedingung nichts
zurückgibt statt alles. Zusammen mit einer mandantenbewussten Factory und
Tests, die zusichern dass der Datensatz eines anderen Mandanten unsichtbar ist,
überlebt die Zusicherung auch den Entwickler, der nächstes Jahr dazukommt.
Queues, die einander nicht aushungern können. Ein Kunde, der zwei Millionen Zeilen importiert, darf nicht das Zurücksetzen der Passwörter aller anderen verzögern. Das ist Queue- und Worker-Aufbau – behandelt im Queue-Engineering – und es ist die häufigste Beschwerde, zu der wir bei SaaS-Plattformen gerufen werden, die über ihre ersten paar hundert Konten hinauswachsen.
Caches und Speicher nach Mandant geschlüsselt. Cache-Schlüssel, hochgeladene Dateien und erzeugte Dokumente brauchen die Grenze ebenfalls. Ein Cache-Schlüssel, der den Mandanten weglässt, ist das schnellstmögliche Datenleck und das am schwersten zu bemerkende.
Onboarding und Offboarding als Code. Einen Mandanten anzulegen – Schema, Startdaten, Domain, Abrechnung – sollte eine Operation sein und kein Handbuch. Ihn zu entfernen ebenso, einschließlich dessen, was der Vertrag über Aufbewahrung sagt.
Abrechnung, wo das Schema leckt
Abonnementabrechnung sieht aus wie eine Integration und verhält sich wie ein Modellierungsproblem. Tarife ändern sich, Kunden stufen mitten in der Periode hoch, Testphasen verlängern sich, eine Zahlung scheitert drei Tage nachdem die Funktion genutzt wurde.
Zwei Entscheidungen ersparen den meisten Schmerz. Berechtigungen sind ein eigenes Konzept, statt vom Zahlungsdienstleister abgelesen zu werden – die Anwendung fragt, ob dieser Mandant dies tun darf, und nicht wie sein Abrechnungsstatus lautet. Und die Abrechnungshistorie ist unveränderlich: Ein Upgrade schreibt einen neuen Datensatz statt den alten zu ändern, denn die Rechnung, die Sie im März ausgestellt haben, muss weiterhin sagen, was sie gesagt hat.
Wo das hingehört
Das ist Anwendungsentwicklung mit bewusst getroffenen Mandantenentscheidungen. Wenn eine Plattform bereits existiert und die Schwierigkeit darin besteht, dass die Last eines Kunden das Problem aller ist, dann ist das Performance und Skalierung – und wenn die Schwierigkeit darin besteht, dass niemand sicher ist, ob die Isolation tatsächlich hält, beantwortet das Audit genau das, mit den Abfragen, die es in die eine oder andere Richtung beweisen.
Wie ein Projekt abläuft
Es beginnt mit einer Frage, die auf Papier beantwortet wird: welches der drei Mandantenmodelle dieses Produkt braucht und was ein Vertrag mit Ihrem größten künftigen Kunden voraussichtlich verlangen wird.
Der Leistungsumfang, der folgt, legt das Modell fest, die Isolationszusagen, das Abrechnungsverhalten und die Phasen, mit einem Preis. Er wird unterschrieben, bevor irgendetwas davon gebaut wird, denn Mandantenfähigkeit ist die eine Entscheidung auf dieser Seite, die sich später nicht ohne ein eigenes Migrationsprojekt ändern lässt.
Dann der Bau, in Phasen, die jeweils deployt enden, mit den Isolationstests parallel zu den Features.
Was Sie bekommen
Das Mandantenmodell wird aufgeschrieben, bevor irgendetwas gebaut wird, dann die Anwendung mit Isolation, die in der Datenschicht durchgesetzt wird, und eine Testsuite, deren Negativfälle der Punkt sind. Ein Mandant, der die Zeilen eines anderen nicht lesen kann, geprüft statt angenommen.
Dazu die Abrechnungsabstimmung, der Migrationspfad zwischen den drei Modellen für den Fall, dass Sie das falsche gewählt haben, und eine schriftliche Antwort auf die Frage, die jeder Enterprise-Einkauf irgendwann stellt: wo die Daten liegen und wer an sie herankommt.
