Finale Gesamtdokumentation - Codex Enterprise Maven V2 Real Systems Lab

Dokumentationsindex - Codex Enterprise Maven V2 Real Systems Lab

Diese finale Dokumentation ist als Arbeits- und Lernhandbuch gedacht. Sie erklärt nicht nur, welche Dateien vorhanden sind, sondern auch, warum die Bausteine existieren, wie sie zusammenspielen, welche Entscheidungen dahinterstehen und wie man das System betreibt.

Systemüberblick

Entwicklerhandbuch

Betriebshandbuch

Lokaler Start und Troubleshooting

Architekturentscheidungen

Security-Handbuch

Observability-Handbuch

Resilience-Handbuch

Datenbankbetrieb-Handbuch

CI/CD- und Deployment-Handbuch

Teststrategie-Handbuch

Fehlerkatalog und Runbooks

Glossar

Dateien- und Ordnerkarte

Lernplan für das Projekt

← Zurueck zum Index

Empfohlene Lesereihenfolge
  1. 01-systemueberblick.md - große fachliche und technische Sicht.
  2. 02-entwicklerhandbuch.md - wie man im Code arbeitet.
  3. 03-betriebshandbuch.md - wie man das System lokal und produktionsnah betreibt.
  4. 04-lokaler-start-und-troubleshooting.md - Start, Checks und typische Fehler.
  5. 05-architekturentscheidungen.md - wichtige Entscheidungen und Alternativen.
  6. 06-security-handbuch.md - Keycloak, Rollen, JWT und API-Schutz.
  7. 07-observability-handbuch.md - Metriken, Health, Prometheus, Grafana.
  8. 08-resilience-handbuch.md - Retry, Timeout, Circuit Breaker, Rate Limiting.
  9. 09-datenbankbetrieb-handbuch.md - Migration, Backup, Restore, Retention.
  10. 10-cicd-deployment-handbuch.md - CI/CD, Quality Gates, Docker, Kubernetes, OpenShift.
  11. 11-teststrategie-handbuch.md - Testpyramide und Testcontainers.
  12. 12-fehlerkatalog-und-runbooks.md - konkrete Fehlerfälle und Reaktion.
  13. 13-glossar.md - zentrale Begriffe.
  14. 14-dateien-und-ordnerkarte.md - wo liegt was?
  15. 15-lernplan.md - wie man das Projekt als Lernpfad nutzt.
Wichtige Einstiegspunkte
DateiZweck
index.htmlSchöne Startseite mit Links auf alle wichtigen Artefakte
OPEN_THIS_V2_REAL_SYSTEMS.htmlidentischer Schnellstart für lokales Öffnen
README.mdkompakter Projektüberblick
START-HIER.mdpraktische Startanleitung
lehrbuch/codex-enterprise-maven-v2-real-systems-doku-final.pdffinale Dokumentation als PDF
DOKUMENTATION-GESAMT.htmlfinale HTML-Gesamtdokumentation
Dokumentationsprinzip

Die Dokumentation folgt drei Ebenen:

  • Lern-Ebene: Begriffe, Architektur und Entscheidungen verstehen.
  • Praxis-Ebene: Container starten, REST Flow testen, Metriken ansehen.
  • Betriebs-Ebene: Fehler erkennen, Runbooks nutzen, Security und Backup verstehen.

---

Zielbild

Das Projekt simuliert eine realistische Enterprise-Plattform rund um Order, Billing, Security, Messaging, Observability und Betrieb. Es ist bewusst nicht als Mini-Beispiel gedacht, sondern als kompaktes Labor, in dem typische Enterprise-Schnittstellen und Betriebsfragen sichtbar werden.

<img src="diagrams/system-landscape.svg" alt="Systemlandschaft">
Systemlandschaft

Fachlicher Kern

Der fachliche Kern ist ein Order Acceptance Flow:

  1. Ein Client ruft einen REST-Endpunkt auf.
  2. Die Runtime prüft über Spring Security, ob der JWT die richtige Rolle enthält.
  3. Der Application Service erstellt oder akzeptiert eine Bestellung.
  4. Der Payment Gateway Adapter ruft einen Mock Payment Provider auf.
  5. Die Bestellung wird in PostgreSQL gespeichert.
  6. Gleichzeitig wird ein Outbox Event geschrieben.
  7. Ein Relay veröffentlicht das Event nach RabbitMQ.
  8. Ein Billing Consumer reagiert auf das Event.
  9. Observability-Komponenten messen Zustand, Fehler und Durchsatz.
