Worum es geht
Einen Mandanten anlegen heißt zweierlei: einen Datensatz in CIAS schreiben und die Datenbank des Mandanten einrichten. Das eine liegt in der Datenbank von CIAS, das andere in der Persistenz von CDMS. Eine gemeinsame Transaktion über beide gibt es nicht. Das zweite kann also scheitern, nachdem das erste gelungen ist.
CIAS löst das, indem es jeden Schritt einzeln festhält. Scheitert etwas, bleibt ein Mandant zurück, der erkennbar kaputt ist und repariert werden kann, statt einer, der als angelegt gilt und nichts bedient.
Wer anlegen darf
Es gibt drei Wege, und alle enden in derselben Methode von CIAS:
| Weg | Wer | Prüfung |
|---|---|---|
Verwaltungs-API POST /cias/admin/tenants | ein Plattform-Administrator | Die Rolle wird bei jedem Aufruf geprüft, auch beim Lesen. Ein Mandanten-Administrator darf keine Mandanten anlegen |
| Selbstregistrierung einer Firma | niemand ist angemeldet | Die Registrierung ruft die Methode ohne Rollenprüfung auf. Diese Variante hat keinen HTTP-Endpunkt |
| Erster Mandant beim Start | die Installation selbst | Steht ein Mandant in der Bootstrap-Konfiguration und gibt es ihn noch nicht, legt CIAS ihn beim Start an |
Warum ein Mandanten-Administrator nicht darf: Mandanten anlegen, sperren oder schließen ist genau das, was Kunden voneinander trennt. Dürfte ein Kunde das, könnte er die anderen erreichen.
Der Ablauf
sequenceDiagram
participant A as Admin
participant C as CIAS
participant DB as CIAS-Datenbank
participant P as Persistenz (CDMS)
A->>C: POST /cias/admin/tenants {key: nordbau, type: DYNAMIC}
C->>DB: Transaktion 1: Schlüssel frei? speichern als PENDING / IN_PROGRESS
C->>P: einrichten (außerhalb jeder Transaktion)
P->>P: Datenbank nordbau anlegen, Schema migrieren
P-->>C: fertig
C->>DB: Transaktion 2: PROVISIONED, ACTIVE
C-->>A: 200 mit dem Mandanten
Drei Gründe für diese Form:
- Absicht zuerst speichern. Stürzt der Prozess danach ab, ist wenigstens etwas da, das man wiedererkennt: ein Mandant in
IN_PROGRESSmit Startzeit. - Einrichten ohne offene Transaktion. Eine Datenbank anzulegen und zu migrieren kann dauern. Liefe das in einer Transaktion, hielte CIAS so lange eine Datenbankverbindung und ihre Sperren fest.
- Ergebnis danach speichern, Erfolg wie Misserfolg, jeweils in einer eigenen kurzen Transaktion.
Was „einrichten“ heißt
Was bei der Einrichtung passiert, hängt davon ab, was im selben Prozess läuft:
Wann: CDMS-Persistenz im selben Prozess, CODAMAI_PERSISTENCE_TENANT_MODE=MULTI
-
1CIAS→CDMSbittet um Einrichtung von
nordbau -
2CDMS→Mandanten-DBfehlt die Datenbank und ist Anlegen freigegeben →
CREATE DATABASE nordbau -
3CDMS→Mandanten-DBmigriert das Schema auf den Stand der Modelle
Ergebnis: Die Datenbank ist fertig, bevor der erste Kunde kommt. Scheitert etwas, merkt es der Betrieb beim Anlegen und nicht der Kunde bei seiner ersten Anfrage.
Wann: CODAMAI_PERSISTENCE_TENANT_MODE=SINGLE
Es gibt nur die eine Datenbank. Die Einrichtung hat nichts zu tun und meldet sofort Erfolg.
Ergebnis: Der Mandant ist sofort ACTIVE. In SINGLE spielt er für Anfragen allerdings keine Rolle, siehe In SINGLE zählt der Mandant im Token nicht.
Wann: CIAS läuft als eigener Dienst, ohne CDMS-Persistenz im Prozess.
CIAS hat keine Datenbanken der Mandanten, also richtet es nichts ein und meldet sofort Erfolg. Beim Start steht einmal im Log, dass diese Installation nichts bereitstellt. Die Datenbank legt CDMS bei der ersten Anfrage für den Mandanten selbst an, sofern Anlegen dort freigegeben ist.
Ergebnis: Der Mandant ist sofort ACTIVE. Die erste Anfrage des Kunden dauert länger. Siehe Datenbanken, Pools, Migration.
Die Einrichtung darf beliebig oft laufen: Eine vorhandene Datenbank wird nicht noch einmal angelegt, und die Migration spielt nur fehlende Änderungen ein. Ein zweiter Versuch nach einem halben Fehlschlag wiederholt also Arbeit, statt etwas doppelt anzulegen.
Was dabei schiefgehen kann
Wann: Es gibt schon einen Mandanten mit diesem Schlüssel, in welchem Zustand auch immer.
CIAS legt nichts an.
Ergebnis: 409 cias.tenancy.key-already-used
Wann: Der Schlüssel verletzt die Regeln, oder type fehlt.
CIAS legt nichts an. Die Meldung beschreibt die eigene Eingabe, etwa welche Zeichen erlaubt sind.
Ergebnis: 400 cias.tenancy.invalid-request, siehe Der Mandantenschlüssel
Wann: Die Datenbank lässt sich nicht anlegen oder migrieren.
-
1CIAS→CDMSeinrichten → Fehler
-
2CIASspeichert den Mandanten als
FAILED, Stellung bleibtPENDING, EventProvisioningFailed -
3CIAS→Admin502
cias.tenancy.provisioning-failed: angelegt, aber nicht eingerichtet
Ergebnis: Der Mandant existiert und wird nicht bedient. Denselben Aufruf noch einmal zu schicken hilft nicht, der Schlüssel ist jetzt vergeben. Richtig ist der Neuversuch.
Wann: POST /cias/admin/tenants/{id}/retry-provisioning für einen Mandanten in FAILED
-
1CIASsetzt den Rollout wieder auf
IN_PROGRESS, mit neuer Startzeit -
2CIAS→CDMSrichtet erneut ein
-
3CIASgelingt es →
PROVISIONED, undACTIVE, wenn die Stellung nochPENDINGist
Ergebnis: Ist der Rollout nicht FAILED oder der Mandant geschlossen, lehnt CIAS ab, bevor etwas eingerichtet wird: 409 cias.tenancy.illegal-transition.retry-provisioning. Einen inzwischen gesperrten Mandanten richtet der Neuversuch ein, lässt ihn aber gesperrt, siehe Der Lebenslauf eines Mandanten.
Wann: Der Prozess stirbt zwischen den beiden Transaktionen. Der Mandant bleibt in IN_PROGRESS, und der Neuversuch nimmt nur FAILED an.
-
1CIASAbgleich läuft alle 15 Minuten: Welche Rollouts sind seit mehr als 30 Minuten
IN_PROGRESS? -
2CIASliest jeden Treffer neu, prüft noch einmal und setzt ihn auf
FAILED, EventProvisioningFailedmit dem Vermerk „aufgegeben“
Ergebnis: Danach geht der normale Neuversuch. Der Abgleich ist abschaltbar, beide Zeiten sind einstellbar.
Der Abgleich ist ein Zeitgeber, der liegengebliebene Rollouts findet. Eingestellt wird er über codamai.cias.tenancy.reconciliation.enabled, .interval (Standard 15 Minuten) und .deadline (Standard 30 Minuten). Im eigenständigen CIAS ist er eingeschaltet.
Die Frist ist mit Absicht großzügig. Wäre sie kürzer als die längste echte Einrichtung, würde der Abgleich einen noch laufenden Rollout aufgeben. Dieser Rollout könnte dann seinen Erfolg nicht mehr eintragen, denn CIAS nimmt „fertig“ nur für einen Rollout in IN_PROGRESS an. Zurück bliebe eine fertige Datenbank hinter einem Mandanten in FAILED. Das behebt ein Neuversuch, aber es ist unnötige Arbeit.
Was bei einem dynamischen Mandanten mit der Organisation passiert
| Weg | Organisation in Keycloak |
|---|---|
Selbstregistrierung (CREATE_NEW) | Die Registrierung legt zuerst die Organisation an, Alias = Schlüssel, und dann den Mandanten mit deren ID. Danach wird die Person Mitglied |
| Verwaltungs-API | CIAS legt keine Organisation an. Das Feld externalOrganizationId nennt eine Organisation, die es in Keycloak schon gibt. Ein dynamischer Mandant ohne dieses Feld wird trotzdem angenommen |
| Erster Mandant beim Start | wie bei der Verwaltungs-API, aus der Konfiguration |
Einen Mandanten zu speichern und später mit seiner Organisation zu verbinden, ist so möglich. Ob ein Token den Mandanten nennt, hängt am Alias der Organisation, nicht an diesem Feld, siehe Den Mandanten einer Anfrage bestimmen.
Anfrage und Antwort
POST /cias/admin/tenants
Authorization: Bearer <Token eines Plattform-Administrators>
{
"key": "nordbau",
"type": "DYNAMIC",
"displayName": "Nordbau GmbH",
"externalOrganizationId": "b7e0…"
}HTTP 200
{
"id": "0f6c…",
"key": "nordbau",
"displayName": "Nordbau GmbH",
"type": "DYNAMIC",
"status": "ACTIVE",
"provisioningState": "PROVISIONED",
"externalOrganizationId": "b7e0…",
"validFrom": null,
"validUntil": null,
"createdAt": "2026-09-22T09:14:03.120Z",
"updatedAt": "2026-09-22T09:14:04.480Z"
}displayName darf fehlen, dann steht dort der Schlüssel. Ein Gültigkeitsfenster gehört nicht zum Anlegen, es wird danach gesetzt, siehe Mandanten sperren, schließen, Gültigkeit.
Fallen
Weiter
- Der Mandantenschlüssel
- Der Lebenslauf eines Mandanten
- Wie die Registrierung einen Mandanten gründet: Woher der Mandant kommt
- Beide Module zusammen: Ein neuer Mandant, Ende zu Ende