Home
Enterprise Maven MasterclassMaven Masterclass
Echte Projektartefakte

Verständnis-Navigator

Geführte Durchstiche durch tatsächlich vorhandene POMs, Java-Klassen, Smoke-Flows und Plattformdateien.

Dokument: Verständnis-NavigatorZielgruppe: Lernende und EntwicklerNiveau: Einstieg bis Deep DiveStatus: geprüftStand: 10.07.2026

Dieser Navigator erklärt die Masterclass nicht nur über Begriffe. Er führt durch tatsächlich vorhandene POMs, Java-Klassen, Smoke-Flows und Plattformdateien im Paket. Jeder genannte Pfad wurde im aktuellen ZIP geprüft.

1. Die wichtigste Lernregel

Lies eine Enterprise-Anwendung in sieben getrennten Sichten:

  1. Fachlichkeit: Welches geschäftliche Problem wird gelöst?
  2. Ablauf: Welche Zustandsänderungen passieren nacheinander?
  3. Modulstruktur: Welches Maven-Modul trägt welche Verantwortung?
  4. Code: Welche Klasse enthält Regel, Orchestrierung, Port oder Adapter?
  5. Runtime: Wo beginnt der ausführbare Ablauf?
  6. Betrieb: Welche Konfiguration, Datenbank, Container- oder Sicherheitsdatei gehört dazu?
  7. End-to-End: Was ist echte Ausführung und was ist bewusst simuliert?

Merksatz: Ein Dateiname oder Modulname beweist noch keine produktive Implementierung. Prüfe immer den Inhalt.

2. Vier Evidenzstufen im Paket

Stufe Bedeutung Woran du sie erkennst
E1 – echte Fachlogik Zustände und Regeln werden im Java-Code geprüft Aggregate, Value Objects, Policies, Tests
E2 – echte lokale Ausführung Eine Main-Klasse oder Runtime führt Code aus RunnableSmokeApp, Spring-Boot-Main, Maven-Startbefehl
E3 – technische Beispielkonfiguration Konfiguration ist konkret, aber nicht als produktive Umgebung nachgewiesen Dockerfile, Compose, Kubernetes, OpenShift, Backup-Skript
E4 – didaktische Simulation Ein Ablauf wird nachvollziehbar dargestellt, ruft aber keine echten Fremdsysteme auf feste Ergebnislisten, new Service(), In-Memory-Speicher, simulierte Meldungen

Diese Einordnung ist absichtlich streng. Sie hilft dir, Lerncode nicht mit einem vollständig integrierten Produktionssystem zu verwechseln.

3. Geführter Durchstich 1: Master 1 – Bestellung von Domain bis REST

3.1 Maven-Reaktor zuerst lesen

Der Ordner 01_MVN_SB3_Modulare_Grundlage/versions/v01-modular-baseline enthält die Module:

Das ist die Architektur bereits als Maven-Struktur: Fachmodell → Anwendungsfall → technischer Speicheradapter → REST-Runtime → separater Smoke-Ablauf.

3.2 Domain: Das Aggregate schützt Regeln

Pfad: 01_MVN_SB3_Modulare_Grundlage/versions/v01-modular-baseline/order-domain/src/main/java/com/aydinsude/enterprise/v01/domain/Order.java

package com.aydinsude.enterprise.v01.domain;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

// PATTERN: Aggregate - Order protects consistency of lines and status.
public final class Order {
    private final OrderId id;
    private final List<OrderLine> lines = new ArrayList<>();
    private OrderStatus status = OrderStatus.OPEN;

    private Order(OrderId id) { this.id = id; }

    // PATTERN: Factory Method - valid aggregate root creation.
    public static Order open(OrderId id) { return new Order(id); }

    public OrderId id() { return id; }
    public OrderStatus status() { return status; }
    public List<OrderLine> lines() { return Collections.unmodifiableList(lines); }

    public void addLine(OrderLine line) {
        ensureOpen();
        lines.add(line);
    }

    public Money total() {
        return lines.stream().map(OrderLine::lineTotal).reduce(Money.eur("0.00"), Money::add);
    }

