Worum es geht
Ein neues CDMS-Projekt fängst du nicht mit einem leeren Ordner an. Der Hub gibt dir einen Projektrahmen (englisch Scaffold, „Baugerüst“): ein ZIP mit POM, Start-Klasse, Konfiguration und dem aktuellen Modell. Den entpackst du, baust einmal, und die Anwendung läuft.
Was genau im Rahmen steht, hängt von ein paar Einstellungen am System im Hub ab: Mit welcher Datenbank arbeitet es? Braucht es Anmeldung? Läuft CIAS mit im selben Prozess? Jede Einstellung ist ein Zweig, der Abhängigkeiten, Konfiguration und manchmal Klassen hinzufügt.
So kommst du zum Rahmen
-
1Entwickler→Huböffnet das System im Hub und klickt Projekt-Rahmen
-
2Hubliest die Einstellungen des Systems und das Modell
-
3Hub→Entwicklerliefert
<id>-project.zipDahinter stehtGET /api/rest/cms/system/{id}/scaffold. Du kannst den Rahmen also auch per Skript holen. -
4Entwicklerentpackt, trägt das Client-Secret in
cdms-generator.propertiesein, legt.envan -
5Build
mvn clean compile: holt die Metadaten, pflegt die POM, generiert den CodeErgebnis: Ein lauffähiges Projekt
Was im ZIP steht
katalog/
├── pom.xml ← Parent cdms-app-parent, Abhängigkeiten je Zweig
├── README.md ← Bauen, Starten, alle Umgebungsvariablen
├── cdms-generator.properties ← Zugang zum Hub für den Build (Secret leer)
├── .env.example ← Laufzeitvariablen: Datenbank, Mandantenmodus, CIAS …
├── .gitignore
├── .cache/ ← das Modell als YAML, damit der erste Build offline geht
│ ├── system.yaml
│ └── models.yaml …
└── src/
├── main/java/com/codamai/shop/katalog/
│ ├── Start.java ← Spring-Boot-Start-Klasse
│ └── config/ ← nur bei CIAS EMBEDDED: drei Verdrahtungsklassen
├── main/resources/application.yaml
└── test/java/…/TenantContextArchitectureTest.java ← nur mit Anmeldung (OIDC)
| Datei | wozu |
|---|---|
pom.xml | Parent ist cdms-app-parent. Er bringt den ganzen Build mit: Metadaten holen, Codegenerator, Spring-Boot-Paket, Native Image. Deine POM enthält nur Koordinaten, ein paar Properties und die Abhängigkeiten. |
Start.java | @SpringBootApplication für das Paket com.codamai. Ohne sie gäbe es keine Quelldatei, und ohne Quelldatei laufen keine Annotation-Processors, also auch kein Generator. |
application.yaml | deine Konfiguration. Datenbank, Mandantenmodus und Identity Provider stehen bewusst nicht hier, sondern kommen aus der Umgebung. |
.env.example | Vorlage für die Umgebungsvariablen. Immer dabei: CODAMAI_PERSISTENCE_TENANT_MODE=SINGLE und die Datenbankzugänge CODAMAI_PERSISTENCE_DATABASE_*. |
cdms-generator.properties | System-ID, Hub-Adresse, Keycloak-Adresse, Realm, Client-ID und cacheDir=.cache. Das clientSecret trägst du selbst ein. Die Datei steht in .gitignore. |
.cache/ | das Modell zum Zeitpunkt des Downloads, siehe Codegenerierung im Build |
Die Maven-Koordinaten leitet der Hub aus den Namen ab. Aus dem Projekt „Shop“ und dem System „Katalog“ wird groupId com.codamai.shop, artifactId katalog und das Basispaket com.codamai.shop.katalog.
Die Zweige
Die Einstellungen stehen am System im Hub. Der Build liest sie später aus .cache/system.yaml. Maven- oder Spring-Properties schalten die Zweige nicht.
flowchart TD
A{"authentication"} -- "NONE" --> N["keine Anmeldung<br/>CIAS ist immer NONE"]
A -- "OIDC" --> O["+ cias-authentication<br/>+ Architekturtest<br/>+ CIAS_ISSUER, CIAS_CLIENT …"]
O --> C{"cias"}
C -- "REMOTE" --> R["+ cias-tenancy-client<br/>CIAS läuft als eigener Service"]
C -- "EMBEDDED" --> E["+ cias-tenancy, cias-user,<br/>cias-authorization, cias-iam-keycloak<br/>+ Block codamai.cias<br/>+ 3 Klassen unter config/"]
C -- "NONE" --> X["kein CIAS-Mandantendienst"]
D{"database"} -- "MYSQL" --> D1["mysql-connector-j"]
D -- "MARIADB" --> D2["mariadb-java-client"]
S{"storage"} -- "FILESYSTEM" --> S1["+ cdms-localfs-storage<br/>+ basePath /files/"]
S -- "NONE" --> S0["keine Dateien"]
M{"monitoring"} -- "ACTUATOR" --> M1["+ Prometheus, AOP<br/>+ Metriken und Probes auf 8081"]
M -- "NONE" --> M0["nur Actuator-Grundausstattung<br/>auf 8081"]
U{"ein Modell auditiert?"} -- "ja" --> U1["+ hibernate-envers"]
Wann: authentication: OIDC oder NONE
OIDC: Die POM bekommt cias-authentication (prüft jedes Token) und für Tests cias-test-support. In .env.example stehen CIAS_ISSUER (der Issuer so, wie er im Token steht), CIAS_CLIENT und CIAS_CLIENT_SECRET, dazu auskommentiert CIAS_BACKCHANNEL_URL. Dazu kommt der Test TenantContextArchitectureTest. Er prüft, dass der Mandant nur aus dem Mandanten-Tor kommt. NONE: nichts davon. Ohne Anmeldung gibt es auch kein CIAS.
Ergebnis: Mit OIDC ist jede Anfrage angemeldet, siehe Token-Prüfung
Wann: cias: EMBEDDED (nur mit OIDC)
CIAS läuft im selben Prozess wie CDMS. Die POM bekommt cias-tenancy, cias-user, cias-authorization und cias-iam-keycloak. application.yaml bekommt einen Block codamai.cias (Mandantenverwaltung an, Mandanten werden lokal nachgeschlagen). Unter config/ liegen drei Klassen, die CIAS verdrahten: CiasEmbeddedConfiguration, CiasIdentityConfiguration, CiasRepositoryTransactionsPostProcessor. Benutzer- und Rechteverwaltung sind vorbereitet und schaltest du über CIAS_USER und CIAS_AUTHORIZATION ein.
Ergebnis: Eine Einheit, siehe Eingebettet
Wann: cias: REMOTE (nur mit OIDC, Standard)
CIAS läuft als eigener Service. Die POM bekommt nur cias-tenancy-client. Er fragt CIAS nach den Mandanten. In .env.example steht CODAMAI_CIAS_TENANCY_CLIENT_BASE_URL, die Adresse des CIAS-Service.
Ergebnis: Zwei Services, siehe Getrennt
Wann: cias: NONE
Kein CIAS-Baustein im Rahmen. Die Anwendung prüft Tokens, fragt aber keinen Mandantendienst.
Wann: database: MYSQL oder MARIADB
Die POM bekommt den passenden JDBC-Treiber. .env.example bekommt CODAMAI_PERSISTENCE_DATABASE_DRIVER und eine Beispiel-URL wie jdbc:mysql://localhost:3306/{tenant}. {tenant} ersetzt CDMS zur Laufzeit durch den Mandanten, siehe Welche Datenbank?
Wann: storage: FILESYSTEM oder NONE
FILESYSTEM: Die POM bekommt cdms-localfs-storage, application.yaml den Ablageort codamai.cdms.persistence.file.basePath (Standard /files/, per CODAMAI_CDMS_PERSISTENCE_FILE_BASE_PATH änderbar). NONE: kein Dateispeicher.
Ergebnis: Siehe Speicher-Backends
Wann: monitoring: ACTUATOR oder NONE
Den Spring-Boot-Actuator hat jede Anwendung, immer auf dem eigenen Management-Port 8081, der nicht nach außen geht. ACTUATOR legt nach: micrometer-registry-prometheus und spring-boot-starter-aop in der POM, in application.yaml die Endpunkte health, info, metrics, prometheus und Health-Probes für Kubernetes.
Wann: mindestens ein Modell ist auditiert
Dafür gibt es keinen Schalter. Sobald ein Modell im Hub auditiert ist, kommt hibernate-envers in die POM.
Ergebnis: Siehe Was auditiert wird
Ob die Anwendung einen oder viele Mandanten bedient, ist kein Zweig des Rahmens. Das entscheidet zur Laufzeit CODAMAI_PERSISTENCE_TENANT_MODE (SINGLE oder MULTI), siehe Single- oder Multi-Tenant.
Ein Beispiel
<parent>
<groupId>com.codamai.cdms</groupId>
<artifactId>cdms-app-parent</artifactId>
</parent>
<properties>
<cdms.main.class>com.codamai.shop.katalog.Start</cdms.main.class>
<cdms.generator.fetch.skip>false</cdms.generator.fetch.skip>
</properties>
<dependencies>
<!-- cdms-managed:dependencies:start -->
… Kern: cdms-rest-api, cdms-system-layer, cdms-database …
hibernate-envers ← Auditing
mysql-connector-j ← database: MYSQL
cdms-localfs-storage ← storage: FILESYSTEM
cias-authentication ← authentication: OIDC
micrometer-registry-prometheus ← monitoring: ACTUATOR
cias-tenancy-client ← cias: REMOTE
<!-- cdms-managed:dependencies:end -->
</dependencies>spring:
application: { name: katalog }
threads: { virtual: { enabled: true } }
codamai:
cdms:
api: { createReadMode: STRICT }
persistence: ← storage: FILESYSTEM
file:
basePath: ${CODAMAI_CDMS_PERSISTENCE_FILE_BASE_PATH:/files/}
management:
server: { port: 8081 }
endpoints: { web: { exposure: { include: health, info, metrics, prometheus } } } ← monitoring: ACTUATOREinmal erzeugt, danach deins
Was passiert mit den Dateien, wenn du später baust oder den Rahmen erneut herunterlädst?
| Datei | Was bei jedem Build passiert |
|---|---|
pom.xml: Parent, verwaltete Properties, Bereich zwischen den cdms-managed-Markern | wird nach dem Hub neu geschrieben |
pom.xml: Koordinaten, eigene Abhängigkeiten, Plugins, eigene Properties | bleibt erhalten |
Start.java, OpenApiConfiguration, NativeHintsConfiguration | legt der Generator an, wenn sie fehlen, sonst nie angefasst |
application.yaml, .env.example, CIAS-Klassen unter config/ | nie angefasst |
generierter Code in target/generated-sources/ | bei jedem Build neu |
Zwei Konsequenzen:
- Einen Zweig nachträglich ändern (etwa
storageaufFILESYSTEM) wirkt beim nächsten Build auf die POM: Die Abhängigkeit kommt hinzu, abgewählte fliegen raus. Die passende Konfiguration inapplication.yamlund.envträgst du selbst nach. Das README eines frischen Rahmens zeigt dir, was dort stehen muss. - Ein neuer Download ist ein neues ZIP. Es wird nichts mit deinem Projekt zusammengeführt. Nimm dir daraus, was du brauchst.
Die POM-Pflege schaltest du mit CODEGEN_POM_GENERATE=false ab.