feat(MP-27): backend consolidation, gateway routing & service dockerfiles

Summary
- Backend Services (Entries, Results, Scheduling) haben Dockerfiles.
- Docker Compose Orchestrierung steht (DB + Gateway + Services).
- Gateway Routing für `entries-service` implementiert (StripPrefix, Path Rewrites).
- Health-Checks und 409-Conflict-Demo Endpunkt verifiziert.

Verification
- `docker compose up --build` -> Success
- `curl http://localhost:8081/api/entries` -> 200 OK (routed through Gateway)

Ref: MP-27
This commit is contained in:
2025-12-08 11:39:43 +01:00
parent b4769d89bc
commit 114236c8d9
12 changed files with 368 additions and 0 deletions
+188
View File
@@ -0,0 +1,188 @@
## Frontend-Architektur
# Frontend-Architektur
**Architektur-Stil:** Feature-First, Clean Architecture, Kotlin Multiplatform (KMP)
## 1. Management Summary
Das Frontend wird als **modulare Kotlin Multiplatform (KMP) Anwendung** entwickelt. Ziel ist eine strikte Trennung von
technischer Basis (`shared`) und fachlichen Funktionen (`features`). Die Architektur ist **"Offline-Ready"** konzipiert:
Durch die konsequente Nutzung des Repository-Patterns kann die Datenquelle später transparent von "Online-Only" (API)
auf "Local-First" (Datenbank + Sync) umgestellt werden, ohne die Benutzeroberfläche (UI) anpassen zu müssen.
## 2. Die Modul-Struktur (Gradle)
Die Anwendung ist nicht monolithisch, sondern in fachliche Module geschnitten ("Feature-First").
- **`:clients:app` (Der Container)**
- **Rolle:** Der Einstiegspunkt ("Main").
- **Aufgabe:**
Initialisierung von Koin (Dependency Injection).
Globales Theming (Material3).
High-Level Navigation (Routing zwischen Features).
Verbindet alle Feature-Module.
- **`:clients:shared` (Das Fundament)**
- **Rolle:** Die gemeinsame Bibliothek für alle Features.
- **Inhalt:**
**DI (Dependency Injection):** Zentrale Koin-Module (NetworkModule, CoreModule).
**Network:** Konfigurierter HttpClient (Singleton).
**Domain Core:** Basis-Modelle (Resource<T>, ApiError, User).
**UI Kit:** Gemeinsame Komponenten (LoadingSpinner, ErrorView), Typography, Colors.
- **Regel:** Hier liegt keine Fachlogik eines spezifischen Features (keine Pferdedaten, keine Nennungen).
- **`:clients:*-feature` (Die Fachlichkeit)**
- **Beispiele:** `:clients:auth-feature`, `:clients:registry-feature`, `:clients:events-feature`.
- **Rolle:** Kapselt einen kompletten fachlichen Bereich.
- **Inhalt:** Eigene Screens, ViewModels und spezifische Use-Cases.
## 3. Die Schichten-Architektur (Innerhalb eines Moduls)
Jedes Modul (besonders `shared` und die Features) folgt einer strikten 3-Schichten-Architektur. Das garantiert
Testbarkeit und Austauschbarkeit.
### 1️⃣ Presentation Layer (UI)
- **Technologie:** Compose Multiplatform.
- **Komponenten:** `Screen` (Composable Functions) und `ViewModel` (State-Holder).
- **Verantwortung:**
Zeigt Daten an (Reagiert auf State).
Nimmt User-Input entgegen.
**Weiß NICHT**, woher die Daten kommen (Netzwerk oder DB).
Nutzt Repositories via Koin Injection (`koinInject()`).
### 2️⃣ Domain Layer (Die Logik)
- **Komponenten:** `Repository Interface`, `Models`.
- **Verantwortung:**
Definiert **WAS** getan werden kann (z.B. `checkSystemStatus()`).
Ist komplett unabhängig von Frameworks (reines Kotlin).
Nutzt `Resource<T>` Wrapper (`Success`, `Error`, `Loading`) für den State-Transport.
### 3️⃣ Data Layer (Die Umsetzung)
- **Komponenten:** `Repository Implementation`, `API-DTOs`, `Database-Entities`.
- **Verantwortung:**
Entscheidet **WIE** Daten geholt werden.
**Aktuell (Online):** Ruft Ktor Client auf.
**Zukunft (Offline/LAN):** Prüft lokale SQLite DB, synchronisiert im Hintergrund.
Mappt rohe API-Daten (DTOs) in saubere Domain-Modelle.
### 4. Technische Kern-Konzepte
**💉 Dependency Injection (Koin)**
Wir nutzen Koin als "Klebstoff".
- Module exportieren ihre Funktionalität via `val myModule = module { single { ... } }`.
- Die `clients:app` sammelt alle Module ein und startet den Container.
- **Vorteil:** Repositories und der HTTP-Client müssen nicht manuell herumgereicht werden.
**🌐 Networking (Ktor)**
Ein zentraler `HttpClient` im `NetworkModule` (`clients:shared`).
- Konfiguriert mit JSON-Serialization.
- Zentrale Base-URL Steuerung (via `AppConfig` umschaltbar für LAN/Dev/Prod).
- Timeout- und Logging-Handling an einer Stelle.
**🔄 Datenfluss (Unidirectional Data Flow)**
1. **UI:** Trigger Event (Button Click).
2. **ViewModel/Scope:** Ruft Repository auf (`launch { repo.getData() }`).
3. **Repository:** Liefert `Resource.Loading` -> `Resource.Success(data)`.
4. **UI:** Rendert den neuen State.
### 5. Strategie für Offline & LAN-Fähigkeit (Zukunft)
Die aktuelle Architektur ist **vorbereitet** für die Offline-Anforderungen der großen Turniere.
**Die Transition (Schritt-für-Schritt):**
1. **Phase 1 (Jetzt):** PingRepositoryImpl ruft direkt httpClient.get() auf.
2. **Phase 2 (Offline):**
Wir fügen **SQLDelight** (lokale DB) hinzu.
Die `PingRepositoryImpl` wird geändert (ohne dass die UI es merkt!):
```Kotlin
fun getData() {
val localData = db.dao.getAll()
if (localData.isEmpty()) {
val remote = api.getAll()
db.dao.insert(remote)
return remote
}
return localData
}
```
3. **Phase 3 (Sync):** Ein Hintergrund-Worker (`WorkManager` oder `Coroutine`) synchronisiert lokale Änderungen mit dem
Server, sobald das LAN verfügbar ist.
### 6. Zusammenfassung für Entwickler
Wenn du ein neues Feature (z.B. "Pferde anzeigen") baust:
1. **Domain:** Erstelle Horse Model und HorseRepository Interface.
2. **Data:** Erstelle HorseRepositoryImpl. Injiziere den HttpClient.
3. **DI:** Registriere das Repository im Koin-Modul.
4. **UI:** Erstelle HorseListScreen. Injiziere das Repository.
5. Fertig.
Diese Struktur ist sauber, skalierbar und bereit für den professionellen Einsatz beim OEPS. ✅
+14
View File
@@ -0,0 +1,14 @@
## Epic 1: Big‑Bang vorbereiten – Snapshot und Branching
* Zusammenfassung: Snapshot des aktuellen Zustands, Tag setzen, Big‑Bang‑Branch erstellen
* Beschreibung:
* Ziel: Den aktuellen Projektstand einfrieren, um die anschließende große Umstrukturierung nachvollziehbar zu machen.
* Schritte:
1. PR „chore: snapshot pre‑refactor state“ auf `main` erstellen und mergen.
2. Git‑Tag `v0-pre-refactor` setzen.
3. Branch `refactor/big-bang-architecture` anlegen und als Arbeitsbasis verwenden.
* Artefakte:
* PR‑Link, Tag‑Nachweis.
* Definition of Done (DoD):
* PR gemergt, Tag `v0-pre-refactor` existiert (git log / remote tags sichtbar).
* Branch `refactor/big-bang-architecture` öffentlich verfügbar.
+27
View File
@@ -0,0 +1,27 @@
## Epic 2: Repository‑Struktur auf Meldestellen‑Domäne umstellen
* Zusammenfassung: Neues Skeleton und physisches Umziehen der Module/Ordner
* Beschreibung:
* Ziel: Einführen der Zielstruktur gemäß Domäne (Meldestelle, ÖTO/FEI) für Frontend, Backend und Docker.
* Soll‑Struktur (Top‑Level):
* `frontend/` (shells, features, core)
* `backend/` (gateway, discovery, services)
* `docker/` (docker-compose.yml, .env.example)
* `docs/` (adr, ARCHITECTURE.md)
* Geplanter Umzug:
* Frontend:
* `clients/app` → `frontend/shells/meldestelle-portal`
* `clients/shared/common-ui` → `frontend/core/design-system`
* `clients/shared/navigation` → `frontend/core/navigation`
* Backend:
* `services|domains|infrastructure|platform|core` → konsolidieren unter `backend/`:
* `backend/services/*`
* `backend/gateway`, `backend/discovery`
* Docker:
* `compose.yaml` → `docker/docker-compose.yml`
* Pro Service ein eigener `Dockerfile` im jeweiligen Service‑Ordner
* Definition of Done (DoD):
* Verzeichnis‑Skeleton vorhanden und committed.
* Dateien physisch verschoben; alle relativen Pfade in Gradle/Konfigurationen angepasst (oder bekannte Fehlerliste
dokumentiert).
* `docker/docker-compose.yml` vorhanden; `.env.example` erstellt.
+14
View File
@@ -0,0 +1,14 @@
## Epic 3: Gradle/Build Governance zentralisieren
* Zusammenfassung: Version Catalog, Settings, Build‑Konventionen
* Beschreibung:
* Ziel: Einheitliche Build‑Basis für alle Module (KMP/JVM), zentrale Versionierung und klare Projekt‑Includes.
* Schritte:
1. `gradle/libs.versions.toml` als Single Source of Truth etablieren.
2. `settings.gradle.kts` an neue Struktur anpassen (Includes für Frontend‑Core, ‑Features, ‑Shells;
Backend‑Services).
3. Build‑Konventionen konsolidieren (`buildSrc` oder `gradle/plugins`): Kotlin, Compose, Detekt, KTLint.
* Definition of Done (DoD):
* `./gradlew projects` zeigt die neue Modul‑Hierarchie ohne verwaiste Einträge.
* Alle Subprojekte beziehen Versionen aus `libs.versions.toml` (keine harten Versionsnummern in Buildskripten).
* Lint/Detekt laufen in CI lokal erfolgreich.
+21
View File
@@ -0,0 +1,21 @@
## Epic 4: Frontend Core etablieren (Network, Local‑DB, Design‑System, Domain)
* Zusammenfassung: Koin/Ktor‑Client, SQLDelight, Design‑System‑Konsolidierung, Shared Domain Models
* Beschreibung:
* Ziel: Eine stabile, wiederverwendbare Basis für alle Features/Shells schaffen.
* Deliverables:
* `frontend/core/network`:
* Ktor `HttpClient` mit Plugins: Auth, Retry, JSON, Timeouts, Logging.
* Koin‑Module mit `single(named("apiClient"))` Export.
* `frontend/core/local-db`:
* SQLDelight‑Setup (KMP), Schema‑Ordner, `1.sqm` Migration, Build‑Konfig.
* Konvention: Keine Inline‑SQL in Business‑Code; Nutzung der generierten Queries.
* `frontend/core/design-system`:
* Konsolidierte `AppTheme`, Komponenten, Tokens.
* `frontend/core/domain`:
* Gemeinsame Modelle/IDs (z. B. `Turnier`, `Pruefung`, `Start`, `ReiterId`, `PferdId`, `Lizenz` …).
* Definition of Done (DoD):
* Kein Vorkommen manueller `Authorization`‑Header im Code (nur DI‑`apiClient`).
* SQLDelight generiert Code; eine Demo‑Query kompiliert für das Web‑Target.
* Design‑System kompiliert; `AppTheme` nutzbar in Shell/Feature‑Sample.
* `core/domain` wird von Features konsumiert, ohne Feature→Feature Abhängigkeiten.
+17
View File
@@ -0,0 +1,17 @@
## Epic 5: Feature‑Pilot – Nennungs‑Management (Vertical Slice)
- Zusammenfassung: Erstes Feature in Zielstruktur mit Route, UI, Data, Domain, DI
- Beschreibung:
- Ziel: Funktionsfähiger, isolierter Slice für Nennungen (Turnier‑bezogen), inkl. Offline/Sync‑Pfad.
- Struktur: `frontend/features/nennungs-management/{api,ui,data,domain,di}`
- Funktionen (Minimum):
- Liste Nennungen für `turnierId` anzeigen (UI liest aus Local‑DB; initialer Sync).
- Anlegen/Ändern einer Nennung lokal; Sync zum Server.
- Konfliktpfad: Bei veralteter `version` → Server 409; UI Toast + automatischer Refresh.
- Navigation/Route:
- `meldestelle/nennungen/turnier/{turnierId}` als EntryPoint.
- Definition of Done (DoD):
- Shell `meldestelle-portal` kann Route aufrufen; UI rendert Daten aus Local‑DB.
- API‑Call nutzt DI‑`apiClient`.
- `lastSyncedAt` steuert Freshness‑Indikator (grün/gelb/rot) im UI.
- Konfliktfall 409 nachweisbar (Mock/Backend) und UI reagiert gemäß Guideline.
+13
View File
@@ -0,0 +1,13 @@
## Epic 6: Shell – Meldestelle‑Portal (JS/Wasm)
- Zusammenfassung: Exekutierbare Web‑Shell mit expliziten Feature‑Dependencies
- Beschreibung:
- Ziel: Eine Shell, die nur benötigte Features bundelt (Tree‑Shaking wirksam) und die Navigation kapselt.
- Schritte:
1. Entry Point/Bootstrap der Shell anlegen (`frontend/shells/meldestelle-portal`).
2. Nur benötigte Features als Gradle‑Dependencies einbinden (Pilot: `nennungs-management`).
3. Bundle‑Report aktivieren; Code‑Splitting konfigurieren.
- Definition of Done (DoD):
- `./gradlew :frontend:shells:meldestelle-portal:build` erfolgreich.
- Bundle‑Report zeigt, dass ausschließlich integrierte Features im Output sind.
- Navigation aus der Shell zu Feature‑Routen funktioniert.
+18
View File
@@ -0,0 +1,18 @@
## Epic 7: Backend‑Konsolidierung – Services & Gateway
- Zusammenfassung: Services domänenspezifisch schneiden, Gateway verankern, Compose lauffähig
- Beschreibung:
- Ziel: Minimales, aber kohärentes Backend gemäß Zielstruktur – startfähig via Docker Compose.
- Services (erste Iteration):
- `entries-service` (Nennungen/Validierung),
- `results-service` (Ergebnisse),
- `scheduling-service` (Zeit/Abteilungen),
- plus `gateway` (Auth/Routing).
- Anforderungen:
- Pro Service eigener `Dockerfile` im Service‑Ordner.
- Mindestens ein Endpunkt pro Service (Stub akzeptabel), 409‑Konfliktpfad im `entries-service`.
- Compose: DB + Gateway + `entries-service` startbar.
- Definition of Done (DoD):
- `docker/docker-compose.yml` gestartet → Services erreichbar (Health/HTTP 200/Stub‑Daten).
- Endpoint für 409‑Konflikt getestet (z. B. Postman/HTTP‑Test dokumentiert).
- Gateway leitet Requests korrekt weiter.
+12
View File
@@ -0,0 +1,12 @@
## Epic 8: Architektur‑Guards und CI – Regeln durchsetzen
- Zusammenfassung: Detekt/KTLint Regeln, Dependency Checks, Bundle Budgets
- Beschreibung:
- Ziel: Die Architekturregeln technisch erzwingen, um Regressionen zu vermeiden.
- Guards:
- Verbot Feature→Feature Dependencies (nur → `frontend/core:*`).
- Verbot manueller `Authorization`‑Header im Code (nur DI‑`apiClient`).
- CI: Dependency‑Graph‑Diff, Bundle‑Size‑Budget je Shell, `docker compose config` Validierung.
- Definition of Done (DoD):
- CI bricht bei Verstößen, Berichte werden erzeugt.
- Auf `main` grüner Build mit aktiven Guards.
+13
View File
@@ -0,0 +1,13 @@
## Epic 9: Dokumentation & ADRs formalisieren
- Zusammenfassung: ADR‑Template, Entscheidungen festschreiben, Architecture Guide aktualisieren
- Beschreibung:
- Ziel: Entscheidungen nachvollziehbar machen und Onboarding erleichtern.
- Schritte:
1. ADR‑Template `docs/adr/ADR-000-template.md` anlegen.
2. ADRs erstellen für: Koin, SQLDelight, Optimistic Locking, Freshness‑UI, Core‑Domain, Feature‑Isolation über
Routen.
3. `docs/ARCHITECTURE.md`: Mapping Vision ↔ Repo, Rollen, Routenbeispiele (Meldestelle, Richter, Zeitnahme).
- Definition of Done (DoD):
- Mindestens 5 ADRs vorhanden und verlinkt.
- `ARCHITECTURE.md` erlaubt Onboarding in < 30 Minuten (interner Review bestanden).
+6
View File
@@ -0,0 +1,6 @@
## Ergänzende Hinweise (Optionen)
- Labels/Tags: `architecture`, `big-bang`, `frontend`, `backend`, `docker`, `docs`.
- Priorisierung: 1 → 9 in ungefährer Reihenfolge, wobei 2–4 parallelisierbar sind.
- Zeitbox für Epics definieren (z. B. 1–2 Wochen je Epic in früher Phase) und nach jedem Epic Zwischenrelease (Tag)
setzen.