    public void submit() {
        ensureOpen();
        if (lines.isEmpty()) throw new IllegalStateException("Order must contain at least one line");
        status = OrderStatus.SUBMITTED;
    }

    private void ensureOpen() {
        if (status != OrderStatus.OPEN) throw new IllegalStateException("Order is not open");
    }
}

Was daran fachlich ist:

Die Klasse kennt weder HTTP noch Datenbank noch Spring. Genau daran erkennst du eine saubere fachliche Grenze.

3.3 Application: Der Use Case orchestriert

Pfad: .../order-application/.../PlaceOrderUseCase.java

package com.aydinsude.enterprise.v01.application;

import com.aydinsude.enterprise.v01.domain.*;

// PATTERN: Application Service / Use Case - coordinates domain object and repository port.
public final class PlaceOrderUseCase {
    private final OrderRepository repository;
    private final PricingPolicy pricingPolicy;

    public PlaceOrderUseCase(OrderRepository repository, PricingPolicy pricingPolicy) {
        this.repository = repository;
        this.pricingPolicy = pricingPolicy;
    }

    public OrderId place(PlaceOrderCommand command) {
        Order order = Order.open(OrderId.newId());
        command.lines().forEach(line -> order.addLine(OrderLine.of(line.sku(), line.quantity(), Money.eur(line.unitPriceEur()))));
        pricingPolicy.calculateTotal(order); // explicit strategy extension point
        order.submit();
        repository.save(order);
        return order.id();
    }
}

Der Use Case erzeugt nicht selbst SQL und beantwortet auch keinen HTTP-Request. Er führt einen fachlichen Auftrag aus:

  1. Bestellung öffnen.
  2. Positionen aus dem Command übernehmen.
  3. Preisstrategie aufrufen.
  4. Bestellung einreichen.
  5. Über den Repository-Port speichern.
  6. Die fachliche ID zurückgeben.

3.4 Port und Adapter auseinanderhalten

Port: .../order-application/.../OrderRepository.java

package com.aydinsude.enterprise.v01.application;

import com.aydinsude.enterprise.v01.domain.Order;
import com.aydinsude.enterprise.v01.domain.OrderId;
import java.util.Optional;

// PATTERN: Repository Port - application defines persistence contract; adapter implements it.
public interface OrderRepository {
    void save(Order order);
    Optional<Order> findById(OrderId id);
}

Adapter: .../order-adapter-memory/.../InMemoryOrderRepository.java

package com.aydinsude.enterprise.v01.adapter.memory;

import com.aydinsude.enterprise.v01.application.OrderRepository;
import com.aydinsude.enterprise.v01.domain.Order;
import com.aydinsude.enterprise.v01.domain.OrderId;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

// PATTERN: Adapter + Repository implementation - technical storage behind application port.
public final class InMemoryOrderRepository implements OrderRepository {
    private final Map<OrderId, Order> store = new ConcurrentHashMap<>();
    @Override public void save(Order order) { store.put(order.id(), order); }
    @Override public Optional<Order> findById(OrderId id) { return Optional.ofNullable(store.get(id)); }
}

Der Port gehört zur Anwendungsschicht. Der Adapter implementiert ihn mit einer ConcurrentHashMap. Deshalb ist dies eine echte lokale Implementierung, aber keine produktive Persistenz.

3.5 REST ist nur der Eingang

Pfad: .../order-app/.../OrderController.java

package com.aydinsude.enterprise.v01.app;

import com.aydinsude.enterprise.v01.application.PlaceOrderCommand;
import com.aydinsude.enterprise.v01.application.PlaceOrderUseCase;
import org.springframework.web.bind.annotation.*;
import java.util.Map;

// PATTERN: Adapter - REST DTO boundary maps HTTP to application command.
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
    private final PlaceOrderUseCase useCase;
    public OrderController(PlaceOrderUseCase useCase) { this.useCase = useCase; }
    @PostMapping
    public Map<String, String> place(@RequestBody PlaceOrderCommand command) {
        return Map.of("orderId", useCase.place(command).value().toString());
    }
}

Der Controller übersetzt HTTP in PlaceOrderCommand und delegiert an den Use Case. Die Regel „Bestellung darf nicht leer sein“ bleibt im Aggregate und wird nicht in den Controller verschoben.

