diff --git a/README.md b/README.md index 48dbe4a8..da985a2a 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,8 @@ Die Hauptdokumentation befindet sich in der **YouTrack Wissensdatenbank**: #### Im Repository - [📖 docs/README.md](docs/README.md) - Übersicht aller Repository-Dokumentation -- [đŸ›ïž Architecture Decision Records](docs/architecture/adr) -- [📐 C4-Diagramme](docs/architecture/c4) +- [đŸ›ïž Architecture Decision Records](docs/adr) +- [📐 C4-Diagramme](docs/c4) - [đŸ› ïž Developer Guides](docs/how-to) - [📑 Projekt-Guidelines (Master)](.junie/guidelines/master-guideline.md) @@ -98,7 +98,7 @@ Das System ist in unabhĂ€ngige DomĂ€nen aufgeteilt: - **Polyglot Persistence**: PostgreSQL + Redis - **Container-First**: Docker & Docker Compose -**Details**: [ADR-0002 Domain-Driven Design](docs/architecture/adr/0002-domain-driven-design-de.md) +**Details**: [ADR-0002 Domain-Driven Design](docs/adr/0002-domain-driven-design-de.md) --- diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index efb52dc3..cc9df699 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -12,8 +12,15 @@ frontend/ KMP Frontend shells AusfĂŒhrbare Apps (Assembler) features Vertical Slices (kein Feature→Feature) core Shared Foundation (Design-System, Network, Local-DB, Auth, Domain) + design-system + domain + network + local-db + navigation docker/ Docker Compose, .env.example, Monitoring-/Core-Konfiguration docs/ Architektur, ADRs, C4-Modelle, Guides + adr Architecture Decision Records (ADRs) + c4 C4-Diagramme (PlantUML Quellen) Ist → Soll Mapping (erste Tranche) @@ -65,3 +72,5 @@ NĂ€chste Schritte (MP-22 Folgetasks) 2. Physisches Verschieben der Backend-Komponenten in backend/* inkl. evtl. Package-Pfade, sofern notwendig. 3. ErgĂ€nzung von docker-compose.services.yml und docker-compose.clients.yml mit echten Overlays. 4. Erstellen der ersten ADRs unter docs/adr (Koin, SQLDelight, Optimistic Locking, Freshness UI, Core Domain). + +Hinweis: ADRs liegen ab sofort zentral unter `docs/adr/` (nicht mehr unter `docs/architecture/adr/`). C4-Diagramme wurden nach `docs/c4/` verschoben. diff --git a/docs/README.md b/docs/README.md index f3c7de1d..879fed66 100644 --- a/docs/README.md +++ b/docs/README.md @@ -23,23 +23,24 @@ Die Hauptdokumentation befindet sich in der **YouTrack Wissensdatenbank**: Architekturentscheidungen sind Teil der Code-Historie und werden im Repository versioniert: -- [ADR Übersicht](architecture/adr) -- [ADR-0001: Modulare Architektur](architecture/adr/0001-modular-architecture-de.md) -- [ADR-0002: Domain-Driven Design](architecture/adr/0002-domain-driven-design-de.md) -- [ADR-0003: Microservices](architecture/adr/0003-microservices-architecture-de.md) -- [ADR-0004: Event-Driven Communication](architecture/adr/0004-event-driven-communication-de.md) -- [ADR-0005: Polyglot Persistence](architecture/adr/0005-polyglot-persistence-de.md) -- [ADR-0006: Authentication & Authorization (Keycloak)](architecture/adr/0006-authentication-authorization-keycloak-de.md) -- [ADR-0007: API Gateway Pattern](architecture/adr/0007-api-gateway-pattern-de.md) -- [ADR-0008: Multiplatform Client Applications](architecture/adr/0008-multiplatform-client-applications-de.md) +- [ADR Übersicht](adr) +- [ADR-0001: Modulare Architektur](adr/0001-modular-architecture-de.md) +- [ADR-0002: Domain-Driven Design](adr/0002-domain-driven-design-de.md) +- [ADR-0003: Microservices](adr/0003-microservices-architecture-de.md) +- [ADR-0004: Event-Driven Communication](adr/0004-event-driven-communication-de.md) +- [ADR-0005: Polyglot Persistence](adr/0005-polyglot-persistence-de.md) +- [ADR-0006: Authentication & Authorization (Keycloak)](adr/0006-authentication-authorization-keycloak-de.md) +- [ADR-0007: API Gateway Pattern](adr/0007-api-gateway-pattern-de.md) +- [ADR-0008: Multiplatform Client Applications](adr/0008-multiplatform-client-applications-de.md) +- [ADR-0009: Final KMP Architecture](adr/0009-final-kmp-architecture.md) ### 2. C4-Diagramme (PlantUML-Quellen) Versionierte Diagramm-Quellen fĂŒr Architekturdokumentation: -- [C4 Context](architecture/c4/01-context-de.puml) -- [C4 Container](architecture/c4/02-container-de.puml) -- [C4 Component - Events Service](architecture/c4/03-component-events-service-de.puml) +- [C4 Context](c4/01-context-de.puml) +- [C4 Container](c4/02-container-de.puml) +- [C4 Component - Events Service](c4/03-component-events-service-de.puml) ### 3. Developer Guides @@ -72,7 +73,7 @@ Das Projekt nutzt automatisierte Workflows fĂŒr Konsistenz: ### FĂŒr Architektur-Entscheidungen -1. ADR in `docs/architecture/adr/` erstellen +1. ADR in `docs/adr/` erstellen 2. PR mit ADR-Review 3. Nach Merge → Zusammenfassung in YouTrack verlinken diff --git a/docs/architecture/adr/0000-adr-template-de.md b/docs/adr/0000-adr-template-de.md similarity index 100% rename from docs/architecture/adr/0000-adr-template-de.md rename to docs/adr/0000-adr-template-de.md diff --git a/docs/architecture/adr/0001-modular-architecture-de.md b/docs/adr/0001-modular-architecture-de.md similarity index 100% rename from docs/architecture/adr/0001-modular-architecture-de.md rename to docs/adr/0001-modular-architecture-de.md diff --git a/docs/architecture/adr/0002-domain-driven-design-de.md b/docs/adr/0002-domain-driven-design-de.md similarity index 100% rename from docs/architecture/adr/0002-domain-driven-design-de.md rename to docs/adr/0002-domain-driven-design-de.md diff --git a/docs/architecture/adr/0003-microservices-architecture-de.md b/docs/adr/0003-microservices-architecture-de.md similarity index 100% rename from docs/architecture/adr/0003-microservices-architecture-de.md rename to docs/adr/0003-microservices-architecture-de.md diff --git a/docs/architecture/adr/0004-event-driven-communication-de.md b/docs/adr/0004-event-driven-communication-de.md similarity index 100% rename from docs/architecture/adr/0004-event-driven-communication-de.md rename to docs/adr/0004-event-driven-communication-de.md diff --git a/docs/architecture/adr/0005-polyglot-persistence-de.md b/docs/adr/0005-polyglot-persistence-de.md similarity index 100% rename from docs/architecture/adr/0005-polyglot-persistence-de.md rename to docs/adr/0005-polyglot-persistence-de.md diff --git a/docs/architecture/adr/0006-authentication-authorization-keycloak-de.md b/docs/adr/0006-authentication-authorization-keycloak-de.md similarity index 100% rename from docs/architecture/adr/0006-authentication-authorization-keycloak-de.md rename to docs/adr/0006-authentication-authorization-keycloak-de.md diff --git a/docs/architecture/adr/0007-api-gateway-pattern-de.md b/docs/adr/0007-api-gateway-pattern-de.md similarity index 100% rename from docs/architecture/adr/0007-api-gateway-pattern-de.md rename to docs/adr/0007-api-gateway-pattern-de.md diff --git a/docs/architecture/adr/0008-multiplatform-client-applications-de.md b/docs/adr/0008-multiplatform-client-applications-de.md similarity index 100% rename from docs/architecture/adr/0008-multiplatform-client-applications-de.md rename to docs/adr/0008-multiplatform-client-applications-de.md diff --git a/docs/adr/0009-final-kmp-architecture.md b/docs/adr/0009-final-kmp-architecture.md new file mode 100644 index 00000000..85325a2f --- /dev/null +++ b/docs/adr/0009-final-kmp-architecture.md @@ -0,0 +1,35 @@ +# ADR-0009: Final KMP Architecture + +Status: Accepted + +Kontext + +Wir schließen die Architektur-Entscheidungen fĂŒr das Frontend als Kotlin Multiplatform (KMP) Projekt ab und bestĂ€tigen die finalen Bausteine sowie die Modulaufteilung. Die Plattformen Web (JS/WASM) und JVM/Desktop werden unterstĂŒtzt. + +Entscheidung + +1. Plattformen: Kotlin Multiplatform mit Targets Web (JS/WASM) und JVM/Desktop. +2. Dependency Injection: Koin als DI-Framework fĂŒr gemeinsame und plattformspezifische Layer. +3. Persistenz (Offline-First): SQLDelight als lokale Datenbank (Single Source of Truth), synchronisiert im Hintergrund. +4. Modulaufteilung im Frontend: + - shells: AusfĂŒhrbare App-Shells (Bootstrap/Assembler, DI-Start, Plattformintegration) + - features: Vertikale Slices mit UI, Domain-Logik und Navigation pro Feature + - core: Gemeinsame Basis (design-system, domain, network, local-db, navigation) +5. Kommunikation: Features reden nicht direkt miteinander; Navigation + Shared-Domain-Modelle in core/domain. + +BegrĂŒndung + +- KMP erlaubt maximale Codewiederverwendung ĂŒber Web und JVM bei konsistentem Tooling. +- Koin bietet leichtgewichtige, idiomatische DI ohne Code-Generierung, geeignet fĂŒr KMP. +- SQLDelight liefert typsichere Queries, portable Schemas und ist fĂŒr Offline-First praxiserprobt. +- Die Trennung in shells/features/core fördert klare ZustĂ€ndigkeiten, Testbarkeit und schrittweise Erweiterbarkeit. + +Konsequenzen + +- Projektstruktur und Gradle-Module folgen strikt der Aufteilung in `shells`, `features`, `core`. +- Der `apiClient` (core/network) wird via Koin als Named Binding injiziert; manuelles Setzen von Authorization-Headern ist untersagt. +- UI liest aus der lokalen Datenbank (SQLDelight); Synchronisation erfolgt ĂŒber Hintergrundjobs. + +Status / Nacharbeiten + +- Diese ADR konsolidiert die KMP-Entscheidung und ersetzt frĂŒhere verstreute Notizen. Weitere Details (z. B. konkrete Module, Pfade) sind in `docs/ARCHITECTURE.md` dokumentiert. diff --git a/docs/architecture/c4/01-context-de.puml b/docs/c4/01-context-de.puml similarity index 100% rename from docs/architecture/c4/01-context-de.puml rename to docs/c4/01-context-de.puml diff --git a/docs/architecture/c4/02-container-de.puml b/docs/c4/02-container-de.puml similarity index 100% rename from docs/architecture/c4/02-container-de.puml rename to docs/c4/02-container-de.puml diff --git a/docs/architecture/c4/03-component-events-service-de.puml b/docs/c4/03-component-events-service-de.puml similarity index 100% rename from docs/architecture/c4/03-component-events-service-de.puml rename to docs/c4/03-component-events-service-de.puml diff --git a/docs/clients/Architektur.md b/docs/clients/Architektur.md deleted file mode 100644 index 6e48bffd..00000000 --- a/docs/clients/Architektur.md +++ /dev/null @@ -1,86 +0,0 @@ -# Meldestelle Clients – ArchitekturĂŒbersicht (aktualisiert) - -## Ziele -- Öffentliche Willkommensseite mit Links zu Ping-Service, Keycloak Login/Registrierung -- Einfache Auth-Status-Seite („Du bist als 
 angemeldet“) -- Bereinigung der Legacy-UI (altes PrĂ€sentations-Layer entfernt) -- Bereitstellung als Docker-Container: `web-app` (Kotlin/JS) und `desktop-app` (VNC/noVNC) - -## Module und Struktur -- `clients/app`: Einstieg der Anwendung (Compose Multiplatform) - - `MainApp.kt`: Start-Routing, Composables `WelcomeScreen`, `LoginScreen`, `AuthStatusScreen` - - Verwendet: `ping-feature` (PingScreen), `auth-feature` (Login via `AuthApiClient`) -- `clients/shared`: Gemeinsame Domain/Data/DI + `AppConfig` - - `AppConfig`: Basis-URLs und Keycloak-Client-Konfiguration -- `clients/shared/common-ui`: generische UI-Bausteine (Legacy-Teile neutralisiert) - - `layout/MainLayout.kt`, `components/NotificationCard.kt`, `screens/DashboardScreen.kt` → bewusst geleert -- `clients/auth-feature`: Login-API gegen Keycloak (Password Grant) -- `clients/ping-feature`: Ping-Screen und ViewModel, greift auf Ping-Service zu - -## Navigation (vereinfacht) -- Start: `AppScreen.Home` → `WelcomeScreen` -- `AppScreen.Ping` → `PingScreen` -- `AppScreen.Login` → `LoginScreen` -- `AppScreen.Profile` → `AuthStatusScreen` - -## Keycloak-Konfiguration -Quelle: `docker/core/keycloak/meldestelle-realm.json` und `docs/reference/ports-and-urls.md` -- Realm: `meldestelle` -- Öffentlicher Client: `web-app` (PKCE; fĂŒr Browser) -- Keycloak URL (lokal): `http://localhost:8180` -- AppConfig nutzt: `KEYCLOAK_URL=http://localhost:8180`, `KEYCLOAK_REALM=meldestelle`, `KEYCLOAK_CLIENT_ID=web-app` - -### Authentifizierungs-Flow (PKCE) -- Flow: Authorization Code Flow mit PKCE (S256) -- Redirect-URI (lokal): `http://localhost:4000/` (Root, Query-Parameter werden vom Client ausgewertet) -- Ablauf: - 1. Button „Login“ → PKCE-Start (Code Verifier/Challenge werden generiert) und Redirect zu Keycloak `/auth` - 2. Keycloak leitet zurĂŒck auf `http://localhost:4000/?code=...&state=...` - 3. Client tauscht `code` + `code_verifier` am `/token`-Endpoint gegen Tokens - 4. `AuthTokenManager` speichert Access-Token (in-memory), UI zeigt Status „Du bist als 
 angemeldet“ - -Hinweis: Password-Grant wird nicht mehr genutzt; fĂŒr Desktop (JVM) bleibt bei Bedarf der lokale Login-Screen als Fallback vorhanden. - -## Ports und URLs (lokal) -Quelle: `docs/reference/ports-and-urls.md` -- API Gateway: `http://localhost:8081` -- Keycloak: `http://localhost:8180` -- Ping Service: `http://localhost:8082` -- Web App: `http://localhost:4000` -- Desktop App: VNC `5901`, noVNC `http://localhost:6080` - -## Docker -### Web-App (Kotlin/JS, kein WASM) -- Dockerfile: `dockerfiles/clients/web-app/Dockerfile` -- Build: Gradle `:clients:app:jsBrowserDistribution` → statische Dateien via Nginx -- Compose: - - Hardcoded: Service `web-app` mit Port `4000:4000` in `compose.hardcoded.yaml` - - Variablen: Service `web-app` mit `${WEB_APP_PORT}` in `compose.yaml` (Wert in `.env`) - -Downloads (Desktop-Installer, Platzhalter): -- Verzeichnis: `dockerfiles/clients/web-app/downloads/` → wird nach `/usr/share/nginx/html/downloads/` kopiert -- URL: `http://localhost:4000/downloads/` -- Alternativ: per Compose ein Host-Verzeichnis auf `/usr/share/nginx/html/downloads` mounten - -### Desktop-App (VNC/noVNC) -- Dockerfile: `dockerfiles/clients/desktop-app/Dockerfile` -- Build: Gradle `:clients:app:createDistributable` → Desktop Runtime -- Runtime: Ubuntu + `xvfb` + `x11vnc` + `noVNC` + `supervisord` -- Compose: - - Hardcoded: Service `desktop-app` 5901/6080 in `compose.hardcoded.yaml` - - Variablen: Service `desktop-app` mit `${DESKTOP_APP_VNC_PORT}` und `${DESKTOP_APP_NOVNC_PORT}` in `compose.yaml` (Werte in `.env`) - -## Bereinigung (Altlasten) -- Entfernt/neutralisiert: Altes PrĂ€sentations-Layer (abhĂ€ngig von `presentation.state`/`actions`) - - `clients/shared/common-ui/components/NotificationCard.kt` → geleert - - `clients/shared/common-ui/layout/MainLayout.kt` → geleert - - `clients/shared/common-ui/screens/DashboardScreen.kt` → geleert - -## Konfigurationsquelle -- Einheitliche Werte/Ports: `docker/versions.toml` (Clients: `web-app=4000`, `desktop-app-vnc=5901`, `desktop-app-novnc=6080`) -- Compose-Variablen: `.env` und `.env.template` - -## NĂ€chste Schritte -- Optional: Umstellung Login auf Authorization Code Flow (PKCE) fĂŒr Browser -- Optional: Willkommensseite visuell ausbauen (Branding) -- Optional: Bereitstellung der Desktop-Installer ĂŒber `web-app` Download-Link diff --git a/docs/clients/visionen/AntwortenOffenerFragenArchitekturReview.md b/docs/clients/visionen/AntwortenOffenerFragenArchitekturReview.md deleted file mode 100644 index 2dca2d81..00000000 --- a/docs/clients/visionen/AntwortenOffenerFragenArchitekturReview.md +++ /dev/null @@ -1,161 +0,0 @@ -### 1\. Welche DI-Lösung? (Dependency Injection) - -**Entscheidung:** Wir nutzen **Koin**. - -**BegrĂŒndung (ADR):** - -* **Warum nicht Dagger/Hilt?** Hilt ist stark auf Android (Context, Lifecycles) fixiert. Dagger ist extrem komplex im Setup fĂŒr Multiplatform (Kapt/KSP Setup ĂŒber alle Targets). -* **Warum Koin?** Es ist ein reines Kotlin-Framework ("Service Locator" Pattern). Es funktioniert identisch auf JVM (Desktop), JS (Web) und Android. Es benötigt keine Annotation-Processing-Magie, was die Build-Zeiten im Monorepo niedrig hĂ€lt. - -**Eintrag im Guide:** - -```text -// GUIDELINE: Dependency Injection -// Wir nutzen Koin. Module werden im `di` Package des Features definiert. - -// 1. Definition (Feature Module) -val inventoryModule = module { - // Singletons fĂŒr Services - single { InventoryRepositoryImpl(get(), get()) } - - // ViewModels (Factory scope) - viewModel { InventoryViewModel(get()) } -} - -// 2. Nutzung des ApiClients (Best Practice) -// Wir injizieren IMMER den "apiClient" (mit Auth-Header), niemals den Default Client. -val networkModule = module { - // Hinweis: Platzhalter (kein ausfĂŒhrbarer Code im Dokument) - single(named("apiClient")) { /* bereitgestellt in :core:network */ } -} - -val myFeatureModule = module { - single { - // Explizites Holen des authentifizierten Clients - MyFeatureApi(httpClient = get(named("apiClient"))) - } -} -``` - ------ - -### 2\. Welche Offline-DB/ORM? - -**Entscheidung:** Wir nutzen **SQLDelight**. - -**BegrĂŒndung (ADR):** - -* **Warum nicht Room (KMP)?** Room ist fĂŒr KMP noch sehr neu (Alpha/Beta Status) und bringt viel Overhead mit sich (SQLite Bundling etc.). -* **Warum SQLDelight?** - 1. **Schema First:** Du schreibst SQL (`.sq`), und Kotlin-Code wird *generiert*. Das zwingt Entwickler dazu, ĂŒber ihr Datenmodell nachzudenken, bevor sie Code schreiben. - 2. **Performance:** Es ist extrem leichtgewichtig und typ-sicher. - 3. **Migrationen:** SQLDelight hat ein exzellentes System fĂŒr Schema-Migrationen (`1.sqm`, `2.sqm`), was fĂŒr Desktop-Apps (die nicht einfach "neu geladen" werden können wie Webseiten) essenziell ist. - -**Eintrag im Guide:** - -> **DB-Guideline:** -> -> * Jedes Feature definiert sein Schema in `:frontend:core:local-db/src/commonMain/sqldelight/...`. -> * Business-Logik darf niemals SQL-Strings enthalten. Nutze die generierten `Queries`-Objekte. -> * Migrationen sind Pflicht bei Schema-Änderungen\! (Kein `DROP TABLE` in Production). - ------ - -### 3\. Konfliktstrategie bei Sync? - -**Entscheidung:** **Optimistic Locking** (Server Wins). - -**BegrĂŒndung (ADR):** - -* In einem System mit Offline-Clients ist "Last Write Wins" gefĂ€hrlich (Lagerbestand wird ĂŒberschrieben). -* **Strategie:** - 1. Jedes Entity hat eine `lastUpdated` (Timestamp) Spalte. - 2. Der Client sendet beim Update die Version mit, die er *kennt*. - 3. Wenn Server-Version \> Client-Version → **HTTP 409 Conflict**. - 4. Client muss Daten neu laden (Refresh) und User fragen/informieren. - -**Eintrag im Guide:** - -```kotlin -// GUIDELINE: Sync & Conflicts -// Das Frontend fĂŒhrt KEIN komplexes Merging durch. - -suspend fun updateStock(item: Item) { - try { - api.update(item.id, item.newStock, currentVersion = item.version) - // Happy Path: DB Update - } catch (e: ConflictException) { // HTTP 409 - // 1. Markiere Item in UI als "Out of Sync" (Rot) - // 2. Trigger automatischen Refresh vom Server - // 3. Zeige User Toast: "Daten waren veraltet. Bitte prĂŒfen." - repo.refreshSingleItem(item.id) - } -} -``` - ------ - -### 4\. Error Budgets / SLIs (Stale Data Indikatoren) - -**Entscheidung:** **Visual Freshness Indicators** (Ampel-System). - -**BegrĂŒndung (ADR):** - -* Ein User muss wissen, ob der Lagerbestand "live" ist oder "von gestern". -* Wir definieren keine harten Timeouts (App blockieren), sondern weiche UI-Hinweise. - -**Eintrag im Guide:** - -> **UI-Regel "Data Freshness":** -> Jedes Entity in der lokalen DB hat ein Feld `lastSyncedAt`. Das UI reagiert darauf: -> -> * **\< 5 min:** ✅ Normalzustand (Kein Indikator). -> * **\> 5 min:** ⚠ Kleines gelbes "Wolke"-Icon oder ausgegrauter Text (Warnung). -> * **\> 1 Stunde:** ❌ Roter Banner "Offline-Daten: Bestand nicht garantiert". -> * **Aktion:** Schreibende Operationen sind bei "Rot" fĂŒr kritische Bereiche (z.B. Inventur-Abschluss) gesperrt, fĂŒr unkritische (z.B. Notiz anlegen) erlaubt (Queue). - ------ - -### 5\. API-VertrĂ€ge und Kapselung der Feature-Teams - -**Entscheidung:** **Loose Coupling via Navigation Routes & Shared Data Models (Core)**. - -**BegrĂŒndung (ADR):** - -* Wir wollen vermeiden, dass Team A (Inventory) direkt Klassen von Team B (Checkout) importiert. Das fĂŒhrt zum "Monolithen-Klumpen". -* Wir nutzen **keine** separaten Gradle-Module pro Feature-API (`:inventory-api`, `:inventory-impl`), da dies den Build-Graph unnötig aufblĂ€ht ("Gradle Overhead"). - -**Strategie:** - -1. **Schnittstelle:** Die einzige "Public API" eines Features ist sein `EntryPoint` (Composable) und seine `Route` (String). -2. **Datenaustausch:** - * *Minimal:* Über URL-Parameter (IDs). `navigator.navigate("inventory/details/123")`. - * *Objekte:* Wenn komplexe Objekte geteilt werden mĂŒssen (z.B. `UserProfile`), gehören diese in **`:frontend:core:domain`** (Shared Kernel). - -**Eintrag im Guide:** - -```text -// GUIDELINE: Feature Isolation -// 1. Features importieren NIEMALS andere Features im `build.gradle.kts`. -// 2. Kommunikation nur ĂŒber Navigation (Router). -// 3. Gemeinsam genutzte Datenobjekte (z.B. UserID, ShopID) liegen in :core:domain. - -// FALSCH: -// import com.project.features.billing.Invoice // AbhĂ€ngigkeit zu anderem Feature! (nur zu Illustrationszwecken) - -// RICHTIG: -// Feature A navigiert zu Feature B via Route -navigator.navigateTo("billing/create?orderId=123") -``` - ------ - -### Zusammenfassung fĂŒr dein Dokument - -Diese 5 Punkte schließen den Kreis: - -1. **Koin** hĂ€lt den Code sauber. -2. **SQLDelight** hĂ€lt die Daten sicher. -3. **Optimistic Locking** verhindert DatenmĂŒll. -4. **Freshness UI** managed die Erwartungshaltung des Users. -5. **Core Domain** verhindert Spaghetti-Code zwischen Features. diff --git a/docs/clients/visionen/MP-20.md b/docs/clients/visionen/MP-20.md deleted file mode 100644 index c4285a34..00000000 --- a/docs/clients/visionen/MP-20.md +++ /dev/null @@ -1,188 +0,0 @@ -## 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, 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` 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. ✅ diff --git a/docs/clients/visionen/MP-21.md b/docs/clients/visionen/MP-21.md deleted file mode 100644 index 43ccfe3c..00000000 --- a/docs/clients/visionen/MP-21.md +++ /dev/null @@ -1,14 +0,0 @@ -## 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. diff --git a/docs/clients/visionen/MP-22.md b/docs/clients/visionen/MP-22.md deleted file mode 100644 index 5d725d89..00000000 --- a/docs/clients/visionen/MP-22.md +++ /dev/null @@ -1,27 +0,0 @@ -## 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. diff --git a/docs/clients/visionen/MP-23.md b/docs/clients/visionen/MP-23.md deleted file mode 100644 index 20d671b4..00000000 --- a/docs/clients/visionen/MP-23.md +++ /dev/null @@ -1,14 +0,0 @@ -## 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. diff --git a/docs/clients/visionen/MP-24.md b/docs/clients/visionen/MP-24.md deleted file mode 100644 index a05b55f7..00000000 --- a/docs/clients/visionen/MP-24.md +++ /dev/null @@ -1,21 +0,0 @@ -## 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. diff --git a/docs/clients/visionen/MP-25.md b/docs/clients/visionen/MP-25.md deleted file mode 100644 index aabc7af6..00000000 --- a/docs/clients/visionen/MP-25.md +++ /dev/null @@ -1,17 +0,0 @@ -## 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. diff --git a/docs/clients/visionen/MP-26.md b/docs/clients/visionen/MP-26.md deleted file mode 100644 index 35036374..00000000 --- a/docs/clients/visionen/MP-26.md +++ /dev/null @@ -1,13 +0,0 @@ -## 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. diff --git a/docs/clients/visionen/MP-27.md b/docs/clients/visionen/MP-27.md deleted file mode 100644 index 81963aeb..00000000 --- a/docs/clients/visionen/MP-27.md +++ /dev/null @@ -1,18 +0,0 @@ -## 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. diff --git a/docs/clients/visionen/MP-28.md b/docs/clients/visionen/MP-28.md deleted file mode 100644 index d8d8bce3..00000000 --- a/docs/clients/visionen/MP-28.md +++ /dev/null @@ -1,12 +0,0 @@ -## 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. diff --git a/docs/clients/visionen/MP-29.md b/docs/clients/visionen/MP-29.md deleted file mode 100644 index 838ddfc4..00000000 --- a/docs/clients/visionen/MP-29.md +++ /dev/null @@ -1,13 +0,0 @@ -## 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). diff --git a/docs/clients/visionen/MP-30.md b/docs/clients/visionen/MP-30.md deleted file mode 100644 index 40970825..00000000 --- a/docs/clients/visionen/MP-30.md +++ /dev/null @@ -1,6 +0,0 @@ -## 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. diff --git a/docs/clients/visionen/MultiplatformApp_Ktor_SQLDelight_Doku.pdf b/docs/clients/visionen/MultiplatformApp_Ktor_SQLDelight_Doku.pdf deleted file mode 100644 index 50930d44..00000000 Binary files a/docs/clients/visionen/MultiplatformApp_Ktor_SQLDelight_Doku.pdf and /dev/null differ diff --git a/docs/clients/visionen/ProjectArchitecture_StructureGuide.md b/docs/clients/visionen/ProjectArchitecture_StructureGuide.md deleted file mode 100644 index d24c541d..00000000 --- a/docs/clients/visionen/ProjectArchitecture_StructureGuide.md +++ /dev/null @@ -1,155 +0,0 @@ -# 🏗 Project Architecture & Structure Guide - -> **"Code is liability. Structure is asset."** -> Wir bauen dieses System nicht fĂŒr den schnellsten Start, sondern fĂŒr die **Wartbarkeit ĂŒber Jahre**, Offline-FĂ€higkeit und Skalierbarkeit ĂŒber mehrere Teams hinweg. - ------ - -## 1\. Die Große Übersicht: The Monorepo Strategy - -Wir organisieren Backend und Frontend in einem einzigen Repository (Monorepo). - -### **Warum Monorepo? (Decision Record)** - -* ❌ **Alternative:** Getrennte Repositories fĂŒr Backend, Web-Frontend, Desktop-App. -* **Problem dabei:** "Version Hell". Backend Ă€ndert API v1 zu v2, aber Frontend-Repo ist noch auf v1. Refactorings ĂŒber die ganze Kette sind schmerzhaft. -* ✅ **Unsere Entscheidung:** Monorepo. - * **Atomic Commits:** Ein Pull Request enthĂ€lt Backend-Änderungen UND die dazugehörige Frontend-Anpassung. - * **Single Versioning:** Wir nutzen `gradle/libs.versions.toml` als einzige Quelle der Wahrheit fĂŒr Library-Versionen (z.B. Kotlin Version) ĂŒber das gesamte System hinweg. - ------ - -## 2\. Der "Deep Dive" in die Ordnerstruktur - -Hier ist der detaillierte Aufriss unseres Dateisystems. Jeder Ordner hat einen spezifischen architektonischen Zweck. - -```text -/my-project-root -│ -├── ⚙ docker-compose.yml <-- Die lokale "Cloud". Startet DBs, Gateway & Services. -├── 📄 settings.gradle.kts <-- Definiert die Module (Frontend & Backend). -├── 📂 gradle -│ └── libs.versions.toml <-- 🛑 STOP! Hier werden Versionen definiert. Nirgendwo sonst. -│ -├── 📂 backend <-- ARCHITEKTUR: Hexagonal / DDD -│ ├── 📂 gateway <-- Der "TĂŒrsteher". Routing & Auth-Check. -│ ├── 📂 discovery <-- Das "Telefonbuch" (Consul/Service Registry). -│ └── 📂 services <-- Die Business Logic (Microservices) -│ ├── 📂 inventory-service -│ │ ├── 📄 Dockerfile <-- Jedes Service ist ein isolierter Container! -│ │ └── 📂 src/main/kotlin/.../domain <-- Reine Logik, kein Spring! -│ └── 📂 auth-service -│ -└── 📂 frontend <-- ARCHITEKTUR: Kotlin Multiplatform (KMP) - │ - ├── 📂 shells <-- 💡 CONCEPT: "The Assembler" - │ │ Das sind die ausfĂŒhrbaren Anwendungen. Sie enthalten KEINE Logik. - │ │ Sie "kleben" nur Features zusammen und konfigurieren DI. - │ │ - │ ├── 📂 warehouse-app <-- Desktop-App (Windows/Linux) fĂŒr Lageristen - │ │ └── build.gradle.kts (bindet :features:inventory ein) - │ └── 📂 admin-portal <-- Web-App (JS/Wasm) fĂŒr Management - │ └── build.gradle.kts (bindet alle Features ein) - │ - ├── 📂 features <-- 💡 CONCEPT: "Vertical Slices" (Micro-Frontends) - │ │ Hier passiert die Arbeit. Ein Feature gehört einem Team. - │ │ - │ ├── 📂 inventory-feature - │ │ ├── 📂 src/commonMain - │ │ │ ├── 📂 api <-- Public Interface (Der Vertrag nach außen) - │ │ │ ├── 📂 ui <-- Screens & Components (Internal) - │ │ │ └── 📂 data <-- Repository & SSoT (Internal) - │ │ └── build.gradle.kts - │ └── 📂 auth-feature - │ - └── 📂 core <-- 💡 CONCEPT: "Shared Foundation" - │ Code, der sich selten Ă€ndert, aber ĂŒberall genutzt wird. - │ - ├── 📂 design-system <-- UI-Baukasten (Farben, Typo, Buttons) - ├── 📂 network <-- HTTP Clients & Auth-Interceptor - ├── 📂 local-db <-- SQLDelight Schemas (Die Offline-Wahrheit) - └── 📂 auth <-- OAuth2 Logik (Browser Bridge fĂŒr Desktop) -``` - ------ - -## 3\. Architectural Decision Records (ADRs) - -Warum haben wir das so gebaut? Hier sind die Antworten auf die "Warum nicht X?" Fragen. - -### ADR 001: Kotlin Multiplatform vs. Electron / Web-Wrapper - -* **Kontext:** Wir brauchen eine Web-App UND eine Desktop-App. -* **Entscheidung:** Wir nutzen **Kotlin Multiplatform (Compose)**. -* **BegrĂŒndung:** - * *Performance:* Electron braucht pro App \~200MB RAM (Chromium Instanz). Unsere Desktop-Apps (Lager, Kasse) laufen auf schwacher Hardware. JVM/Native ist effizienter. - * *Type Safety:* Wir teilen Business-Logik (Validation, SSoT) zwischen Web und Desktop. Mit JS/Electron mĂŒssten wir Logik duplizieren oder transpilen. - * *Offline:* Echte SQL-Datenbank (SQLite) Integration ist in nativem Code robuster als im Browser-Storage. - -### ADR 002: Multiple App Shells vs. One "Super-App" - -* **Kontext:** Wir haben Lagerarbeiter, Kassierer und Manager. -* **Entscheidung:** Wir bauen **pro Rolle eine eigene "Shell"** (Executable). -* **BegrĂŒndung:** - * *Security (Web):* "Tree Shaking". Wenn der Code fĂŒr "Admin-User-Löschen" gar nicht erst in der `warehouse-app.js` enthalten ist, kann er auch nicht gehackt werden. - * *Focus (Desktop):* Die Lager-App startet schneller und hat weniger Bugs, weil sie den Code fĂŒr das Rechnungswesen gar nicht lĂ€dt. - * *FlexibilitĂ€t:* Wir können Features wiederverwenden. Das Feature `auth-feature` ist in ALLEN Apps, `inventory-feature` nur in zweien. - -### ADR 003: Single Source of Truth (SSoT) via Database - -* **Kontext:** Desktop-Apps werden in Hallen mit schlechtem WLAN genutzt. -* **Entscheidung:** **Database First Architecture**. -* **BegrĂŒndung:** - * Klassisch (`UI -> API -> UI`) fĂŒhrt zu weißen Screens und Ladekreisen bei Netzschwankungen. - * Wir nutzen `UI -> Local DB <- Sync -> API`. - * Das UI zeigt **immer** Daten an (auch wenn sie 10 Minuten alt sind). Der User kann arbeiten. Sync passiert transparent im Hintergrund. - -### ADR 004: Docker fĂŒr alles (außer Desktop Runtime) - -* **Kontext:** "Bei mir lĂ€uft's aber..." Probleme. -* **Entscheidung:** Das gesamte Backend + Web-Frontend Build-Pipeline lĂ€uft in Docker. -* **BegrĂŒndung:** - * Die `docker-compose.yml` ist die Wahrheit. - * FĂŒr die Desktop-Entwicklung nutzen wir Gradle lokal, aber der Server, gegen den entwickelt wird, lĂ€uft im Container. Das garantiert IdentitĂ€t zwischen Dev und Prod. - ------ - -## 4\. Guidelines: Wo gehört mein Code hin? - -Wenn du neuen Code schreibst, stelle dir diese Fragen: - -### Q1: Ist es Business Logik (z.B. "Preis berechnen")? - -* âžĄïž Gehört in **`/backend/services/.../domain`** (Server-Side Validierung ist Pflicht). -* âžĄïž UND optional in **`/frontend/features/.../domain`** (fĂŒr schnelle UI-Feedback, aber Server hat das letzte Wort). - -### Q2: Ist es ein UI-Element (z.B. "Runder Button")? - -* âžĄïž Gehört in **`/frontend/core/design-system`**. -* 🛑 *Stop\!* Baue keine Custom Buttons in deinem Feature-Ordner. Nutze das Design System. Wenn etwas fehlt, erweitere das Design System. - -### Q3: Ich brauche Daten von einem anderen Service. - -* **Szenario:** Im "Checkout" (Kasse) brauche ich den Produktnamen aus dem "Inventory". -* ❌ **Falsch:** `CheckoutService` ruft `InventoryService` Datenbank direkt ab. -* ✅ **Richtig (Backend):** `CheckoutService` ruft `InventoryService` via REST/gRPC ĂŒber das Gateway. -* ✅ **Richtig (Frontend):** Das `Checkout-Feature` kennt das `Inventory-Feature` nicht. Es bekommt nur eine `productId`. Wenn es Details anzeigen muss, nutzt es entweder ein eigenes minimales Datenmodell oder fragt das Backend. - -### Q4: Auth Token Handling - -* ❌ **Niemals:** `httpClient.header("Authorization", token)` manuell aufrufen. -* ✅ **Immer:** Nutze den konfigurierten Client aus dem DI-Container: `get(named("apiClient"))`. Die Architektur kĂŒmmert sich um Refresh und Injection. - ------ - -## 5\. Das "Mental Model" fĂŒr Entwickler - -Stell dir unsere App wie einen **Lego-Baukasten** vor. - -1. **Core (Platte):** Das Fundament (Auth, Network, Design). Muss immer da sein. -2. **Features (Steine):** Bunte Bausteine (Inventory, Cart, Profile). Sie berĂŒhren sich seitlich nicht (keine direkten AbhĂ€ngigkeiten). -3. **Shells (Modelle):** Das fertige Haus. - * Haus A (Admin Portal) nutzt alle Steine. - * Haus B (Lager App) nutzt nur die grĂŒnen Steine (Inventory). - -Dein Job als Entwickler ist es meistens, **einen neuen Stein (Feature)** zu bauen oder einen bestehenden zu verbessern. Du musst dich selten um das Fundament oder das fertige Haus kĂŒmmern.