Technische Systemgrenzen
SystemVerantwortungWarum im Lab enthalten?
Spring Boot RuntimeREST, Security, Use Cases, Adapter Verdrahtungausführbare Anwendung
PostgreSQLfachliche Daten und Outboxechte relationale Persistenz
RabbitMQasynchrone Event-Kommunikationlose Kopplung und DLQ lernen
KeycloakIdentity ProviderOAuth2/OIDC realistisch üben
WireMockexterne Provider simulierenPayment/Fraud ohne echte Anbieter testen
MailHogE-Mail Simulationtechnische Benachrichtigung lokal testen
PrometheusMetriken sammelnBetriebssicht und Alerts
GrafanaDashboardsMetriken visuell verstehen
Architekturidee

Die Struktur folgt Ports and Adapters:

Domain
  keine Framework-Abhängigkeit

Application
  koordiniert Use Cases

Ports
  fachliche Verträge für Infrastruktur

Adapters
  PostgreSQL, RabbitMQ, WireMock, Payment, Outbox

Runtime
  Spring Boot, Security, Scheduling, REST, Actuator

Der wichtigste Lernpunkt: Fachlogik soll nicht von PostgreSQL, RabbitMQ, Keycloak oder Spring Security abhängig sein. Diese Dinge sitzen am Rand.

Kritische Flows

Synchronous Flow

Client -> REST -> Security -> Use Case -> Payment Provider -> PostgreSQL -> Response

Dieser Flow ist direkt sichtbar. Wenn Payment langsam oder fehlerhaft ist, muss Resilience greifen.

Asynchronous Flow

Use Case -> Outbox -> Relay -> RabbitMQ -> Billing Consumer

Dieser Flow zeigt lose Kopplung. Billing hängt nicht direkt im REST Request, sondern reagiert später auf Events.

Operational Flow

Runtime -> Actuator -> Prometheus -> Grafana -> Alert/Runbook

Dieser Flow zeigt, wie Betrieb und Entwicklung zusammenarbeiten.

---

Arbeitsweise im Code

Das Maven-Projekt ist modular aufgebaut. Änderungen sollen immer in der passenden Schicht landen.

maven-project/
├── domain
├── ports
├── application
├── adapters
├── runtime
└── integration-tests
Regel: Fachlogik zuerst

Neue fachliche Regeln gehören zuerst in domain. Beispiel: Eine Bestellung darf nicht ohne Position angenommen werden. Diese Regel darf nicht in einem REST Controller oder Repository versteckt werden.

// Pattern: Aggregate Root - Order schützt fachliche Invarianten zentral.
public final class Order {
    private final OrderId id;
    private final List<OrderLine> lines;
    private OrderStatus status;

    private Order(OrderId id, List<OrderLine> lines) {
        if (lines == null || lines.isEmpty()) {
            throw new DomainRuleViolation("Eine Bestellung braucht mindestens eine Position.");
        }

        this.id = id;
        this.lines = List.copyOf(lines);
        this.status = OrderStatus.DRAFT;
    }
}
Regel: Abhängigkeiten zeigen nach innen

Die Runtime darf Application, Ports und Adapters kennen. Die Domain darf nichts von Runtime, Spring, PostgreSQL oder RabbitMQ kennen.

ModulDarf kennenDarf nicht kennen
domaineigene Value Objects, EntitiesSpring, JDBC, RabbitMQ
portsDomainAdapter-Implementierungen
applicationDomain, PortsPostgreSQL, Keycloak, HTTP
adaptersPorts, Domain, technische LibrariesREST Controller Logik
runtimealle Module zur VerdrahtungFachregeln implementieren
Neuer Use Case: Vorgehen
  1. Fachliche Sprache notieren.
  2. Domain-Regeln ergänzen.
  3. Port definieren, falls Infrastruktur nötig ist.
  4. Application Service schreiben.
  5. Adapter implementieren.
  6. Runtime verdrahten.
  7. Tests ergänzen.
  8. Doku und Runbook aktualisieren.
Beispiel: neuer Provider

Wenn ein Fraud Provider ergänzt wird, sollte die Application nur einen Port sehen:

public interface FraudGateway {
    FraudDecision check(Order order);
}

Die konkrete HTTP-Kommunikation gehört in einen Adapter:

// Pattern: Gateway Adapter - externer Fraud Provider wird gekapselt.
public final class WireMockFraudGateway implements FraudGateway {
    private final RestClient restClient;

    public FraudDecision check(Order order) {
        return restClient.post()
                .uri("/fraud/check")
                .body(order.id().value())
                .retrieve()
                .body(FraudDecision.class);
    }
}
Coding-Konventionen
  • Entwurfsmuster im Code kurz kommentieren.
  • Keine Business-Regeln im Controller verstecken.
  • Keine Datenbankdetails in Domain-Klassen.
  • Keine langen Monster-Methoden ohne Zerlegung.
  • Adapter dürfen technisch sein, Application Services sollen lesbar bleiben.
  • Jede neue externe Integration braucht ein Runbook und ein Fehlerbild.
