docs(frontend): add detailed offline-first architecture and web setup documentation
Added documentation to outline the Offline-First strategy for the KMP frontend, emphasizing the use of SQLDelight with cross-platform storage. Also included guidance for setting up Web targets, covering OPFS integration and Web Worker usage. Updated ADRs with decisions for SQLDelight and Koin adoption.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
# ADR-0010: SQLDelight für Cross-Platform-Persistenz
|
||||
|
||||
## Status
|
||||
|
||||
Akzeptiert
|
||||
|
||||
## Kontext
|
||||
|
||||
Das "Meldestelle Portal" wird als Kotlin Multiplatform (KMP) Anwendung für Desktop (JVM) und Web (JS/Wasm) entwickelt. Eine zentrale Anforderung ist die **Offline-Fähigkeit**, was eine robuste, plattformübergreifende Persistenzlösung erfordert.
|
||||
|
||||
Die ursprünglich evaluierte Lösung, **Room**, unterstützt die Web-Targets (JS/Wasm) nicht, was die Implementierung der Offline-Fähigkeit im Browser blockiert. Wir benötigen eine Datenbank-Bibliothek, die auf allen Zielplattformen funktioniert und eine moderne, asynchrone API bietet.
|
||||
|
||||
## Entscheidung
|
||||
|
||||
Wir werden **SQLDelight** als primäre Persistenz-Bibliothek für das KMP-Frontend einsetzen.
|
||||
|
||||
* **SQLDelight** generiert typsichere Kotlin-APIs aus SQL-Anweisungen und unterstützt alle KMP-Ziele, einschließlich JVM, JS und Wasm.
|
||||
* **Web (JS/Wasm):** Wir nutzen den `WebWorkerDriver` in Kombination mit dem **Origin Private File System (OPFS)**. Dies ermöglicht eine performante, persistente Speicherung, die im Browser-Kontext in einem Hintergrund-Thread läuft, um die UI nicht zu blockieren.
|
||||
* **Desktop (JVM):** Wir verwenden den `JdbcSqliteDriver`, um eine SQLite-Datenbank im Dateisystem des Benutzers zu speichern.
|
||||
* **Async-First:** Die Datenbank-Schnittstellen werden durch die Option `generateAsync = true` standardmäßig als `suspend`-Funktionen generiert, um den asynchronen Anforderungen der Web-Plattform gerecht zu werden.
|
||||
|
||||
## Konsequenzen
|
||||
|
||||
* **Positive:**
|
||||
* **Echte Cross-Platform-Persistenz:** Wir können dieselbe Datenbanklogik und dasselbe Schema auf allen Zielplattformen wiederverwenden.
|
||||
* **Offline-Fähigkeit im Web:** Die Nutzung von OPFS ermöglicht eine robuste und performante Offline-Speicherung im Browser.
|
||||
* **Typsicherheit:** SQLDelight bietet eine hohe Typsicherheit bei der Interaktion mit der Datenbank.
|
||||
* **Asynchrone API:** Die standardmäßig asynchrone API passt gut zu Kotlin Coroutines und den Anforderungen moderner UIs.
|
||||
|
||||
* **Negative:**
|
||||
* **Erhöhte Komplexität im Web-Setup:** Die Konfiguration von OPFS erfordert spezifische HTTP-Header (`Cross-Origin-Opener-Policy`, `Cross-Origin-Embedder-Policy`), die im Webserver bzw. im Webpack Dev Server gesetzt werden müssen.
|
||||
* **Lernkurve:** Das Team muss sich mit SQLDelight und den Besonderheiten der plattformspezifischen Treiber vertraut machen.
|
||||
|
||||
## Betrachtete Alternativen
|
||||
|
||||
* **Room:** War die ursprüngliche Wahl, wurde aber aufgrund der fehlenden Unterstützung für JS/Wasm verworfen.
|
||||
* **Realm:** Eine weitere plattformübergreifende Datenbank, wurde aber aufgrund der komplexeren Lizenzierung und der engeren Bindung an das Realm-Ökosystem nicht weiter verfolgt.
|
||||
* **IndexedDB (manuell):** Die manuelle Verwendung von IndexedDB im Browser wäre eine Option gewesen, hätte aber zu einer inkonsistenten API zwischen den Plattformen und zu einem erheblichen Mehraufwand bei der Implementierung geführt.
|
||||
|
||||
## Referenzen
|
||||
|
||||
* [Frontend Status Report 01-2026](docs/90_Reports/Frontend_Status_Report_01-2026.md)
|
||||
* [SQLDelight Dokumentation](https://cashapp.github.io/sqldelight/)
|
||||
@@ -0,0 +1,42 @@
|
||||
# ADR-0011: Koin für Dependency Injection
|
||||
|
||||
## Status
|
||||
|
||||
Akzeptiert
|
||||
|
||||
## Kontext
|
||||
|
||||
Das KMP-Frontend benötigt einen Dependency-Injection-Mechanismus, der auf allen Zielplattformen (JVM, JS, Wasm) funktioniert und gut mit Compose Multiplatform integriert ist. Wir müssen sicherstellen, dass die Anwendungslogik (ViewModels, Repositories) lose gekoppelt und leicht testbar ist.
|
||||
|
||||
Besonders wichtig ist die zentrale Bereitstellung von plattformspezifischen Implementierungen (z.B. Datenbank-Treiber) und die Verwaltung von Singletons wie dem Ktor HTTP-Client.
|
||||
|
||||
## Entscheidung
|
||||
|
||||
Wir werden **Koin** als Dependency-Injection-Framework für das KMP-Frontend verwenden.
|
||||
|
||||
* **Koin** ist ein leichtgewichtiger DI-Container, der vollständig in Kotlin geschrieben ist und alle KMP-Ziele unterstützt.
|
||||
* **Compose-Integration:** Koin bietet eine nahtlose Integration mit Compose Multiplatform (`koin-compose`), die es uns ermöglicht, ViewModels und andere Abhängigkeiten direkt in unseren Composable-Funktionen zu injizieren.
|
||||
* **Modulare Konfiguration:** Wir werden Koin-Module verwenden, um die Abhängigkeiten für jede Schicht unserer Anwendung (Core, Features, Shells) zu definieren. Dies fördert die Modularität und Übersichtlichkeit.
|
||||
* **Zentrale Initialisierung:** Die Koin-Anwendung wird in den plattformspezifischen `main`-Funktionen der "Shell"-Module (z.B. `meldestelle-portal`) initialisiert.
|
||||
|
||||
## Konsequenzen
|
||||
|
||||
* **Positive:**
|
||||
* **Plattformübergreifende DI:** Wir können dieselbe DI-Konfiguration auf allen Zielplattformen verwenden.
|
||||
* **Vereinfachte Testbarkeit:** Koin erleichtert das Mocking von Abhängigkeiten in Unit-Tests.
|
||||
* **Gute Integration mit Compose:** Die `koin-compose`-Bibliothek reduziert den Boilerplate-Code bei der Injektion von Abhängigkeiten in die UI.
|
||||
* **Schnelle Lernkurve:** Koin ist im Vergleich zu anderen DI-Frameworks wie Dagger/Hilt relativ einfach zu erlernen und zu verwenden.
|
||||
|
||||
* **Negative:**
|
||||
* **Laufzeit-Fehler:** Koin löst Abhängigkeiten zur Laufzeit auf, was bedeutet, dass Fehler in der DI-Konfiguration erst beim Start der Anwendung oder bei der Verwendung einer Abhängigkeit auftreten (im Gegensatz zu Compile-Zeit-Fehlern bei Dagger/Hilt).
|
||||
* **Service Locator Pattern:** Koin wird manchmal als Service Locator kritisiert, was zu einer weniger strikten Einhaltung von DI-Prinzipien führen kann. Wir werden durch Code-Reviews darauf achten, dass Koin korrekt verwendet wird.
|
||||
|
||||
## Betrachtete Alternativen
|
||||
|
||||
* **Dagger/Hilt:** Dagger und Hilt sind mächtige DI-Frameworks, die Compile-Zeit-Sicherheit bieten. Allerdings ist ihre Konfiguration komplexer und ihre Unterstützung für KMP ist weniger ausgereift als die von Koin.
|
||||
* **Manuelle DI:** Die manuelle Implementierung von Dependency Injection wäre eine Option gewesen, hätte aber zu einem erheblichen Mehraufwand und zu mehr Boilerplate-Code geführt.
|
||||
|
||||
## Referenzen
|
||||
|
||||
* [Koin Dokumentation](https.koin.io)
|
||||
* [Repository-Architektur (MP-22)](docs/01_Architecture/ARCHITECTURE.md) (veraltet, aber erwähnt die DI-Policy)
|
||||
Reference in New Issue
Block a user