docs: restructure and streamline sprint execution order
- Consolidated and removed redundant steps in `SPRINT_EXECUTION_ORDER.md`. - Simplified descriptions and roadmap formatting for improved clarity. - Updated progress and dependencies to align with Phase 8 objectives. - Adjusted role-specific roadmaps to reflect the latest sprint updates. Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
@@ -1,163 +1,117 @@
|
||||
# 🎨 [Frontend Expert] — Schritt-für-Schritt Roadmap
|
||||
# 🎨 [Frontend Expert] — Zwischenstand & Roadmap
|
||||
|
||||
> **Stand:** 3. April 2026
|
||||
> **Rolle:** KMP, Compose Desktop, State-Management, MVVM/UDF, Backend-Anbindung
|
||||
> **Rolle:** KMP, Compose Desktop, State-Management, Navigation, Backend-Anbindung
|
||||
|
||||
---
|
||||
|
||||
## 🔴 Sprint A — Sofort (diese Woche)
|
||||
## ✅ Erledigte Sprints
|
||||
|
||||
- [x] **A-1** | ViewModel-Architektur definieren und Referenz-Implementierung umsetzen
|
||||
- [x] MVVM mit UDF (Unidirectional Data Flow) als verbindliches Muster festlegen
|
||||
- [x] `Intent`- und `State`-Klassen-Struktur definieren (Vorlage für alle anderen ViewModels)
|
||||
- [x] `VeranstalterViewModel` als vollständige Referenz-Implementierung umsetzen
|
||||
- [x] `State`-Klasse definieren
|
||||
- [x] `Intent`-Klasse (Sealed Class) definieren
|
||||
- [x] Business-Logik aus Composables herausziehen (keine `StoreV2`-Aufrufe mehr direkt in `onSaved`)
|
||||
- [x] Lokalen `remember`-State durch ViewModel-State ersetzen
|
||||
- [x] Ergebnis als Muster-Dokument in `docs/06_Frontend/` ablegen
|
||||
|
||||
Referenzen:
|
||||
- docs/06_Frontend/MVVM_UDF_Pattern.md (Regeln, Vorlage, Referenz-Code)
|
||||
- frontend/features/veranstalter-feature/src/commonMain/.../VeranstalterViewModel.kt
|
||||
- frontend/features/veranstalter-feature/src/jvmMain/kotlin/at/mocode/frontend/features/veranstalter/data/remote/DefaultVeranstalterRepository.kt
|
||||
- frontend/features/veranstalter-feature/src/jvmMain/.../VeranstalterAuswahlScreen.kt (nutzt ViewModel/Intents)
|
||||
### Sprint A — Abgeschlossen
|
||||
|
||||
- [x] **A-2** | Abteilungs-Logik im Bewerb-Dialog berücksichtigen
|
||||
- [x] Dialog enthält Abteilungs-Auswahl als Teil des „Bewerb anlegen“-Flows (im selben Modal)
|
||||
- [x] CSN-C-NEU: Automatischer Vorschlag der Pflicht-Teilung mit 4 Abteilungen:
|
||||
- [x] Ohne Lizenz · R1
|
||||
- [x] Ohne Lizenz · R2+
|
||||
- [x] Mit Lizenz · R1
|
||||
- [x] Mit Lizenz · R2+
|
||||
- [x] Beim Auto-Vorschlag Default-Setzung des Abteilungs-Typs auf `SEPARATE_SIEGEREHRUNG`
|
||||
- [x] Manuelle Umschaltung des Abteilungs-Typs möglich: `SEPARATE_SIEGEREHRUNG` oder `ORGANISATORISCH`
|
||||
- [x] UX: Bei erkanntem Typ „CSN-C-NEU“ wird ein AssistChip „Pflicht-Teilung vorgeschlagen“ angezeigt
|
||||
- [x] **A-1** | ViewModel-Architektur definieren & Referenz-Implementierung
|
||||
- [x] MVVM mit UDF als verbindliches Muster festgelegt
|
||||
- [x] `Intent`/`State`-Struktur definiert (Sealed Classes)
|
||||
- [x] `VeranstalterViewModel` als vollständige Referenz-Implementierung
|
||||
- [x] Muster-Dokument in `docs/06_Frontend/` abgelegt
|
||||
|
||||
Akzeptanzkriterien:
|
||||
- [x] Der „Bewerb anlegen“-Dialog zeigt ein Eingabefeld „Bewerbs-Typ“ und eine Auswahl für den Abteilungs-Typ (zwei Chips)
|
||||
- [x] Bei Eingabe „CSN-C-NEU“ wird automatisch die oben definierte 4er-Teilung in der Abteilungs-Liste angezeigt
|
||||
- [x] Die Auto-Teilung kann angezeigt werden, ohne dass der Dialog neu geöffnet werden muss (Live-Reaktion auf Eingabe)
|
||||
- [x] Der gesetzte Abteilungs-Typ ist im State sichtbar und wird vom Dialog korrekt reflektiert
|
||||
- [x] Kein Vorschlag für andere Typen; Liste bleibt leer bis manuell hinzugefügt/implementiert (aktuell out-of-scope)
|
||||
- [x] **A-2** | Abteilungs-Logik im Bewerb-Dialog
|
||||
- [x] CSN-C-NEU: Automatischer Vorschlag der Pflicht-Teilung mit 4 Abteilungen
|
||||
- [x] AssistChip „Pflicht-Teilung vorgeschlagen" bei erkanntem Typ
|
||||
- [x] Abteilungs-Typen `SEPARATE_SIEGEREHRUNG` / `ORGANISATORISCH` in UI
|
||||
|
||||
Referenzen (konkret):
|
||||
- frontend/features/turnier-feature/src/commonMain/kotlin/at/mocode/turnier/feature/presentation/BewerbAnlegenViewModel.kt
|
||||
- `BewerbAnlegenState`, `BewerbAnlegenIntent`, `applySuggestion()` (Auto-Vorschlag + Default-AbteilungsTyp)
|
||||
- frontend/features/turnier-feature/src/jvmMain/kotlin/at/mocode/turnier/feature/presentation/TurnierBewerbeTab.kt
|
||||
- `BewerbAnlegenDialog(...)`: Eingabe „Bewerbs-Typ“, AssistChip, Auswahl Abteilungs-Typ, Anzeige der vorgeschlagenen Abteilungen
|
||||
### Sprint B (Teilweise) — Abgeschlossene Punkte
|
||||
|
||||
---
|
||||
|
||||
## 🟠 Sprint B — Kurzfristig (nächste Woche)
|
||||
|
||||
- [x] **B-1** | ViewModels für alle V3-Screens umsetzen
|
||||
- [x] `TurnierViewModel`
|
||||
- [x] `BewerbViewModel` (inkl. Abteilungs-Logik via Dialog-VM)
|
||||
- [x] `PferdProfilViewModel`
|
||||
- [x] `ReiterProfilViewModel`
|
||||
- [x] `VereinsViewModel`
|
||||
- [x] `FunktionaerViewModel`
|
||||
- [x] **B-1** | ViewModels für alle V3-Screens
|
||||
- [x] `TurnierViewModel`, `BewerbViewModel`, `PferdProfilViewModel`
|
||||
- [x] `ReiterProfilViewModel`, `VereinsViewModel`, `FunktionaerViewModel`
|
||||
- [x] `AbteilungViewModel` (Startliste, Ergebnisse)
|
||||
|
||||
- [ ] **B-2** | Ktor-Clients und Repositories für Backend-Anbindung vorbereiten (V3-ready)
|
||||
- [x] KMP-Ktor-Client zentral konfigurieren (BaseURL, Auth, Timeout, JSON, Logging)
|
||||
- [x] BaseURL per `PlatformConfig.resolveApiBaseUrl()` (SSoT; JS: `globalThis.API_BASE_URL`/`window.location.origin`, JVM: `.env`/Systemprop) → frontend/core/network
|
||||
- [x] Auth: Bearer Token über Interceptor; Token-Quelle: core/auth (`AuthApiClient`) bzw. Session-Store → Header `Authorization: Bearer <token>`
|
||||
- [x] Timeouts: connect = 5s, request = 15s, socket = 30s (prod); dev je 2× höher; Retry-Policy max 2 Versuche bei 5xx/Network
|
||||
- [x] JSON: `kotlinx.serialization` mit `ignoreUnknownKeys=true`, `explicitNulls=false`, `coerceInputValues=true`
|
||||
- [x] Logging: `LogLevel.HEADERS` in dev, `LogLevel.NONE` in prod; PII nie loggen
|
||||
- [x] Engines: JVM=CIO, JS=fetch (ktor-client-js), WASM=js (vorbereitet)
|
||||
### Zusätzlich erledigt (Session 02.04.2026)
|
||||
|
||||
- [ ] Repository-Schnittstellen je Domäne definieren (Mock ↔ Real austauschbar)
|
||||
- [ ] Pakete/Orte (commonMain):
|
||||
- [x] `at.mocode.frontend.features.veranstalter.domain.VeranstalterRepository`
|
||||
- [x] `at.mocode.turnier.feature.domain.TurnierRepository`
|
||||
- [ ] `at.mocode.turnier.feature.domain.BewerbRepository`
|
||||
- [ ] `at.mocode.turnier.feature.domain.AbteilungRepository`
|
||||
- [ ] Operationen V3-Minimum: `list`, `getById`, `create`, `update`, `delete` (suspend)
|
||||
- [ ] Rückgabetypen: Domain-Modelle (nicht DTOs); Fehler als `Either<DomainError, T>` oder `Result<T>` (einheitlich festlegen)
|
||||
- [x] Navigation V2 / Back-Stack-System implementiert
|
||||
- [x] Profil-Cards mit Edit-Dialog (Veranstalter, Pferd, Reiter, Verein, Funktionär)
|
||||
- [x] Onboarding: State-Lift via `rememberSaveable` (Gerätename, Sicherheitsschlüssel)
|
||||
- [x] Veranstaltungs-Wizard: Bestätigungs-Dialog mit Daten-Vorschau vor finalem Anlegen
|
||||
- [x] Breadcrumbs und Zurück-Navigation korrigiert
|
||||
|
||||
- [ ] HTTP-Clients + DTOs + Mapper (jvmMain/jsMain)
|
||||
- [x] DTOs pro Feature in `.../data/remote/dto` mit `@Serializable` (Veranstalter)
|
||||
- [x] Mapper: `Dto ↔ Domain` in `.../data/mapper` (reine Funktionen) (Veranstalter)
|
||||
- [x] Client-Implementierungen in `.../data/remote/Default*Repository` mit Ktor (Veranstalter)
|
||||
- [x] Fehlerbehandlung: Mapping HTTP 401→`AuthError.Expired`, 403→`AuthError.Forbidden`, 404→`NotFound`, 409→`Conflict`, 5xx→`ServerError`
|
||||
---
|
||||
|
||||
- [ ] Koin-DI-Module
|
||||
- [x] `core/network`: `HttpClient`-Factory als `single { provideHttpClient(env) }`
|
||||
- [ ] Feature-Module binden `Repository`-Interfaces auf Default-Impl
|
||||
- [ ] `AuthApiClient` (core/auth) integrieren, Token-Provider injizierbar (z. B. `() -> String?`)
|
||||
## 🔴 Sprint B — Offen (höchste Priorität)
|
||||
|
||||
- [ ] Backend-Endpunkte verdrahten (gemäß contracts/ oder Backend-Services)
|
||||
- [x] Veranstalter: GET `/api/v3/veranstalter`, POST `/api/v3/veranstalter` ...
|
||||
- [ ] Turniere: GET `/api/v3/turniere`, ...
|
||||
- [ ] Bewerbe: GET `/api/v3/turniere/{id}/bewerbe`, ...
|
||||
- [ ] Abteilungen: GET `/api/v3/bewerbe/{id}/abteilungen`, ...
|
||||
- [ ] Versionierung: Präfix `/api/v3` zentral in `ApiRoutes`
|
||||
|
||||
- [ ] Migration: `StoreV2` schrittweise ablösen
|
||||
- [ ] ViewModels von `StoreV2` auf Repositories umschalten (Feature für Feature)
|
||||
- [ ] Parallelbetrieb per Toggle: `useRealBackend=true/false` (Konfig/DI)
|
||||
- [ ] Entfernen von `StoreV2`, sobald Feature vollständig migriert und stabil
|
||||
|
||||
- [ ] Qualität & DX
|
||||
- [ ] Akzeptanztests per Fake-Server (Mock Engine) gegen Repos (happy + error paths)
|
||||
- [ ] Network-Error-UX: Einheitliche Fehlermeldungen/Retry in ViewModels (UDF)
|
||||
- [ ] Dokumentation in `docs/06_Frontend/Networking.md` (Beispiele, Guidelines)
|
||||
|
||||
Referenzen (bestehend):
|
||||
- frontend/core/network/src/commonMain/.../PlatformConfig.kt (expect) und js/jvm actuals
|
||||
- frontend/core/auth/src/commonMain/.../AuthApiClient.kt (Keycloak/PKCE, Token-Erhalt)
|
||||
- frontend/core/network/build.gradle.kts (Ktor- und Engine-Dependencies)
|
||||
- frontend/core/network/src/commonMain/.../NetworkModule.kt (HttpClient-Setup, Retry/Timeout, Token-Inject)
|
||||
- frontend/features/veranstalter-feature/src/jvmMain/kotlin/at/mocode/frontend/features/veranstalter/data/remote/DefaultVeranstalterRepository.kt
|
||||
|
||||
Akzeptanzkriterien (B-2 abgeschlossen):
|
||||
- [x] `HttpClient`-Factory vorhanden, konfiguriert und via Koin injizierbar
|
||||
- [x] Repository-Interfaces existieren in commonMain, mit Domain-Typen und suspend-APIs (Veranstalter, Turnier vorbereitet)
|
||||
- [x] Mindestens `VeranstalterRepository` nutzt echten Backend-Client und liefert Daten
|
||||
- [x] Fehler werden einheitlich modelliert und bis ins ViewModel propagiert
|
||||
- [x] Ein Feature-ViewModel (z. B. Veranstalter) läuft ohne `StoreV2`
|
||||
- [ ] **B-2** | Ktor-Clients & Repositories für Backend-Anbindung
|
||||
- [x] `HttpClient`-Factory zentral konfiguriert (Auth, Timeout, JSON, Logging, Retry)
|
||||
- [x] `VeranstalterRepository` (Interface + Default-Impl mit Ktor) vollständig
|
||||
- [x] `TurnierRepository` Interface in commonMain vorbereitet
|
||||
- [x] Fehler-Mapping HTTP → Domain-Errors einheitlich
|
||||
- [ ] `BewerbRepository` und `AbteilungRepository` anlegen
|
||||
- [ ] Koin Feature-Module: Repository-Interfaces auf Default-Impl binden
|
||||
- [ ] `AuthApiClient`-Integration: Token-Provider injizierbar
|
||||
- [ ] Turnier/Bewerb/Abteilung Backend-Endpunkte verdrahten
|
||||
- [ ] `StoreV2` schrittweise ablösen (Feature-für-Feature, Toggle `useRealBackend`)
|
||||
- [ ] Akzeptanz-Tests per Fake-Server (Mock Engine, happy + error paths)
|
||||
- [ ] Dokumentation `docs/06_Frontend/Networking.md`
|
||||
|
||||
- [ ] **B-3** | Validierungs-Live-Feedback in Edit-Dialogen
|
||||
- [ ] Spezifikation von 📜 Rulebook Expert (Sprint A-5) als Basis nutzen
|
||||
- [ ] `MsValidationWrapper`: `Error.short` inline, `Error.long` als Tooltip
|
||||
- [ ] `isValid` im ViewModel für Speichern-Button-State nutzen
|
||||
- [ ] OEPS-Nummer: Inline-Validierung beim Tippen
|
||||
- [ ] FEI-ID: Inline-Validierung beim Tippen
|
||||
- [ ] Lizenzklasse × Bewerbs-Klasse: Warnung wenn nicht erlaubt
|
||||
- [ ] Altersklasse Pferd: Warnung wenn nicht kompatibel
|
||||
- [ ] Basis: `OetoValidatorsTest.kt`-Grenzfälle als Akzeptanzkriterien
|
||||
|
||||
- [ ] **B-4** | Kassa-Screen: Veranstaltungs-Kassa implementieren
|
||||
- [ ] **B-4** | Kassa-Screen: Veranstaltungs-Kassa
|
||||
- [ ] Gesamt-Saldo-Ansicht (Salden aus allen Turnieren der Veranstaltung)
|
||||
- [ ] Turnier-übergreifender Zahlvorgang (eine Zahlung, mehrere Rechnungen)
|
||||
- [ ] Rechnungsvorschau je Turnier
|
||||
|
||||
---
|
||||
|
||||
## 🟡 Sprint C — Mittelfristig (in 2 Wochen)
|
||||
## 🟠 Sprint C — Priorität 2 (nächste Woche)
|
||||
|
||||
- [ ] **C-1** | Mock-Store (`StoreV2`) vollständig ablösen
|
||||
- [ ] **C-1** | `StoreV2` vollständig ablösen
|
||||
- [ ] Alle verbleibenden `StoreV2`-Referenzen durch echte Repositories ersetzen
|
||||
- [ ] `StoreV2` nach vollständiger Ablösung entfernen oder als `@Deprecated` markieren
|
||||
- [ ] `StoreV2` entfernen nach vollständiger Migration
|
||||
|
||||
- [ ] **C-2** | LAN-Sync-UI vorbereiten (nach ADR von Architect)
|
||||
- [ ] Verbindungsstatus-Anzeige (Online/Offline/LAN)
|
||||
- [ ] Sync-Trigger manuell und automatisch
|
||||
- [ ] **C-2** | VeranstalterNeu: Vereinssuche & Daten-Übernahme
|
||||
- [ ] Vereins-Suche implementieren (Suche, Auswahl, Mapping)
|
||||
- [ ] Validierung und Fehleranzeigen
|
||||
|
||||
> ⏸️ **USB-Stick Fallback (Export/Import UI)** — Separate Besprechung zu einem späteren Zeitpunkt
|
||||
- [ ] **C-3** | LAN-Sync-UI vorbereiten (ADR-0022 ✅ freigegeben)
|
||||
- [ ] `SyncEvent`-Datenmodell aus `core`-Modul einbinden (KMP-shared)
|
||||
- [ ] `originNodeId`-Generierung und -Persistierung beim App-Start
|
||||
- [ ] WebSocket-Client auf Richter-Turm-Desk (Ktor-Client/KMP): HELLO/SYNC_PUSH/SYNC_ACK
|
||||
- [ ] Geräte-Discovery-UI (gefundene Geräte im LAN via mDNS anzeigen)
|
||||
- [ ] Sync-Status-Indicator in der Hauptnavigation (verbunden / getrennt / ausstehende Events)
|
||||
- [ ] Offline-Indikator: ausstehende lokale Events sichtbar machen
|
||||
- [ ] Domänen-Mastership beachten: Richter-Turm schreibt nur Bewertungen/Ergebnisse
|
||||
|
||||
- [ ] **C-4** | Lint-Bereinigung & Code-Qualität
|
||||
- [ ] Ungenutzte Imports/Parameter entfernen
|
||||
- [ ] `Long → Duration`-Konvertierungen modernisieren
|
||||
- [ ] Redundante Not-null-Calls vereinfachen
|
||||
|
||||
> ⏸️ **USB-Stick Fallback (Export/Import UI)** — Separate Besprechung (Sprint B/C)
|
||||
|
||||
---
|
||||
|
||||
## 📌 Abhängigkeiten
|
||||
|
||||
| Warte auf | Von wem |
|
||||
|----------------------------------|--------------------|
|
||||
| Domänen-Modell final (Abteilung) | 🏗️ Architect |
|
||||
| CRUD-Endpunkte | 👷 Backend |
|
||||
| Validierungs-Spezifikation | 📜 Rulebook Expert |
|
||||
| Wireframes Edit-Formulare | 🖌️ UI/UX Designer |
|
||||
| Warte auf | Von wem | Betrifft |
|
||||
|----------------------------------------|-------------------|----------------------------|
|
||||
| Reiter/Pferde/Vereine/Funktionäre APIs | 👷 Backend B-1 | B-2 Repository-Verdrahtung |
|
||||
| Rulebook Validierungs-Spezifikation | 📜 Rulebook B-2 | B-3 Live-Validierung |
|
||||
| Kassa-Service API | 👷 Backend B-2 | B-4 Kassa-Screen |
|
||||
| ~~ADR-0022 LAN-Sync~~ | ✅ Erledigt | C-3 Sync-UI freigegeben |
|
||||
| Wireframes Edit-Dialoge / Kassa | 🖌️ UI/UX B-1/B-3 | B-3, B-4 Implementierung |
|
||||
|
||||
| Meine Aufgabe | Ermöglicht wem |
|
||||
|--------------------------|-----------------------------------------------|
|
||||
| ViewModel-Referenz (A-1) | Alle anderen ViewModels folgen diesem Muster |
|
||||
| Ktor-Repositories (B-2) | Ablösung von StoreV2, echte Daten im Frontend |
|
||||
---
|
||||
|
||||
## 💡 Empfehlungen (nach Priorität)
|
||||
|
||||
1. **B-2 Repository-Verdrahtung** — Bewerb/Abteilung-Repos und StoreV2-Ablösung sind der kritische Pfad für echte Daten
|
||||
im Frontend.
|
||||
2. **B-3 Live-Validierung** — Rulebook hat Spezifikation übergeben (Sprint B-1 ✅); Frontend kann sofort mit
|
||||
`OetoValidators` loslegen.
|
||||
3. **C-2 VeranstalterNeu** — Offener Punkt aus Session 02.04; Vereinssuche fehlt noch für vollständigen Onboarding-Flow.
|
||||
|
||||
Reference in New Issue
Block a user