Lokale Entwicklerbefehle
docker compose up -d
cd maven-project
mvn -q -DskipTests package
mvn -pl runtime spring-boot:run
Typische Entwicklungsfehler
FehlerUrsacheBesser
Business-Regel im Controllerschneller HackRegel in Domain verschieben
Repository direkt im ControllerSchichten vermischtUse Case nutzen
RabbitTemplate im Use CaseBroker-LeakPublisher Port nutzen
JWT Claims in DomainSecurity-LeakSecurity am Runtime-Rand halten
Test nur mit MockIntegration bleibt unsichtbarkritischen Pfad mit Testcontainers testen

---

Betriebsziel

Das System soll lokal nachvollziehbar, in Kubernetes/OpenShift übertragbar und operativ beobachtbar sein. Betrieb bedeutet hier nicht nur "Container läuft", sondern: Start, Health, Logs, Metriken, Backup, Restore, Security und Incident Response sind dokumentiert.

Betriebsmodi
ModusZweckStartpunkt
LokalLernen und Entwicklungdocker compose up -d
CIQualität prüfen.github/workflows/ci.yml
Kubernetesgenerisches Deploymentdeploy/kubernetes
OpenShiftEnterprise Deploymentdeploy/openshift
Helmpaketiertes Deploymentdeploy/helm/order-runtime
Mindestchecks nach Start
docker compose ps
curl -fsS http://localhost:8082/realms/order-platform/.well-known/openid-configuration
curl -fsS http://localhost:8089/__admin/mappings
curl -fsS http://localhost:9090/-/ready
Laufende Betriebsindikatoren
IndikatorBedeutungReaktion
Outbox Backlog steigtEvents werden nicht veröffentlichtRabbitMQ/Relay prüfen
Payment Timeout steigtProvider langsamCircuit Breaker und Provider prüfen
401/403 steigtToken/RollenproblemKeycloak und Clients prüfen
DB Connections hochPool/Queries problematischSQL und Connection Pool prüfen
DLQ wächstConsumer kann Nachrichten nicht verarbeitenFehlerpayload analysieren
Log-Prinzip

Jeder Request soll eine Correlation ID erhalten. Dadurch kann man REST-Aufruf, Payment-Aufruf, Outbox-Eintrag und Consumer-Log zusammenführen.

X-Correlation-Id: 7f4d1c...
Betriebsrollen
RolleVerantwortung
EntwicklerCode, Tests, fachliche Fehleranalyse
Plattform-TeamContainer, Netzwerk, Secrets, Ressourcen
BetriebMonitoring, Incident Response, Backup
SecurityRollen, Token, Policies, Audits
Product/Fachbereichfachliche Priorisierung bei Incidents
Wartungsfenster

Für Datenbankmigrationen, große Konfigurationsänderungen und Keycloak-Realm-Änderungen sollte ein Wartungsfenster geplant werden. Kleine Runtime-Releases können bei Kubernetes/OpenShift über Rolling Updates erfolgen.

---

Schnellstart
cp .env.example .env
docker compose up -d
cd maven-project
mvn -q -DskipTests package
mvn -pl runtime spring-boot:run
Wichtige URLs
SystemURLLogin
Runtimehttp://localhost:8080Bearer Token
Adminerhttp://localhost:8081order_user / order_pass
Keycloakhttp://localhost:8082admin / admin
RabbitMQhttp://localhost:15672order_user / order_pass
WireMockhttp://localhost:8089kein Login
MailHoghttp://localhost:8025kein Login
Prometheushttp://localhost:9090kein Login
Grafanahttp://localhost:3000admin / admin
Geschützten Flow testen
./scripts/security/call-secured-order-flow.sh
Event Flow testen
curl -X POST http://localhost:8080/api/orders/ORD-LOCAL-1/accept \
  -H "Authorization: Bearer ${TOKEN}"

Danach prüfen:

select event_id, aggregate_id, event_type, status
from outbox.events
order by event_id desc;
Fehler: Port ist belegt

Symptom:

bind: address already in use

Prüfen:

docker ps
lsof -i :5432
lsof -i :8082

Lösung:

docker compose down

Oder Ports in docker-compose.yml ändern.

Fehler: Keycloak Token funktioniert nicht

Mögliche Ursachen:

  • Realm wurde noch nicht importiert.
  • Keycloak ist noch nicht vollständig gestartet.
  • Falscher Client order-runtime.
  • User oder Passwort falsch.
  • Runtime erwartet einen anderen Issuer.

Prüfung:

curl http://localhost:8082/realms/order-platform/.well-known/openid-configuration
Fehler: Outbox bleibt NEW

