meldestelle/client/common-ui/README-CLIENT-COMMON-UI.md
2025-08-16 15:47:57 +02:00

9.4 KiB

Client Common-UI Modul

Überblick

Das common-ui Modul stellt die geteilten Benutzeroberflächen-Komponenten und Geschäftslogik für die Meldestelle Client-Anwendungen bereit. Dieses Modul implementiert die Kern-"Tracer Bullet" Funktionalität unter Verwendung eines modernen MVVM-Architekturmusters und dient sowohl der Desktop- als auch der Web-Anwendung.

Hauptfunktionen:

  • 🏗️ MVVM-Architektur - ordnungsgemäße Trennung der Belange mit ViewModel-Muster
  • 🌐 Plattformübergreifend - geteilter Code für Desktop (JVM) und Web (JavaScript) Anwendungen
  • 🎯 Vier UI-Zustände - vollständige Implementierung gemäß trace-bullet-guideline.md
  • 🔧 Ressourcenverwaltung - ordnungsgemäßer HttpClient-Lebenszyklus und Speicherverwaltung
  • 🧪 Testabdeckung - umfassende Testsuite für alle kritischen Funktionen

Architektur

Modulstruktur

client/common-ui/src/
├── commonMain/kotlin/at/mocode/client/
│   ├── data/service/
│   │   ├── PingResponse.kt        # Datenmodell für API-Antworten
│   │   └── PingService.kt         # HTTP-Service mit Ressourcenverwaltung
│   └── ui/
│       ├── App.kt                 # Hauptanwendungskomponente
│       └── viewmodel/
│           └── PingViewModel.kt   # MVVM-Zustandsverwaltung
└── commonTest/kotlin/at/mocode/client/
    ├── data/service/
    │   ├── PingResponseTest.kt    # Datenmodell-Tests
    │   └── PingServiceTest.kt     # Service-Schicht-Tests
    └── ui/viewmodel/
        └── PingViewModelTest.kt   # ViewModel- und Zustands-Tests

MVVM-Muster Implementierung

PingUiState (Sealed Class):

  • Initial - Neutrale Nachricht, Button aktiv
  • Loading - Ladeindikator, Button deaktiviert
  • Success - Positive Antwortanzeige, Button aktiv
  • Error - Klare Fehlernachricht, Button aktiv

PingViewModel:

  • Verwaltet UI-Zustandsübergänge
  • Behandelt Coroutine-Lebenszyklus
  • Ordnungsgemäße Ressourcenentsorgung

PingService:

  • HTTP-Client-Verwaltung
  • Result-Wrapper-Muster
  • Ressourcen-Bereinigungsunterstützung

Abhängigkeiten

Laufzeit-Abhängigkeiten

// Compose Multiplatform UI
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)

// Netzwerk & Serialisierung
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.contentNegotiation)
implementation(libs.ktor.client.serialization.kotlinx.json)
implementation(libs.kotlinx.serialization.json)

// Coroutines
implementation(libs.kotlinx.coroutines.core)

Plattformspezifische Abhängigkeiten

// JVM (Desktop)
jvmMain {
    implementation(libs.ktor.client.cio)
}

// JS (Web)
jsMain {
    implementation(libs.ktor.client.js)
}

Test-Abhängigkeiten

commonTest {
    implementation(libs.kotlin.test)
    implementation(libs.kotlinx.coroutines.test)
}

Verwendung

Grundlegende Integration

@Composable
fun YourApplication() {
    // Verwendet at.mocode.client.ui.App
    App(baseUrl = "https://your-api.com")
}

Erweiterte Verwendung mit benutzerdefinierter Konfiguration

// Benutzerdefinierte Service-Konfiguration
// Verwendet at.mocode.client.data.service.PingService
val customService = PingService(
    baseUrl = "https://custom-api.com",
    httpClient = createCustomHttpClient()
)

// Benutzerdefiniertes ViewModel mit spezifischem Scope
// Verwendet at.mocode.client.ui.viewmodel.PingViewModel
val customViewModel = PingViewModel(
    pingService = customService,
    coroutineScope = customCoroutineScope
)

API-Referenz

PingService

class PingService(
    private val baseUrl: String = "http://localhost:8080",
    private val httpClient: HttpClient = createDefaultHttpClient()
) {
    suspend fun ping(): Result<PingResponse>
    fun close()

    companion object {
        fun createDefaultHttpClient(): HttpClient
    }
}

PingViewModel

class PingViewModel(
    private val pingService: PingService,
    private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
) {
    var uiState: PingUiState by mutableStateOf(PingUiState.Initial)
        private set

    fun pingBackend()
    fun dispose()
}

PingUiState

sealed class PingUiState {
    data object Initial : PingUiState()
    data object Loading : PingUiState()
    data class Success(val response: PingResponse) : PingUiState()
    data class Error(val message: String) : PingUiState()
}

Entwicklung

Das Modul erstellen

# Für alle Plattformen kompilieren
./gradlew :client:common-ui:build

# Nur JVM-Kompilierung
./gradlew :client:common-ui:compileKotlinJvm

# Nur JavaScript-Kompilierung
./gradlew :client:common-ui:compileKotlinJs

Tests ausführen

# Alle Tests ausführen
./gradlew :client:common-ui:jvmTest

