meldestelle/docs/04_Agents/Roadmaps/Frontend_Roadmap.md
StefanMoCoAt f82dbd64a5 Integrate Ktor HTTP clients and repositories for Veranstalter and Turnier features:
- Add `ApiRoutes` for central backend routing configuration.
- Implement `DefaultVeranstalterRepository` and `DefaultTurnierRepository` with Ktor clients.
- Add domain models (`Turnier`, `Bewerb`, `Abteilung`, `Veranstalter`) and respective repository interfaces.
- Replace fake VeranstalterRepository with real implementation.
- Update DI with `veranstalterModule` and HTTP client injection.
- Simplify TokenProvider and update HttpClient setup (timeouts, retries, logging).
- Mark roadmap tasks B-2 as partially complete.
2026-04-03 01:09:35 +02:00

9.5 KiB
Raw Blame History

🎨 [Frontend Expert] — Schritt-für-Schritt Roadmap

Stand: 3. April 2026 Rolle: KMP, Compose Desktop, State-Management, MVVM/UDF, Backend-Anbindung


🔴 Sprint A — Sofort (diese Woche)

  • A-1 | ViewModel-Architektur definieren und Referenz-Implementierung umsetzen

    • MVVM mit UDF (Unidirectional Data Flow) als verbindliches Muster festlegen
    • Intent- und State-Klassen-Struktur definieren (Vorlage für alle anderen ViewModels)
    • VeranstalterViewModel als vollständige Referenz-Implementierung umsetzen
      • State-Klasse definieren
      • Intent-Klasse (Sealed Class) definieren
      • Business-Logik aus Composables herausziehen (keine StoreV2-Aufrufe mehr direkt in onSaved)
      • Lokalen remember-State durch ViewModel-State ersetzen
    • 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)
  • A-2 | Abteilungs-Logik im Bewerb-Dialog berücksichtigen

    • Dialog enthält Abteilungs-Auswahl als Teil des „Bewerb anlegen“-Flows (im selben Modal)
    • CSN-C-NEU: Automatischer Vorschlag der Pflicht-Teilung mit 4 Abteilungen:
      • Ohne Lizenz · R1
      • Ohne Lizenz · R2+
      • Mit Lizenz · R1
      • Mit Lizenz · R2+
    • Beim Auto-Vorschlag Default-Setzung des Abteilungs-Typs auf SEPARATE_SIEGEREHRUNG
    • Manuelle Umschaltung des Abteilungs-Typs möglich: SEPARATE_SIEGEREHRUNG oder ORGANISATORISCH
    • UX: Bei erkanntem Typ „CSN-C-NEU“ wird ein AssistChip „Pflicht-Teilung vorgeschlagen“ angezeigt

    Akzeptanzkriterien:

    • Der „Bewerb anlegen“-Dialog zeigt ein Eingabefeld „Bewerbs-Typ“ und eine Auswahl für den Abteilungs-Typ (zwei Chips)
    • Bei Eingabe „CSN-C-NEU“ wird automatisch die oben definierte 4er-Teilung in der Abteilungs-Liste angezeigt
    • Die Auto-Teilung kann angezeigt werden, ohne dass der Dialog neu geöffnet werden muss (Live-Reaktion auf Eingabe)
    • Der gesetzte Abteilungs-Typ ist im State sichtbar und wird vom Dialog korrekt reflektiert
    • Kein Vorschlag für andere Typen; Liste bleibt leer bis manuell hinzugefügt/implementiert (aktuell out-of-scope)

    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 — Kurzfristig (nächste Woche)

  • B-1 | ViewModels für alle V3-Screens umsetzen

    • TurnierViewModel
    • BewerbViewModel (inkl. Abteilungs-Logik via Dialog-VM)
    • PferdProfilViewModel
    • ReiterProfilViewModel
    • VereinsViewModel
    • FunktionaerViewModel
    • AbteilungViewModel (Startliste, Ergebnisse)
  • B-2 | Ktor-Clients und Repositories für Backend-Anbindung vorbereiten (V3-ready)

    • KMP-Ktor-Client zentral konfigurieren (BaseURL, Auth, Timeout, JSON, Logging)

      • BaseURL per PlatformConfig.resolveApiBaseUrl() (SSoT; JS: globalThis.API_BASE_URL/window.location.origin, JVM: .env/Systemprop) → frontend/core/network
      • Auth: Bearer Token über Interceptor; Token-Quelle: core/auth (AuthApiClient) bzw. Session-Store → Header Authorization: Bearer <token>
      • Timeouts: connect = 5s, request = 15s, socket = 30s (prod); dev je 2× höher; Retry-Policy max 2 Versuche bei 5xx/Network
      • JSON: kotlinx.serialization mit ignoreUnknownKeys=true, explicitNulls=false, coerceInputValues=true
      • Logging: LogLevel.HEADERS in dev, LogLevel.NONE in prod; PII nie loggen
      • Engines: JVM=CIO, JS=fetch (ktor-client-js), WASM=js (vorbereitet)
    • Repository-Schnittstellen je Domäne definieren (Mock ↔ Real austauschbar)

      • Pakete/Orte (commonMain):
        • at.mocode.frontend.features.veranstalter.domain.VeranstalterRepository
        • 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)
    • HTTP-Clients + DTOs + Mapper (jvmMain/jsMain)

      • DTOs pro Feature in .../data/remote/dto mit @Serializable (Veranstalter)
      • Mapper: Dto ↔ Domain in .../data/mapper (reine Funktionen) (Veranstalter)
      • Client-Implementierungen in .../data/remote/Default*Repository mit Ktor (Veranstalter)
      • Fehlerbehandlung: Mapping HTTP 401→AuthError.Expired, 403→AuthError.Forbidden, 404→NotFound, 409→Conflict, 5xx→ServerError
    • Koin-DI-Module

      • 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?)
    • Backend-Endpunkte verdrahten (gemäß contracts/ oder Backend-Services)

      • 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):

    • HttpClient-Factory vorhanden, konfiguriert und via Koin injizierbar
    • Repository-Interfaces existieren in commonMain, mit Domain-Typen und suspend-APIs (Veranstalter, Turnier vorbereitet)
    • Mindestens VeranstalterRepository nutzt echten Backend-Client und liefert Daten
    • Fehler werden einheitlich modelliert und bis ins ViewModel propagiert
    • Ein Feature-ViewModel (z. B. Veranstalter) läuft ohne StoreV2
  • B-3 | Validierungs-Live-Feedback in Edit-Dialogen

    • Spezifikation von 📜 Rulebook Expert (Sprint A-5) als Basis 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
  • B-4 | Kassa-Screen: Veranstaltungs-Kassa implementieren

    • 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)

  • C-1 | Mock-Store (StoreV2) vollständig ablösen

    • Alle verbleibenden StoreV2-Referenzen durch echte Repositories ersetzen
    • StoreV2 nach vollständiger Ablösung entfernen oder als @Deprecated markieren
  • C-2 | LAN-Sync-UI vorbereiten (nach ADR von Architect)

    • Verbindungsstatus-Anzeige (Online/Offline/LAN)
    • Sync-Trigger manuell und automatisch

⏸️ USB-Stick Fallback (Export/Import UI) — Separate Besprechung zu einem späteren Zeitpunkt


📌 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
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