Ursachen:

  • Runtime Scheduler läuft nicht.
  • RabbitMQ ist nicht erreichbar.
  • Routing Key ist falsch.
  • Publisher wirft Exception.

Prüfung:

select * from outbox.events order by event_id desc;

RabbitMQ prüfen:

http://localhost:15672
Fehler: Metriken fehlen

Prüfen:

curl http://localhost:8080/actuator/prometheus
curl http://localhost:9090/targets

Wenn Prometheus die Runtime nicht erreicht, ist host.docker.internal auf der Plattform eventuell anders zu konfigurieren.

---

Entscheidung 1: Maven Multi-Module statt einzelnes Projekt

Entscheidung: Das Projekt nutzt domain, ports, application, adapters, runtime und integration-tests.

Grund: Die Modulgrenzen machen Abhängigkeiten sichtbar. Ein einzelnes Projekt wäre schneller, aber fachliche und technische Klassen würden leichter vermischt.

Konsequenz: Mehr Struktur, mehr POM-Dateien, aber bessere Lernwirkung.

Entscheidung 2: Ports and Adapters

Entscheidung: Externe Systeme werden über Ports abstrahiert.

Alternativen: Direkt JdbcTemplate, RabbitTemplate oder RestClient im Use Case verwenden.

Bewertung: Direkte technische Abhängigkeiten sind am Anfang schneller, führen aber zu schlechter testbarer Fachlogik.

Entscheidung 3: Transactional Outbox

<img src="diagrams/outbox-flow.svg" alt="Outbox Flow">
Outbox Flow

Entscheidung: Events werden zuerst in PostgreSQL gespeichert und danach durch ein Relay publiziert.

Grund: Vermeidung des Dual-Write-Problems zwischen Datenbank und Message Broker.

Konsequenz: Zusätzliche Tabelle, Relay-Logik und Monitoring nötig.

Entscheidung 4: Keycloak als echter Identity Provider

Entscheidung: OIDC/JWT wird nicht nur simuliert, sondern über Keycloak bereitgestellt.

Grund: Rollen, Claims, Issuer und Tokenfehler sind in Enterprise-Projekten zentrale Fehlerquellen.

Konsequenz: Mehr Container-Setup, aber deutlich realistischer.

Entscheidung 5: WireMock statt echter Payment Provider

Entscheidung: Payment und Fraud werden als Mock Provider umgesetzt.

Grund: Externe Anbieter sind teuer, instabil oder nicht lokal verfügbar. WireMock erlaubt klare Verträge.

Entscheidung 6: Docker Compose als lokales Systemlabor

Entscheidung: Alle Systeme laufen lokal per Compose.

Grund: Ein Lernprojekt braucht reproduzierbaren Start ohne Cloud-Abhängigkeit.

Entscheidung 7: Kubernetes/OpenShift ergänzen, aber Compose behalten

Entscheidung: Compose bleibt Lern- und Entwicklungsmodus. Kubernetes/OpenShift sind Deployment-Profile.

Grund: Beide Welten haben andere Ziele. Compose ist schnell, Kubernetes ist produktionsnäher.

Entscheidung 8: Observability als Code

Entscheidung: Prometheus-Regeln und Grafana Dashboards liegen als Dateien im Projekt.

Grund: Monitoring darf kein manuelles Klickprodukt sein.

Entscheidung 9: Resilience als Boundary

Entscheidung: Retry, Timeout und Circuit Breaker sitzen um externe Calls, nicht in der Domain.

Grund: Resilience ist technische Schutzlogik. Die Fachlogik soll nicht wissen, ob ein Provider gerade instabil ist.

---

<img src="diagrams/security-flow.svg" alt="Security Flow">
Security Flow

Security-Ziel

Die Anwendung nutzt Keycloak als Identity Provider. Die Runtime ist ein OAuth2 Resource Server. REST-Endpunkte werden über Rollen geschützt.

Rollenmodell
Keycloak RolleSpring AuthorityZugriff
order-readerROLE_ORDER_READERlesende Order-Funktionen
order-adminROLE_ORDER_ADMINBestellung annehmen
billing-userROLE_BILLING_USERBilling-Funktionen
Tokenfluss
Client -> Keycloak Token Endpoint -> JWT -> Runtime -> Spring Security -> Controller
Wichtige Regel

Security bleibt in der Runtime-Schicht. Domain und Application sollen keine JWT Claims auswerten.

Token holen
TOKEN="$(
  curl -s -X POST "http://localhost:8082/realms/order-platform/protocol/openid-connect/token" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "client_id=order-runtime" \
    -d "grant_type=password" \
    -d "username=order-admin" \
    -d "password=admin" | python -c "import sys,json; print(json.load(sys.stdin)['access_token'])"
)"
Positivtest
curl -i -X POST "http://localhost:8080/api/orders/ORD-SEC-1/accept" \
  -H "Authorization: Bearer ${TOKEN}"

