meldestelle/docs/01_Architecture/adr/0015-context-map-de.md
Stefan Mogeritsch 354bd49de6 feat: integrate new desktop shell and extend backend & ADRs
- Added `meldestelle-desktop` module using JVM/Compose Desktop, registered in `settings.gradle.kts`.
- Integrated new screens and desktop navigation into core: `Veranstaltungen`, `TurnierDetail`, etc.
- Expanded backend with `ExposedFunktionaerRepository` in `officials-infrastructure`.
- Completed ADRs for bounded context mapping (`ADR-0014`) and context map (`ADR-0015`).
- Updated and extended project documentation with session logs and architecture decisions.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-03-24 18:22:15 +01:00

17 KiB

type id status owner last_update
ADR ADR-0015 ACTIVE Lead Architect 2026-03-24

ADR-0015: Context Map & Integration Patterns

Status

Akzeptiert

Kontext

Nach der Definition der 6 Bounded Contexts (→ ADR-0014) müssen die Beziehungen zwischen den Contexts explizit dokumentiert werden. Eine Context Map beschreibt:

  • Welche Contexts miteinander kommunizieren
  • In welche Richtung Abhängigkeiten fließen
  • Welches Integration Pattern verwendet wird
  • Wo Anti-Corruption Layers (ACL) notwendig sind

Ohne eine explizite Context Map entstehen implizite Abhängigkeiten, die die Unabhängigkeit der Contexts untergraben und die Offline-First-Strategie gefährden.

Entscheidung

Context Map (ASCII-Diagramm)

┌─────────────────────────────────────────────────────────────────────────────┐
│                         EXTERNE SYSTEME                                     │
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  ZNS (Zentrales Nennungs-System / OEPS)   [Upstream / Big Ball]    │   │
│   └──────────────────────────┬──────────────────────────────────────────┘   │
│                              │ ACL (A-Satz / B-Satz Import)                │
│                              ▼                                              │
│   ┌──────────────────────────────────────────────────────────────────────┐  │
│   │  Keycloak (Identity Provider)             [Upstream / Conformist]   │  │
│   └──────────────────────────┬───────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘
                               │
                               │ JWT / OIDC
                               ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                         INTERNE CONTEXTS                                    │
│                                                                             │
│  ┌──────────────────────┐        ┌──────────────────────────────────────┐   │
│  │   identity-context   │◄───────│          (alle Contexts)             │   │
│  │   [Generic Domain]   │  OHS   │  prüfen Berechtigungen via Token     │   │
│  └──────────────────────┘        └──────────────────────────────────────┘   │
│                                                                             │
│  ┌──────────────────────┐  ACL   ┌──────────────────────────────────────┐   │
│  │    actor-context     │◄───────│           ZNS (extern)               │   │
│  │  [Supporting Domain] │        └──────────────────────────────────────┘   │
│  │                      │                                                   │
│  │  DomReiter           │  CL/SK ┌──────────────────────────────────────┐   │
│  │  DomPferd            │───────►│       registration-context           │   │
│  │  DomFunktionär       │        │         [Core Domain]                │   │
│  │  DomVerein           │        │                                      │   │
│  └──────────────────────┘        │  DomNennung                          │   │
│                                  │  DomNennungsTransfer                 │   │
│  ┌──────────────────────┐  CL/SK │  DomAbteilung                        │   │
│  │ event-management-    │───────►│                                      │   │
│  │     context          │        └──────────────┬───────────────────────┘   │
│  │  [Supporting Domain] │                       │                           │
│  │                      │                       │ Domain Events             │
│  │  DomVeranstaltung    │                       │ (NennungErstellt,         │
│  │  DomTurnier          │                       │  NennungStorniert,        │
│  │  DomAusschreibung    │                       │  NennungTransferiert)     │
│  └──────────────────────┘                       │                           │
│                                                 ▼                           │
│  ┌──────────────────────┐        ┌──────────────────────────────────────┐   │
│  │   billing-context    │◄───────│       competition-context            │   │
│  │  [Generic Domain]    │  ACL   │       [Supporting Domain]            │   │
│  │                      │        │                                      │   │
│  │  DomKonto            │        │  DomBewerb                           │   │
│  │  DomGebühr           │        │  DomAbteilung                        │   │
│  │  DomAbrechnung       │        │  DomStartliste                       │   │
│  └──────────────────────┘        │  DomErgebnis                         │   │
│                                  └──────────────────────────────────────┘   │
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │  series-context  [Phase 2+ — Architektur vorbereitet, nicht aktiv]   │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘

Legende:

  • ACL = Anti-Corruption Layer
  • CL/SK = Customer/Supplier mit Shared Kernel (gemeinsame IDs)
  • OHS = Open Host Service (standardisiertes Interface)
  • = Abhängigkeitsrichtung (Downstream → Upstream)

Beziehungen im Detail

1. ZNS (extern) → actor-context

Pattern: Upstream/Downstream mit Anti-Corruption Layer (ACL)

Eigenschaft Beschreibung
Richtung ZNS ist Upstream (Datenquelle), actor-context ist Downstream
Protokoll Datei-Import (A-Satz / B-Satz, proprietäres Format)
ACL-Aufgabe Übersetzung von ZNS-Datenformaten in interne Domänenmodelle
Offline-Verhalten ZNS-Daten werden lokal gecacht; Import läuft asynchron
Kritische Regel Satznummer ist primärer Schlüssel; Lebensnummer und Kopfnummer sind nicht als DB-Schlüssel geeignet (ZNS-Inkonsistenzen bekannt)

ACL-Verantwortlichkeiten:

  • Normalisierung inkonsistenter Felder (z.B. Farbe "Braun" vs. "Brauner")
  • Generierung interner IDs für ausländische Pferde ohne UELN
  • Validierung und Ablehnung korrupter ZNS-Datensätze mit Protokollierung