4. Geführter Durchstich 2: Master 8 – Versicherungsprozess wirklich lesen

Pfad: 08_IMPL_INS_Versicherung/mvn-ws-impl-ins/runnable-smoke/.../InsuranceProcessFacade.java

package com.aydin.enterprise.master8.runnable;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

public final class InsuranceProcessFacade {
    public InsuranceResult runDemo(Customer customer) {
        List<String> steps = new ArrayList<>();
        // PATTERN: Pipeline - Quote -> Underwriting -> Policy -> Billing -> Claim -> Payout.
        Quote quote = new QuoteService().createQuote(customer, new BigDecimal("125000.00"));
        steps.add("Quote erstellt: " + quote.quoteNumber());
        UnderwritingDecision decision = new UnderwritingService().decide(quote);
        steps.add("Underwriting: " + decision.status() + " / " + decision.reason());
        if (!decision.accepted()) return InsuranceResult.rejected("Underwriting abgelehnt", steps);
        Policy policy = new PolicyService().issuePolicy(quote, LocalDate.now());
        steps.add("Police erstellt: " + policy.policyNumber());
        Invoice invoice = new BillingService().createInvoice(policy);
        steps.add("Rechnung erstellt: " + invoice.invoiceNumber() + " Betrag=" + invoice.amount());
        PaymentReceipt payment = new PaymentService().settle(invoice);
        steps.add("Zahlung verbucht: " + payment.receiptNumber());
        Claim claim = new ClaimsService().registerClaim(policy, new BigDecimal("8500.00"), "Wasserschaden");
        steps.add("Schaden erfasst: " + claim.claimNumber());
        ClaimDecision claimDecision = new ClaimsService().assess(claim, policy);
        steps.add("Schadenentscheidung: " + claimDecision.status());
        Payout payout = new ClaimsService().payout(claimDecision);
        steps.add("Auszahlung: " + payout.payoutNumber() + " Betrag=" + payout.amount());
        ReinsuranceNote note = new ReinsuranceService().evaluate(policy, claimDecision);
        steps.add("Rueckversicherung: " + note.message());
        AuditTrail audit = new AuditTrail("TRACE-INS-8", steps);
        return InsuranceResult.accepted("Versicherungsablauf abgeschlossen", audit.events());
    }
}

Was der Ablauf tatsächlich macht

Der Tarif kommt aus der real vorhandenen QuoteService:

package com.aydin.enterprise.master8.runnable;
import java.math.BigDecimal;
public final class QuoteService {
    public Quote createQuote(Customer customer, BigDecimal sumInsured) {
        // PATTERN: Domain Service - Tariflogik wird fachlich zentralisiert.
        BigDecimal rate = switch (customer.riskClass()) { case LOW -> new BigDecimal("0.018"); case MEDIUM -> new BigDecimal("0.026"); case HIGH -> new BigDecimal("0.041"); };
        return new Quote("Q-2026-0001", customer, sumInsured, sumInsured.multiply(rate));
    }
}

Die Risikoklasse bestimmt den Satz 0.018, 0.026 oder 0.041. Das ist nachvollziehbare Fachlogik. Gleichzeitig ist der Ablauf didaktisch: Services werden direkt mit new erzeugt, Nummern sind fest vorgegeben, und es gibt in diesem Smoke-Flow keine Datenbank- oder Netzwerktransaktion.

Lernwert: Du kannst Fachbegriffe, Reihenfolge und Verantwortlichkeiten lesen. Produktionslücke: Persistenz, Transaktionen, externe Zahlungs- und Rating-Schnittstellen, robuste Fehlerbehandlung und Idempotenz fehlen im gezeigten Smoke-Durchstich.

5. Geführter Durchstich 3: Master 14 – Legacy-Modernisierung ohne Selbsttäuschung

Der Master enthält konkrete Module wie characterization-tests, strangler-facade, anti-corruption-layer, data-reconciliation, parallel-run, cutover-control, rollback-control, oracle-to-postgres-adapter und outbox-bridge.

Der ausführbare Demo-Ablauf lautet:

package com.aydin.enterprise.master14.demo;
import java.util.ArrayList;
import java.util.List;
public final class DemoProcessFacade {
    public DemoResult run() {
        // PATTERN: Pipeline - die fachlichen Schritte laufen kontrolliert nacheinander.
        List<String> steps = new ArrayList<>();
        for (String step : List.of("Legacy Read", "Characterization Test", "Strangler Facade", "Extract Domain", "Outbox Bridge", "Data Migration", "Parallel Run", "Cutover")) {
            steps.add("OK - " + step);
        }
        // PATTERN: Result Object - ein konsistentes Ergebnis fuer Smoke Test und Dokumentation.
        return DemoResult.accepted("Master 14 Legacy Refactoring and Migration System Demo erfolgreich", steps);
    }
}

Das ist keine echte Datenmigration. Der Code protokolliert eine sinnvolle Reihenfolge als erfolgreiche Schritte. Dadurch ist er für Orientierung geeignet, aber kein Nachweis, dass Oracle-Daten gelesen, transformiert und in PostgreSQL abgeglichen wurden.

Auch die Capability-Klasse zeigt die didaktische Struktur:

package com.aydin.enterprise.master14.demo;
import java.time.Instant;
import java.util.List;

/** Modul strangler-facade im System Legacy Refactoring and Migration System. */
public final class StranglerFacadeCapability {
    // PATTERN: Aggregate Root - klare fachliche Modulgrenze.
    private final String name = "strangler-facade";
    public CapabilityReport describe() {
        // PATTERN: Domain Event - Ereignisse/Ergebnisse bleiben nachvollziehbar.
        return new CapabilityReport(name, "domain", "Legacy Refactoring and Migration System", Instant.now(), List.of("Aggregate Root", "Value Object", "Specification", "Domain Event"));
    }
    public Decision handle(String input) {
        // PATTERN: Specification - fachliche Regel ist isoliert und testbar.
        if (input == null || input.isBlank()) return Decision.reject(name, "Eingang fehlt");
        return Decision.accept(name, input.trim() + " verarbeitet");
    }
}

Die Klasse liefert Metadaten und eine einfache Eingabeprüfung. Sie ist ein Lernbaustein für Modulgrenzen und Pattern-Markierung, nicht die Implementierung eines produktiven Strangler-Routings.

Die richtige Lesart

  1. Nutze die Modulnamen als Modernisierungslandkarte.
  2. Nutze DemoProcessFacade als Reihenfolge der Arbeitsschritte.
  3. Suche für echte Umsetzung nach Netzwerkaufrufen, Datenzugriff, Mapping, Transaktionsgrenzen und Tests.
  4. Fehlen diese, bleibt der Baustein didaktisch oder konzeptionell.

6. Geführter Durchstich 4: Master 25 – End-to-End-Klammer

Der Maven-Reaktor von Master 25 enthält genau drei Module: api-contracts, e2e-orchestrator und runnable-smoke.

package com.aydin.master25.e2e;

import com.aydin.master25.contracts.CorrelationId;
import com.aydin.master25.contracts.E2eStep;
import java.util.ArrayList;
import java.util.List;

// PATTERN: Facade - offers one simple method for a complex cross-system flow.
public class E2eOrchestrator {
    public List<E2eStep> run(CorrelationId correlationId) {
        List<E2eStep> steps = new ArrayList<>();
        // PATTERN: Pipeline - each step enriches the same end-to-end business story.
        steps.add(new E2eStep("Portal", "create scenario", "scenario accepted " + correlationId.value()));
        steps.add(new E2eStep("Gateway", "route request", "correlation and idempotency checked"));
        steps.add(new E2eStep("Insurance", "issue policy", "policy demo created"));
        steps.add(new E2eStep("Banking", "capture payment", "ledger entry simulated"));
        steps.add(new E2eStep("ERP", "create invoice", "invoice demo created"));
        steps.add(new E2eStep("Logistics", "send document", "document shipment simulated"));
        steps.add(new E2eStep("Legacy", "compare old data", "anti-corruption mapping simulated"));
        steps.add(new E2eStep("Observability", "collect telemetry", "audit trail complete"));
        return steps;
    }
}

Die Main-Klasse führt den Orchestrator aus:

package com.aydin.master25.smoke;

