Anwendung bauen und betreiben
Kurzantwort: Ihr Projekt ist ein gewöhnliches Maven-Projekt. Beim Build holt ein Plugin die Modellbeschreibung aus dem Hub, danach erzeugt der CDMS-Generator als Annotation-Processor den Code — Ergebnis ist ein ausführbares Spring-Boot-Artefakt. Zur Laufzeit brauchen Sie eine Datenbank, ein Verzeichnis für Dateien und einen OIDC-Anbieter.
Voraussetzungen
Abschnitt betitelt „Voraussetzungen“| JDK | 24 (für den nativen Build: GraalVM Community 24) |
| Maven | 3.9+ |
| Datenbank | MySQL 8 produktiv, H2 für Tests |
| Identitätsanbieter | Keycloak oder ein anderer OIDC-Anbieter |
| Zugang zur Artefakt-Registry | Zugangsdaten für die CDMS-Bibliotheken, in ~/.m2/settings.xml |
| Generator-Zugang | Client-ID, Secret und die UUID Ihres CDMS-Systems |
Zugangsdaten und Registry-URL erhalten Sie vom Betreiber Ihres Hubs. Die
UUID Ihres Systems finden Sie in der Modellierungsoberfläche oder über
cdms_list_targets im MCP-Server.
Der Build in zwei Schritten
Abschnitt betitelt „Der Build in zwei Schritten“flowchart TB
subgraph "mvn generate-sources"
F["Metadaten holen"] -->|Client-Credentials| K[(Identitätsanbieter)]
F -->|Modelle, Felder, Endpunkte| API[(CDMS-Hub)]
F --> Y["Modell-Cache<br/>models · folders · enumerations · system"]
end
subgraph "mvn compile"
L[Lombok] --> MS[MapStruct] --> G[CDMS-Generator]
Y --> G
G --> GEN["target/generated-sources/annotations<br/>~20 Klassen je Modell"]
end
GEN --> PKG["mvn package<br/>ausführbares JAR"]
PKG -.->|"Profil native"| BIN["natives Binary"]
Projekt einrichten
Abschnitt betitelt „Projekt einrichten“1. Registry-Zugang
Abschnitt betitelt „1. Registry-Zugang“Die CDMS-Bibliotheken liegen in einer Maven-Registry. Tragen Sie die
Zugangsdaten in ~/.m2/settings.xml ein — die Server-IDs nennt Ihnen der
Betreiber zusammen mit der Repository-URL.
2. Metadaten-Abruf einbinden
Abschnitt betitelt „2. Metadaten-Abruf einbinden“<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.4.1</version> <dependencies> <dependency> <groupId>com.codamai.cdms</groupId> <artifactId>cdms-generator</artifactId> <version>${cdms.version}</version> </dependency> </dependencies> <executions> <execution> <id>fetch-cdms-metadata</id> <phase>generate-sources</phase> <goals><goal>java</goal></goals> </execution> </executions> <configuration> <mainClass>com.codamai.cdms.remote.CdmsMetadataFetcher</mainClass> <includePluginDependencies>true</includePluginDependencies> <skip>${cdms.generator.fetch.skip}</skip> </configuration></plugin>includePluginDependencies ist nötig, damit das Generator-JAR im Classloader
des Plugins landet. Über cdms.generator.fetch.skip schalten Sie den Abruf ab
und arbeiten auf dem vorhandenen Cache.
3. Annotation-Processors einbinden
Abschnitt betitelt „3. Annotation-Processors einbinden“Die Reihenfolge ist verbindlich: Lombok → MapStruct → CDMS-Generator. Lombok erzeugt die Accessoren, auf die MapStruct aufsetzt; der Generator kommt zuletzt.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>24</source> <target>24</target> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </path> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${mapstruct.version}</version> </path> <path> <groupId>com.codamai.cdms</groupId> <artifactId>cdms-generator</artifactId> <version>${cdms.version}</version> </path> </annotationProcessorPaths> <compilerArgs> <arg>-parameters</arg> <arg>-Acdms.generator.cacheDir=${project.build.directory}/cache</arg> <arg>-Acdms.generator.basePackage=com.example.meineapp</arg> </compilerArgs> </configuration></plugin>-parameters behält die Parameternamen im Bytecode — Spring MVC und MapStruct
brauchen sie.
4. Generator-Zugang hinterlegen
Abschnitt betitelt „4. Generator-Zugang hinterlegen“Werte kommen aus Umgebungsvariablen, JVM-Properties oder einer lokalen
cdms-generator.properties. Details unter
Generierung.
cdms.generator.keycloakUrl=https://<ihr-idp>cdms.generator.keycloakRealm=<realm>cdms.generator.clientId=<client-id>cdms.generator.clientSecret=<secret>cdms.generator.cdmsUrl=https://<ihr-hub>cdms.generator.systemId=<uuid-ihres-systems>cdms.generator.cacheDir=target/cacheDas Secret gehört nicht ins Repository. Nehmen Sie die Datei in
.gitignoreauf und setzen Sie die Werte in der CI aus geschützten Variablen.
# vollständiger Build inklusive Testsmvn clean package
# ohne erneuten Modell-Abruf, auf dem vorhandenen Cachemvn clean package -Dcdms.generator.fetch.skip=true
# nur generieren und kompilierenmvn clean compile
# natives Binary (benötigt GraalVM 24)mvn clean package -Pnative -DskipTestsNach einer Modelländerung im Hub den Abruf einmal mit
-Dcdms.generator.fetch.skip=false laufen lassen, sonst baut Maven weiter
gegen den alten Cache.
Offline arbeiten geht mit CODEGEN_OFFLINE=true, sofern die vier
Cache-Dateien vorliegen. Fehlt eine, bricht der Build mit einer klaren Meldung
ab.
Was Sie danach haben
Abschnitt betitelt „Was Sie danach haben“| Ort | Inhalt |
|---|---|
target/generated-sources/annotations/ | Entities, DTOs, Payloads, Mapper, APIs, Service- und Persistenzschicht |
src/main/java/ | einmalig erzeugtes Gerüst (Hauptklasse, OpenAPI, Native Hints) plus Ihr Code |
target/*.jar | ausführbares Spring-Boot-Artefakt |
target/<name> | natives Binary, wenn mit -Pnative gebaut |
Generierten Code niemals von Hand ändern — er wird bei jedem Build neu erzeugt. Fachlogik kommt über Hooks.
Betreiben
Abschnitt betitelt „Betreiben“Konfiguration
Abschnitt betitelt „Konfiguration“Datenbank, Betriebsart, Dateiablage und Identitätsanbieter werden über Spring-Properties bzw. Umgebungsvariablen gesetzt. Die vollständige Liste steht unter Konfiguration; das Minimum:
cdms: database: mode: MULTI # oder SINGLE ohne Mandantentrennung driver: com.mysql.cj.jdbc.Driver url: jdbc:mysql://db:3306/{tenant} user: ${DB_USER} password: ${DB_PASSWORD}codamai: cdms: persistence: file: basePath: /files/Der Platzhalter {tenant} wird pro Mandant ersetzt — siehe
Mandantentrennung.
Ports und Health-Checks
Abschnitt betitelt „Ports und Health-Checks“| Zweck | Wert |
|---|---|
| Anwendung | 8080 |
| Management | 8081 |
| Liveness | GET :8081/actuator/health/liveness |
| REST-API | /api/rest/** |
Die Health-Indikatoren für Persistenz und Dateiablage sind aktiv, sobald Actuator im Projekt liegt — siehe Observability.
Datenbank-Schema
Abschnitt betitelt „Datenbank-Schema“| Modus | Verhalten |
|---|---|
HIBERNATE (Standard) | Hibernate passt das Schema selbst an (hbm2ddl.auto=update) |
FLYWAY | versionierte Migrationen pro Ziel: db/migration/system und db/migration/tenant, danach nur noch Validierung |
Für produktive Installationen ist FLYWAY die belastbarere Wahl: Änderungen
sind nachvollziehbar und wiederholbar. Eine neue Mandantendatenbank wird beim
ersten Zugriff angelegt (sofern freigegeben) und anschließend migriert.
flyway-core ist optional und nur für diesen Modus nötig.
Container
Abschnitt betitelt „Container“# JVM-VarianteFROM eclipse-temurin:24-jreWORKDIR /appCOPY target/meineapp.jar app.jarEXPOSE 8080 8081VOLUME /filesENTRYPOINT ["java", "-jar", "app.jar"]# Native Variante — kleiner und schneller am StartFROM debian:bookworm-slimRUN apt-get update && apt-get install -y --no-install-recommends curl \ && rm -rf /var/lib/apt/lists/*WORKDIR /appCOPY target/meineapp .RUN useradd -r -u 1001 appuser && chown -R appuser /appUSER appuserEXPOSE 8080 8081VOLUME /filesHEALTHCHECK CMD curl -fsS http://127.0.0.1:8081/actuator/health/liveness || exit 1ENTRYPOINT ["./meineapp"]Das Volume unter dem konfigurierten basePath ist Pflicht, sobald Sie
Datei-Modelle nutzen: Ohne persistentes Volume sind die Inhalte nach einem
Neustart verloren, während die Metadaten in der Datenbank bleiben.
Ressourcen
Abschnitt betitelt „Ressourcen“- Native Image senkt Startzeit und Speicherbedarf deutlich (Erfahrungswert: rund 400 MB auf unter 200 MB) — dafür dauert der Build länger und Reflexion muss registriert sein, siehe Native Image.
- Verbindungspool:
cdms.database.pool-sizegilt pro Mandant. Bei vielen Mandanten ist das die Stellschraube, die zuerst knapp wird. - Parallelität bei abstrakten Abfragen:
cdms_hub_query_parallelismmuss zur Poolgröße passen; jeder Worker belegt ein bis zwei Verbindungen. - Dateigrößen: Downloads werden vollständig in den Speicher gelesen. Der Heap-Bedarf wächst mit Dateigröße mal gleichzeitiger Downloads.
mvn test # Unit- und Integrationstests gegen H2mvn verify # inklusive nachgelagerter PhasenWas sich zu testen lohnt: Create, Update, Patch, Read, Suche, Response Requests, Validierung, Beziehungen, Mandanten-Isolation, Rechte, Datei-Handling und Auditing.
Hinweise zu H2: Tests isolieren, die Datenbank vor jedem Test in
FK-verträglicher Reihenfolge leeren, Transaktionsgrenzen prüfen, nicht unnötig
parallelisieren und @DirtiesContext nur gezielt einsetzen.
Fehlersuche
Abschnitt betitelt „Fehlersuche“| Symptom | Ursache und Abhilfe |
|---|---|
Maven findet die cdms-*-Artefakte nicht | Registry-Zugang fehlt — Zugangsdaten in ~/.m2/settings.xml, Erreichbarkeit prüfen |
| Metadaten-Abruf schlägt fehl oder hängt | Zugangsdaten und URLs prüfen; ersatzweise -Dcdms.generator.fetch.skip=true mit vorhandenem Cache |
Build bricht mit UnsupportedClassVersionError ab | Es läuft ein JDK < 24 — auch die IDE muss auf 24 laufen, wenn sie den Abruf im eigenen Prozess ausführt |
| Generierte Klassen fehlen | Reihenfolge der Annotation-Processors prüfen (Lombok → MapStruct → Generator) |
| Reflexionsfehler nur im nativen Image | Native Hints ergänzen, siehe Native Image |
| Beziehungen werden nicht persistiert | Besitzende Seite beachten, siehe Beziehungen |
| Objekte ohne Beziehung fehlen im Suchergebnis | impliziter Inner Join — Pfadausdrücke prüfen, siehe Suche und Filter |
CDMS_TENANT_REQUIRED im Betrieb | Mandantenobjekt ohne effektiven Mandanten, siehe Mandantentrennung |