2. actor-contextregistration-context

Pattern: Customer/Supplier mit Shared Kernel (gemeinsame IDs)

Eigenschaft Beschreibung
Richtung actor-context ist Upstream (Stammdaten-Lieferant)
Shared Kernel ReiterId (Satznummer), PferdId (Satznummer) als gemeinsame Referenz-IDs
Kommunikation Synchron: Lookup bei Nennungs-Erstellung; Asynchron: Sperrlisten-Updates
Offline-Verhalten registration-context hält lokale Kopie der benötigten Akteur-Daten
Kritische Regel registration-context darf Akteur-Daten nicht direkt mutieren (nur lesen)

3. event-management-contextregistration-context

Pattern: Customer/Supplier mit Shared Kernel (gemeinsame IDs)

Eigenschaft Beschreibung
Richtung event-management-context ist Upstream (Turnier-/Bewerbs-Struktur)
Shared Kernel TurnierId, BewerbId als gemeinsame Referenz-IDs
Kommunikation Synchron: Bewerbs-Lookup bei Nennungs-Erstellung
Kritische Regel Nennungen können nur für existierende Bewerbe erstellt werden

4. registration-contextcompetition-context

Pattern: Upstream/Downstream via Domain Events

Eigenschaft Beschreibung
Richtung registration-context ist Upstream (Ereignis-Quelle)
Events NennungErstelltEvent, NennungStorniertEvent, NennungTransferiertEvent
Kommunikation Asynchron (Event Bus / lokale Event Queue)
Aufgabe Downstream competition-context baut Startlisten aus Nennungs-Events auf
Offline-Verhalten Events werden lokal persistiert und bei Verbindung synchronisiert

5. registration-contextbilling-context

Pattern: Upstream/Downstream via Domain Events mit ACL

Eigenschaft Beschreibung
Richtung registration-context ist Upstream (Gebühren-Auslöser)
Events NennungErstelltEvent (löst Nenngeld aus), NennungStorniertEvent (Gutschrift), GebührenVerzichtEvent
ACL-Aufgabe Übersetzung von Nennungs-Events in Gebühren-Buchungen
Kritische Regel Sportförderbeitrag und Tierwohl-Euro fallen pro Start an (nicht pro Nennung)

6. competition-contextbilling-context

Pattern: Upstream/Downstream via Domain Events mit ACL

Eigenschaft Beschreibung
Richtung competition-context ist Upstream
Events StartErfolgreich (löst Sportförderbeitrag + Tierwohl-Euro aus)
ACL-Aufgabe Übersetzung von Start-Events in Gebühren-Buchungen

7. Keycloak → alle Contexts

Pattern: Upstream/Downstream, Conformist (alle Contexts passen sich Keycloak an)

Eigenschaft Beschreibung
Richtung Keycloak ist Upstream (Identity Provider)
Protokoll OIDC / JWT-Token
Kommunikation Synchron: Token-Validierung bei jedem Request
Offline-Verhalten Token-Caching mit konfigurierbarer TTL; Offline-Modus mit eingeschränkten Rechten

Anti-Corruption Layer (ACL) — Implementierungsrichtlinien

Jeder ACL wird als eigenständiges Modul innerhalb des Downstream-Contexts implementiert:

actor-context/
  └── infrastructure/
        └── zns/
              ├── ZnsImportService.kt       # Orchestrierung
              ├── ZnsAkteurMapper.kt        # Übersetzung ZNS → Dom*
              ├── ZnsValidationFilter.kt    # Ablehnung korrupter Daten
              └── ZnsImportProtokoll.kt     # Audit-Log aller Imports

Prinzipien:

  1. Der ACL übersetzt immer in die interne Ubiquitous Language — niemals umgekehrt
  2. Fehlerhafte externe Daten werden protokolliert und übersprungen (kein Systemabsturz)
  3. Der ACL ist der einzige Ort, der das externe Datenformat kennt

Offline-First Integration

Da die Anwendung als Desktop-App (Offline-First) betrieben wird, gelten folgende Regeln:

Szenario Verhalten
ZNS nicht erreichbar Lokaler Cache wird verwendet; Import-Status wird angezeigt
Nennungs-Erstellung offline Lokal gespeichert; Events werden bei Sync übertragen
Keycloak nicht erreichbar Gecachter Token wird verwendet (TTL-basiert)
Konflikt bei Sync Optimistic Locking (409) + manuelle Auflösung (→ ADR-0013)

Konsequenzen

Positive

  • Explizite Abhängigkeiten: Alle Context-Beziehungen sind dokumentiert und nachvollziehbar
  • Schutz der Kern-Domäne: registration-context ist durch ACLs von externen Systemen isoliert
  • Offline-Fähigkeit: Jede Integration ist auf Offline-Betrieb ausgelegt
  • Erweiterbarkeit: series-context kann in Phase 2+ als reiner Downstream-Consumer hinzugefügt werden

Negative

  • Komplexität: ACLs und Event-Übersetzungen erhöhen den initialen Implementierungsaufwand
  • Eventual Consistency: Zwischen registration-context und competition-context gibt es keine sofortige Konsistenz

Neutral

  • Die Context Map ist ein lebendes Dokument und wird mit jeder neuen Integration aktualisiert

Betrachtete Alternativen

Direkte Context-zu-Context-Aufrufe (abgelehnt)

Direkte synchrone Aufrufe zwischen Contexts würden enge Kopplung erzeugen und die Offline-Fähigkeit untergraben.

Shared Database (abgelehnt)

Eine gemeinsame Datenbank für alle Contexts würde die Context-Grenzen aufweichen und die unabhängige Entwicklung verhindern.

Referenzen