# Spezifische Testklasse ausführen
./gradlew :client:common-ui:jvmTest --tests "PingViewModelTest"

Codequalität

Das Modul hält hohe Codequalitätsstandards aufrecht:

  • Testabdeckung: 32 umfassende Tests über alle Schichten
  • Architektur-Konformität: 100% MVVM-Muster-Einhaltung
  • Ressourcenverwaltung: Ordnungsgemäßer Lebenszyklus und Bereinigung
  • Speichersicherheit: Keine Speicherlecks durch ordnungsgemäße Entsorgung

Tests

Testabdeckung Übersicht

Komponente Test-Datei Tests Abdeckung
PingResponse PingResponseTest.kt 7 Datenmodell, Serialisierung
PingService PingServiceTest.kt 10 HTTP-Service, Lebenszyklus
PingViewModel PingViewModelTest.kt 8 MVVM, Zustandsverwaltung

Spezifische Test-Suites ausführen

# Datenschicht-Tests
./gradlew :client:common-ui:jvmTest --tests "*PingResponseTest*"

# Service-Schicht-Tests
./gradlew :client:common-ui:jvmTest --tests "*PingServiceTest*"

# ViewModel-Tests
./gradlew :client:common-ui:jvmTest --tests "*PingViewModelTest*"

Architektur-Vorteile

🏗️ Moderne MVVM-Implementierung

  • Testbarkeit: Ordnungsgemäße Dependency Injection ermöglicht umfassende Unit-Tests
  • Wartbarkeit: Klare Trennung der Belange und Single-Responsibility-Prinzip
  • Skalierbarkeit: Architektur unterstützt zukünftige Funktionserweiterungen nahtlos

🚀 Laufzeit-Effizienz

  • Ressourcenverwaltung: Ordnungsgemäße HttpClient-Bereinigung verhindert Speicherlecks
  • Leistung: Eliminierung unnötiger Operationen und Callback-Muster
  • Stabilität: Verbesserte Fehlerbehandlung und Zustandsverwaltung

🔧 Entwicklererfahrung

  • Code-Klarheit: Selbstdokumentierender Code mit Sealed Classes und klarer Benennung
  • Debugging: Einfache Zustandsverfolgung und Problemidentifikation
  • Integration: Einfaches Integrationsmuster für abhängige Module

Migrations-Hinweise

Von der vorherigen Implementierung

Das Modul wurde vollständig von einem komponentenbasierten Ansatz zu MVVM refaktoriert:

Vorher (Komponentenbasiert):

  • Vermischte Belange in einzelnen Dateien
  • Callback-basierte Zustandsverwaltung
  • Manuelle Ressourcenverwaltung
  • Speicherleck-Potenzial

Nachher (MVVM):

  • Klare Trennung der Belange
  • Compose-Zustandsverwaltung
  • Automatische Ressourcenbereinigung
  • Speicherleck-Prävention

Breaking Changes

Keine - Das Refactoring behielt vollständige Rückwärtskompatibilität für abhängige Module bei.


Zukünftige Entwicklung

Empfohlene Verbesserungen

  1. Konfigurationsverwaltung

    • Umgebungsspezifische Einstellungen
    • Konfigurationsvalidierung
  2. Fehlerbehandlung

    • Spezifische Fehlertypen
    • Wiederholungsmechanismen für Netzwerkausfälle
  3. Monitoring-Integration

    • Metriken-Sammlung
    • Leistungsüberwachung
  4. Internationalisierung

    • Mehrsprachige Unterstützung
    • Sprachspezifische Formatierung

Mitwirken

Entwicklungsumgebung einrichten

  1. Stellen Sie sicher, dass JDK 21 installiert ist
  2. Klonen Sie das Repository
  3. Führen Sie ./gradlew :client:common-ui:build aus, um die Einrichtung zu verifizieren

Code-Standards

  • Befolgen Sie Kotlin-Codierungskonventionen
  • Fügen Sie Tests für neue Funktionalität hinzu
  • Behalten Sie MVVM-Architekturmuster bei
  • Stellen Sie ordnungsgemäße Ressourcenverwaltung sicher

Test-Anforderungen

  • Alle öffentlichen APIs müssen Tests haben
  • Mindestens 90% Testabdeckung für neue Features
  • Integrationstests für modulübergreifende Funktionalität

Fehlerbehebung

Häufige Probleme

Problem Lösung
HttpClient nicht ordnungsgemäß geschlossen Stellen Sie sicher, dass dispose() im ViewModel aufgerufen wird
Zustand wird in UI nicht aktualisiert Überprüfen Sie die Compose-Zustandsbeobachtung-Einrichtung
Netzwerk-Timeouts Überprüfen Sie baseUrl-Konfiguration und Konnektivität
Test-Fehler auf JS-Plattform Verwenden Sie JS-kompatible Test-Muster (keine Reflection)

Debug-Informationen

# Abhängigkeitskonflikte überprüfen
./gradlew :client:common-ui:dependencies

# Ausführliche Test-Ausgabe
./gradlew :client:common-ui:jvmTest --info

# Build-Scan für detaillierte Analyse
./gradlew :client:common-ui:build --scan

Modul-Status: Produktionsbereit Architektur: MVVM-konform Testabdeckung: Umfassend (32 Tests) Dokumentation: Vollständig

Zuletzt aktualisiert: 16. August 2025