Worum es geht
Wenn du im Hub ein Modell anlegst, wählst du als Erstes seinen Scope, also die Ebene, auf der seine Daten leben. Es gibt genau drei:
- gilt für die ganze Installation
- liegt immer in der System-Datenbank
- alle Mandanten sehen dieselben Daten
- Beispiel: Länderliste, Produktkatalog der Plattform
- gehört einem Kunden
- liegt in der Datenbank dieses Mandanten
- alle Personen des Mandanten sehen dieselben Daten (sofern ihre Rollen es erlauben)
- Beispiel: Kunden, Aufträge, Audits einer Firma
- gehört einer Person
- liegt ebenfalls in der Mandanten-Datenbank
- jede Person sieht nur ihre eigenen Zeilen
- Beispiel: persönliche Einstellungen, Notizen, Favoriten
Wo die Daten liegen
In der Betriebsart MULTI hat jeder Mandant eine eigene Datenbank. Die Benutzerebene ist keine eigene Datenbank, sondern eine Verfeinerung innerhalb der Mandanten-Datenbank:
flowchart LR
subgraph SYS["System-Datenbank"]
S1["System-Modelle<br/>z. B. Länderliste"]
end
subgraph TA["Datenbank Mandant A"]
A1["Mandanten-Modelle<br/>z. B. Kunden von A"]
A2["Benutzer-Modelle<br/>Zeilen von Anna | Zeilen von Ben"]
end
subgraph TB2["Datenbank Mandant B"]
B1["Mandanten-Modelle<br/>z. B. Kunden von B"]
B2["Benutzer-Modelle<br/>Zeilen von Clara"]
end
SYS ~~~ TA ~~~ TB2
Benutzer-Modelle haben ein zusätzliches Feld _userId. CDMS trägt dort beim Anlegen die ID der angemeldeten Person ein und filtert beim Lesen danach.
Welche Ebene wähle ich?
Zwei Fragen genügen:
flowchart LR
Q1{"Brauchen alle Kunden<br/>dieselben Daten?"}
Q1 -->|ja| SYS["System"]
Q1 -->|nein| Q2{"Gehören die Daten einer<br/>einzelnen Person, die sie<br/>als Einzige sehen darf?"}
Q2 -->|ja| USR["Benutzer"]
Q2 -->|nein| TEN["Mandant"]
Was bei einem Zugriff passiert
Die Ebene wirkt bei jedem Lesen und Schreiben an zwei Stellen: bei der Wahl der Datenbank und beim Filtern der Zeilen.
Wann: Das Modell hat den Scope „Systemweit“.
-
1Client→CDMSliest oder schreibt, mit oder ohne Mandant im Token
-
2CDMSerkennt am Modell: System-Ebene. Der Mandant wird gar nicht erst gelesen, auch ein
tenant-Header ändert nichts -
3CDMS→System DBgreift auf die System-Datenbank zu, ohne Zeilenfilter der Ebene
Ergebnis: Alle sehen dieselben Daten, soweit ihre Rollen es erlauben.
Wann: Das Modell hat den Scope „Mandant“ (oder keinen).
-
1Client→CDMSliest oder schreibt, der Mandant steht im Token
-
2CDMSGibt es einen Mandanten im Kontext? Darf diese Anfrage auf ihn zugreifen?Kein Mandant in
MULTI→ 400CDMS_TENANT_REQUIRED. Mandant nicht erlaubt → 403. -
3CDMS→Mandanten-DBgreift auf die Datenbank genau dieses Mandanten zu
Ergebnis: Jede Person des Mandanten sieht dieselben Daten, soweit ihre Rollen es erlauben. Andere Mandanten sehen nichts davon.
Wann: Das Modell hat den Scope „Benutzer“.
-
1Client→CDMSliest oder schreibt, Mandant und Person stehen im Token
-
2CDMSwählt die Mandanten-Datenbank, genau wie bei der Ebene Mandant
-
3CDMSbeim Anlegen: setzt
_userIdauf die ID der angemeldeten Person. Einen mitgeschickten Wert ignoriert CDMS -
4CDMSbeim Lesen, Suchen, Ändern, Löschen: hängt den Pflichtfilter
_userId = angemeldete Personan -
5CDMS→Mandanten-DBliefert oder ändert nur Zeilen dieser Person
Ergebnis: Jede Person sieht nur ihre eigenen Zeilen. Fremde Zeilen gibt es aus ihrer Sicht nicht: 404, nicht 403.
Welche Datenbank? Die vollständige Entscheidung
So entscheidet die Persistenz bei jedem einzelnen Zugriff. Die Reihenfolge ist wichtig: Die Frage „System-Modell?“ kommt vor allem anderen.
| System-Modell? | Betriebsart | Mandant im Kontext? | Mandant steht in allowedTenants? | Ziel |
|---|---|---|---|---|
| ja | – | – | – | System-Datenbank |
| nein | MULTI | ja | ja | Datenbank dieses Mandanten |
| nein | MULTI | ja | nein | 403 CDMS_TENANT_SWITCH_NOT_AUTHORIZED |
| nein | MULTI | nein | – | 400 CDMS_TENANT_REQUIRED |
| nein | SINGLE | – | – | die eine gemeinsame Datenbank |
„Erlaubt“ heißt: Der Mandant steht in der Liste allowedTenants aus dem Token. Fehlt die Liste, ist nichts erlaubt.
Die Tabelle zeigt die Sicht der Persistenz. Eine Anfrage ohne Mandant erreicht sie in MULTI meist gar nicht erst: Schon die Filterkette von CIAS lehnt sie mit 403 tenant-required ab. Die 400 ist die zweite Sicherung dahinter.
Einen Rückfall gibt es nicht: Fehlt der Mandant, landet ein Mandanten-Objekt nie stillschweigend in der System-Datenbank. Ob ein Mandant überhaupt bedient wird (aktiv, nicht gesperrt), hat vorher schon das Mandanten-Tor in CIAS entschieden.
SINGLE und MULTI
Die Ebenen gibt es in beiden Betriebsarten. Was sich ändert, ist nur die Datenhaltung:
| MULTI | SINGLE | |
|---|---|---|
| Datenbanken | eine System-DB + eine DB je Mandant | genau eine |
| System-Modelle | System-DB | die eine DB |
| Mandanten-Modelle | DB des Mandanten | die eine DB, ohne Trennung nach Kunden |
| Benutzer-Modelle | DB des Mandanten, gefiltert nach _userId | die eine DB, gefiltert nach _userId |
| Mandant im Token nötig? | ja, sonst 400 | nein |
Beziehungen zwischen den Ebenen
Eine Beziehung verbindet zwei Modelle, und beide müssen in derselben Datenbank erreichbar sein. Daraus folgt die Regel, die der Hub beim Modellieren durchsetzt:
| Ebene von A | Ebene von B | Beziehung |
|---|---|---|
| System | System | erlaubt – beide in der System-DB |
| Mandant | Mandant | erlaubt – beide in der Mandanten-DB |
| Mandant | Benutzer | erlaubt – beide in der Mandanten-DB |
| Benutzer | Mandant | erlaubt – beide in der Mandanten-DB |
| Mandant oder Benutzer | System | nicht erlaubt – Ziel liegt in einer anderen Datenbank |
| System | Mandant oder Benutzer | nicht erlaubt – Ziel liegt in einer anderen Datenbank |
Im Hub sind unzulässige Ziele im Auswahlfeld ausgegraut („Scope unzulässig“) und werden beim Speichern abgewiesen.
Wie die Ebene festgelegt wird
-
1Adminwählt im Hub beim Modell das Feld Scope: „Systemweit“, „Mandant“ oder „Benutzer“
-
2CDMSspeichert es als
modelType=SYSTEM,TENANToderUSER. Fehlt der Wert, giltTENANT -
3CDMSDer Generator leitet die Entity von der passenden Basisklasse ab:
AbstractSystemModel,AbstractTenantModeloderAbstractUserModelEin Untertyp eines abstrakten Modells erbt die Basisklasse seines Obermodells und damit dessen Ebene. -
4CDMSBeim Start prüft CDMS, dass jede Entity in der richtigen Gruppe steht. Passt etwas nicht, startet die Anwendung nicht
Zwei Sicherungen gegen Verwechslung
Dass ein Objekt in der falschen Datenbank landet, verhindern zwei voneinander unabhängige Mechanismen:
-
CDMSRoutingWählt die Datenbank anhand der Basisklasse. System-Modelle ignorieren den Mandanten vollständig.↳ nein 400 / 403, nie Rückfall auf die System-DB
-
CDMSTypmengenJede Datenbankverbindung kennt nur die Modelle ihrer Ebene. Die System-DB kennt keine Mandanten-Modelle und umgekehrt.↳ nein ein falsch geroutetes Objekt scheitert an Hibernate, statt falsch gespeichert zu werden
-
CDMSStartprüfungPassen Routing und Typmengen zusammen?↳ nein Anwendung startet nicht
- Objekt liegt in der Datenbank seiner Ebene
Was sonst noch an der Ebene hängt
| Thema | System | Mandant | Benutzer |
|---|---|---|---|
| Singleton | ein Objekt für die ganze Installation | ein Objekt je Mandant | ein Objekt je Person |
| Dateien | Ablagepfad ohne Mandant | Pfad mit Mandant | Pfad mit Mandant |
| Historie | Revisionsprotokoll der System-DB | Revisionsprotokoll der Mandanten-DB | Revisionsprotokoll der Mandanten-DB |
| Zeilenfilter | keiner durch die Ebene | keiner durch die Ebene, der Mandant wirkt über die Datenbank | _userId = angemeldete Person |
Rollen, Attributfilter und eigene Filter wirken zusätzlich auf jeder Ebene.