import com.aydin.master25.contracts.CorrelationId;
import com.aydin.master25.e2e.E2eOrchestrator;

// PATTERN: Command - executable entry point for the consolidated demo flow.
public class RunnableSmokeApp {
    public static void main(String[] args) {
        var flow = new E2eOrchestrator().run(new CorrelationId("master-25-demo-001"));
        System.out.println("MASTER 25 END-TO-END RUNTIME SMOKE");
        flow.forEach(step -> System.out.printf("%-14s | %-22s | %s%n", step.system(), step.action(), step.result()));
        System.out.println("STATUS: OK");
    }
}

Der Ablauf ist ausführbar und liefert eine konsistente End-to-End-Geschichte. Die Texte policy demo created, ledger entry simulated und anti-corruption mapping simulated zeigen aber ausdrücklich: Es sind keine echten HTTP-, Kafka-, Datenbank- oder Legacy-Aufrufe. Master 25 ist eine Integrationslandkarte in ausführbarer Form, kein verteilter Systemtest.

7. Betrieb verstehen: konkrete Dateien aus Master 15

Backup-Beispiel:

Pfad: 15_DOCKER_K8S_PG_SEC_Plattform/platform/database/postgres/backup.sh

#!/usr/bin/env bash
set -euo pipefail
: "${PGHOST:=localhost}" "${PGDATABASE:=demo}" "${PGUSER:=demo}"
pg_dump -Fc -h "$PGHOST" -U "$PGUSER" "$PGDATABASE" > "backup-${PGDATABASE}-$(date +%Y%m%d-%H%M%S).dump"

Das Skript verwendet pg_dump im Custom-Format und bricht bei Fehlern ab. Für Produktion fehlen unter anderem Rotation, Verschlüsselung, Offsite-Speicherung, Restore-Test, Monitoring und Aufbewahrungsregeln.

NetworkPolicy-Beispiel:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: app-to-db-storage-only
spec:
  podSelector:
    matchLabels:
      tier: app
  policyTypes: [Egress]
  egress:
    - to:
        - podSelector: { matchLabels: { tier: database } }
      ports:
        - protocol: TCP
          port: 5432
    - to:
        - podSelector: { matchLabels: { tier: storage } }
      ports:
        - protocol: TCP
          port: 9000

Die Policy beschränkt Egress eines Pods mit tier: app auf Datenbank-Port 5432 und Storage-Port 9000. Sie ist konkrete Kubernetes-Syntax. Ob sie in einem Cluster wirksam ist, hängt zusätzlich von Namespace, Labels, CNI-Unterstützung und ergänzenden Ingress-/DNS-Regeln ab.

8. So liest du jede beliebige Master-Seite

Schritt Öffnen Prüffrage
1 MASTER_LEHRBUCH.html Welche fachliche Geschichte wird behauptet?
2 Workspace-pom.xml Welche Module existieren wirklich?
3 RUNNABLE.html und Main-Klasse Was wird tatsächlich ausgeführt?
4 Domain-/Application-Code Wo werden Regeln und Use Cases umgesetzt?
5 Adapter-/Runtime-Code Wo werden Technik und Framework angebunden?
6 Deploy-/Platform-Dateien Welche Betriebsannahmen sind konkret?
7 Tests und Reports Was wurde wirklich geprüft?
8 DEMO_VS_PRODUKTION.html Welche Lücken bleiben bis Produktion?

9. Ein ehrlicher 7-Tage-Lernplan

Tag Ziel Konkretes Artefakt
1 Maven und Schichten Master 1 v01-modular-baseline/pom.xml, Order.java
2 Use Case und Port PlaceOrderUseCase.java, OrderRepository.java
3 Adapter und Runtime InMemoryOrderRepository.java, OrderController.java
4 Fachprozess Master 8 InsuranceProcessFacade.java, QuoteService.java
5 Legacy einordnen Master 14 DemoProcessFacade.java und Modulstruktur
6 Plattform lesen Master 15 Backup-Skript und NetworkPolicy
7 End-to-End kritisch bewerten Master 25 E2eOrchestrator.java und RunnableSmokeApp.java

10. Abschlussfragen

⌂ Cockpit