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:
@@ -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. ✅
|
||||
Reference in New Issue
Block a user