Erwartung: 200 OK.

Negativtest

Mit order-reader darf der POST nicht erlaubt sein. Erwartung: 403 Forbidden.

Häufige Security-Fehler
SymptomUrsacheLösung
401 UnauthorizedToken fehlt/ungültigToken neu holen
403 ForbiddenToken gültig, Rolle fehltKeycloak Rolle prüfen
Issuer mismatchRuntime erwartet anderen Issuerapplication.yml prüfen
Rollen leerConverter findet Claim nichtrealm_access.roles prüfen
Prometheus kann nicht scrapenEndpoint geschützt/actuator/prometheus permitAll lassen
Produktionshinweise
  • Keine Default-Passwörter in Produktion.
  • Realm-Konfiguration versionieren.
  • Client Secrets und Admin-Passwörter als Secrets verwalten.
  • Token-Lebensdauer bewusst wählen.
  • Rollen nicht direkt aus UI-Wünschen ableiten, sondern fachlich modellieren.

---

Ziel

Observability beantwortet drei Fragen:

  1. Ist das System erreichbar?
  2. Funktionieren fachliche Flows?
  3. Wo entsteht ein Fehler oder Engpass?
Metrikarten
MetrikartBeispielZweck
technische MetrikHTTP LatenzPerformance prüfen
fachliche Metrikakzeptierte BestellungenBusiness Flow beobachten
IntegrationsmetrikPayment FehlerProvider-Probleme sehen
BetriebsmetrikOutbox BacklogEvent-Stau erkennen
Health Checks

Actuator Health zeigt technische Bereitschaft. Ein Health Check darf nicht nur sagen, dass der Prozess läuft. Wichtig sind Abhängigkeiten:

  • PostgreSQL erreichbar?
  • Outbox Backlog im Rahmen?
  • RabbitMQ erreichbar?
  • Payment Provider erreichbar oder Circuit offen?
Correlation ID

Jeder Request soll mit einer Correlation ID nachvollziehbar sein:

Client Request
  -> Runtime Log
  -> Payment Call
  -> Outbox Event
  -> Consumer Log
Prometheus

Prometheus scrapt:

/actuator/prometheus

Wichtige PromQL-Ideen:

rate(http_server_requests_seconds_count[5m])
sum(order_outbox_backlog)
Grafana

Dashboards sollten nicht nur technische Kurven zeigen, sondern Fragen beantworten:

  • Kommen Bestellungen rein?
  • Werden Events publiziert?
  • Gibt es Backlog?
  • Steigt die Fehlerrate?
  • Ist der Payment Provider langsam?
Alert-Regeln

Gute Alerts sind handlungsorientiert. Ein Alert soll ein Runbook verlinken und nicht nur "rot" sein.

AlertBedeutungRunbook
OutboxBacklogHighRelay/Broker ProblemOutbox/RabbitMQ Runbook
PaymentErrorRateHighProvider instabilResilience Runbook
RuntimeDownAnwendung nicht erreichbarBetriebs-Runbook
DbConnectionHighDB/Pool ProblemDatenbank-Runbook
Logging-Grundregeln
  • Keine Tokens loggen.
  • Keine Passwörter loggen.
  • Fachliche IDs erlaubt, personenbezogene Daten vermeiden.
  • Correlation ID immer mitschreiben.
  • Fehler mit Ursache und Kontext, aber ohne Secrets.

---

Ziel

Resilience schützt das System vor instabilen Abhängigkeiten. Im Projekt ist besonders der Payment Provider relevant.

Muster
MusterZweckBeispiel
Timeoutnicht endlos wartenPayment Provider langsam
Retrytemporäre Fehler abfangenkurzer Netzwerkfehler
Circuit Breakerkaputte Abhängigkeit entlastenProvider down
BulkheadRessourcen isolierenPayment blockiert nicht alles
Rate LimitingÜberlast begrenzenzu viele API Requests
Reihenfolge

Eine sinnvolle Kette:

Rate Limit -> Bulkhead -> Timeout -> Retry -> Circuit Breaker -> Fallback/Error Response
Timeout

Timeout verhindert, dass Threads oder Verbindungen hängen bleiben. Ein Timeout muss kleiner sein als der Client-Timeout vor der Runtime.

Retry

Retry nur bei Fehlern verwenden, die wirklich transient sind. Nicht jeder Fehler darf wiederholt werden.

Nicht sinnvoll:

400 Bad Request -> Retry

Sinnvoll:

503 Service Unavailable -> Retry mit Backoff
Circuit Breaker

Der Circuit Breaker öffnet, wenn zu viele Fehler auftreten. Danach werden Calls kurzfristig abgelehnt, damit sich der Provider erholen kann.

Fehlerantworten

APIs sollen stabile Fehlerformate liefern:

{
  "code": "PAYMENT_TEMPORARILY_UNAVAILABLE",
  "message": "Payment Provider ist aktuell nicht erreichbar.",
  "correlationId": "..."
}
Runbook bei Payment-Ausfall
  1. Grafana Payment Dashboard prüfen.
  2. Circuit Breaker Status prüfen.
  3. WireMock/Provider Health prüfen.
  4. Logs mit Correlation ID suchen.
  5. Outbox Backlog prüfen.
  6. Falls Provider down: Incident klassifizieren.
  7. Nach Wiederherstellung Retry/Backlog beobachten.

---

Ziel

PostgreSQL ist im Projekt nicht nur Datenspeicher, sondern auch Teil des Integrationsmusters durch die Outbox. Deshalb braucht die Datenbank eigene Betriebsdoku.

Schemata
SchemaZweck
order_platformfachliche Order-Daten
outboxEvent-Zwischenspeicher
Migrationen

Migrationen laufen über Flyway. Jede Änderung am Schema soll als neue Migration versioniert werden.

V1__create_order_and_outbox.sql
V2__outbox_relay_indexes.sql
Backup

Backup-Script:

./scripts/database/backup-postgres.sh

Grundregel:

  • Backup regelmäßig testen.
  • Restore regelmäßig üben.
  • Backup ohne Restore-Test ist nur eine Hoffnung.
Restore

Restore-Script:

./scripts/database/restore-postgres.sh backup-file.sql
Outbox Retention

Outbox Events dürfen nicht unbegrenzt wachsen. Publizierte Events können nach einer definierten Zeit archiviert oder gelöscht werden.

Beispiel:

delete from outbox.events
where status = 'PUBLISHED'
  and published_at < now() - interval '30 days';
Wichtige SQL Checks
select status, count(*)
from outbox.events
group by status;
select count(*)
from order_platform.orders;
select installed_rank, version, description, success
from flyway_schema_history
order by installed_rank desc;
Produktionshinweise
  • Keine manuellen Schemaänderungen ohne Migration.
  • Indizes für Outbox Status und Event ID prüfen.
  • Connection Pool überwachen.
  • Lange Transaktionen vermeiden.
  • Backup-Verschlüsselung und Aufbewahrung definieren.
  • Restore-Zeit messen und dokumentieren.

---

<img src="diagrams/deployment-profiles.svg" alt="Deployment Profile">
Deployment Profile

CI/CD-Ziel

Die Pipeline soll nicht nur bauen, sondern Qualität sichtbar erzwingen.

Quality Gates
GateZweck
Maven VerifyKompilierung und Tests
Dependency Reviewriskante Abhängigkeiten erkennen
SBOMSoftwarebestand dokumentieren
Lizenzprüfungrechtliche Risiken sichtbar machen
Docker BuildRuntime Image baubar halten
Release CheckPaketstruktur prüfen
Lokale Gates
./scripts/quality/run-quality-gates.sh
Docker Image
./scripts/deploy/build-runtime-image.sh
Kubernetes Deployment
kubectl apply -k deploy/kubernetes/overlays/local
OpenShift Deployment
oc apply -k deploy/kubernetes/overlays/openshift
Helm Deployment
helm upgrade --install order-runtime deploy/helm/order-runtime
Release-Regel

Ein Release ist erst dann fertig, wenn:

  • Tests grün sind.
  • SBOM erzeugt wurde.
  • Lizenzbericht geprüft wurde.
  • Docker Image gebaut wurde.
  • Deployment Manifest gerendert wurde.
  • Runbooks aktualisiert wurden.
  • Version und Release Notes stimmen.
Typischer Pipeline-Ablauf
checkout
  -> setup java
  -> mvn verify
  -> testcontainers/e2e optional
  -> sbom
  -> license report
  -> docker build
  -> manifest render
  -> release artifact

---

Testziel

Tests sollen nicht nur Code Coverage erzeugen. Sie sollen Risiken absichern.

Testpyramide
Viele Domain Tests
  -> Application Tests
  -> Adapter Tests
  -> Contract Tests
  -> Security Tests
  -> wenige E2E Tests
Welche Tests gehören wohin?
RisikoTestart
Fachregel falschDomain Test
Use Case ruft falschen PortApplication Test
SQL falschAdapter Test mit PostgreSQLContainer
Payment Vertrag falschWireMock Contract Test
Rolle falschSecurity Test
Systemfluss kaputtE2E Test
Testcontainers

Testcontainers ist für Infrastrukturtests gedacht. Nicht jeder Test sollte Container starten.

Gute Kandidaten:

  • PostgreSQL Schema/Migration.
  • RabbitMQ Verbindung und Routing.
  • WireMock Providervertrag.
  • E2E Happy Path.

Schlechte Kandidaten:

  • einfache Value Object Regeln.
  • reine Berechnung.
  • Mapping ohne Infrastruktur.
E2E Testumfang

Ein guter E2E-Test prüft einen kritischen Pfad:

REST -> Security -> Use Case -> Payment -> DB -> Outbox -> RabbitMQ -> Consumer

Aber er soll nicht alle fachlichen Varianten abdecken. Sonst wird er langsam und fragil.

Testdaten

Testdaten müssen reproduzierbar sein. Keine versteckten lokalen Datenbanken. Keine Abhängigkeit von vorheriger Testreihenfolge.

Fehlerdiagnose

Wenn ein E2E-Test fehlschlägt:

  1. Container Logs prüfen.
  2. Ports und Health prüfen.
  3. Testdaten prüfen.
  4. WireMock Requests prüfen.
  5. DB Zustand prüfen.
  6. RabbitMQ Queue prüfen.

---

Fehlerklasse: REST 401

Symptom: API antwortet mit 401 Unauthorized.

Wahrscheinliche Ursachen:

  • Kein Token gesendet.
  • Token abgelaufen.
  • Issuer stimmt nicht.
  • Keycloak nicht erreichbar.

Runbook:

curl http://localhost:8082/realms/order-platform/.well-known/openid-configuration
./scripts/security/get-keycloak-token.sh order-admin admin
Fehlerklasse: REST 403

Symptom: Token gültig, Zugriff verboten.

Ursache: Rolle fehlt.

Runbook:

  • JWT Claims prüfen.
  • realm_access.roles prüfen.
  • Mapping zu ROLE_* prüfen.
  • Security-Regel für Endpunkt prüfen.
Fehlerklasse: Outbox Backlog

Symptom: Viele Events bleiben NEW.

Ursachen:

  • Relay läuft nicht.
  • RabbitMQ down.
  • Routing falsch.
  • Publisher wirft Exception.

Runbook:

select status, count(*) from outbox.events group by status;

RabbitMQ Management prüfen:

http://localhost:15672
Fehlerklasse: Payment Timeout

Symptom: Bestellannahme langsam oder fehlerhaft.

Runbook:

  • WireMock Mapping prüfen.
  • Resilience Dashboard prüfen.
  • Circuit Breaker Status prüfen.
  • Correlation ID in Logs verfolgen.
Fehlerklasse: Migration fehlgeschlagen

Symptom: Runtime startet nicht, Flyway Fehler.

Runbook:

select * from flyway_schema_history order by installed_rank desc;
  • Fehlgeschlagene Migration nicht manuell überschreiben.
  • Ursache analysieren.
  • Korrektur als neue Migration erstellen.
Fehlerklasse: Prometheus Target down

Symptom: Grafana zeigt keine Daten.

Runbook:

curl http://localhost:8080/actuator/prometheus
curl http://localhost:9090/targets
Fehlerklasse: Docker Compose startet nicht

Symptom: Container bleiben unhealthy oder starten nicht.

Runbook:

docker compose ps
docker compose logs postgres
docker compose logs keycloak
docker compose logs rabbitmq
Incident-Klassifikation
KlasseBeispielReaktion
P1Bestellungen können nicht angenommen werdensofortiger Incident
P2Billing Consumer hängt, Outbox wächstpriorisiert behandeln
P3Dashboard fehlerhaft, System läuftnormaler Fix
P4Doku/Minor IssueBacklog

---

Aggregate Root

Zentrale fachliche Einheit, die Invarianten schützt. Im Projekt ist Order ein Aggregate Root.

Application Service

Koordiniert einen Use Case. Er enthält Ablaufsteuerung, aber keine technischen Details.

Adapter

Technische Implementierung eines Ports. Beispiele: PostgreSQL Repository, RabbitMQ Publisher, WireMock Gateway.

Port

Fachlicher Vertrag, den die Application benötigt. Der Port kennt keine konkrete Infrastruktur.

Transactional Outbox

Muster, bei dem Events zuerst in derselben Datenbanktransaktion gespeichert und später veröffentlicht werden.

Relay

Job oder Prozess, der Outbox Events liest und an einen Message Broker publiziert.

RabbitMQ Exchange

Verteiler für Nachrichten. Im Projekt: order.events.

Routing Key

Schlüssel, mit dem RabbitMQ entscheidet, welche Queue eine Nachricht erhält.

DLQ

Dead Letter Queue. Dort landen Nachrichten, die nicht verarbeitet werden konnten.

OAuth2 Resource Server

Anwendung, die Bearer Tokens validiert und Zugriffe schützt.

JWT

JSON Web Token. Enthält Claims wie Subject, Rollen und Ablaufzeit.

Keycloak Realm

Isolierter Sicherheitsbereich mit Clients, Rollen und Usern.

Prometheus

Zeitreihen-Datenbank und Scraper für Metriken.

Grafana

Dashboard-System zur Visualisierung von Metriken.

Circuit Breaker

Resilience-Muster, das bei vielen Fehlern weitere Aufrufe temporär verhindert.

Bulkhead

Resilience-Muster zur Isolation von Ressourcen.

SBOM

Software Bill of Materials. Liste verwendeter Software-Komponenten.

ADR

Architecture Decision Record. Dokumentiert wichtige Architekturentscheidungen.

---

Root
Datei/OrdnerBedeutung
index.htmlHauptstartseite
OPEN_THIS_V2_REAL_SYSTEMS.htmlalternativer Startpunkt
README.mdProjektüberblick
START-HIER.mdschnelle Anleitung
docker-compose.ymllokaler Container-Stack
.env.exampleBeispielumgebung
Dockerfile.runtimeRuntime Image Build
Maven Projekt
PfadBedeutung
maven-project/domainFachmodell
maven-project/portsPort-Schnittstellen
maven-project/applicationUse Cases
maven-project/adapterstechnische Adapter
maven-project/runtimeSpring Boot Runtime
maven-project/integration-testsTestcontainers und E2E Tests
Container
PfadBedeutung
containers/postgresInit SQL
containers/rabbitmqExchange, Queue, DLQ Definitionen
containers/keycloakRealm Import
containers/wiremockMock Provider Mappings
containers/prometheusPrometheus Konfiguration und Alerts
containers/grafanaDashboard Provisioning
Dokumentation
PfadBedeutung
docs/architectureArchitekturdetails
docs/runbookskonkrete Betriebsanleitungen
docs/adrArchitekturentscheidungen
docs/securitySecurity Modell
docs/testingTeststrategie
dokumentationfinales ausgiebiges Handbuch
lehrbuchLernbuch Markdown/HTML/PDF
berichtePrüfberichte und Release Notes
promptsverwendbare Weiterarbeit-Prompts
Deployment
PfadBedeutung
deploy/kubernetesKubernetes Manifeste
deploy/helmHelm Chart
scripts/deployDeployment-Hilfsskripte
Betriebsskripte
PfadBedeutung
scripts/securityToken und Security Flow
scripts/testsTest/E2E Checks
scripts/databaseBackup/Restore/Checks
scripts/observabilityMetrikchecks
scripts/resilienceFehler- und Timeout-Szenarien
scripts/qualityQuality Gates

---

Ziel

Dieser Lernplan hilft, das Projekt nicht nur zu öffnen, sondern systematisch zu verstehen.

Woche 1: Struktur verstehen
  • Root index.html öffnen.
  • README.md lesen.
  • Maven Module ansehen.
  • domain, ports, application, adapters, runtime vergleichen.

Übung:

cd maven-project
mvn -q -DskipTests package
Woche 2: Lokale Systemlandschaft starten
  • Docker Compose starten.
  • Adminer, RabbitMQ, Keycloak, Grafana öffnen.
  • WireMock Mapping ansehen.

Übung:

docker compose up -d
docker compose ps
Woche 3: REST und Security
  • Token holen.
  • geschützten Flow testen.
  • order-admin und order-reader vergleichen.

Übung:

./scripts/security/call-secured-order-flow.sh
Woche 4: Outbox und Messaging
  • Outbox Tabelle ansehen.
  • Relay Job verstehen.
  • RabbitMQ Queue prüfen.

Übung:

select status, count(*) from outbox.events group by status;
Woche 5: Observability und Resilience
  • Actuator Prometheus Endpoint öffnen.
  • Grafana Dashboard ansehen.
  • Timeout/Fehlerfall über WireMock simulieren.
Woche 6: Tests und CI/CD
  • Testcontainers Struktur verstehen.
  • E2E Tests ausführen.
  • GitHub Actions Pipeline lesen.

Übung:

./scripts/tests/run-phase4-e2e.sh
./scripts/quality/run-quality-gates.sh
Woche 7: Deployment und Betrieb
  • Dockerfile verstehen.
  • Kubernetes/Kustomize lesen.
  • Helm Chart lesen.
  • Backup/Restore Runbook durcharbeiten.
Abschlussaufgabe

Ergänze einen Fraud Provider:

  1. FraudGateway Port definieren.
  2. WireMock Fraud Mapping erstellen.
  3. Application Service erweitern.
  4. Resilience für Fraud Call ergänzen.
  5. Metrik fraud_checks_total ergänzen.
  6. Testcontainers/Contract Test ergänzen.
  7. Doku und Runbook aktualisieren.
⌂ Cockpit