### feat: erweitere Wizard- und UI-Logik

- Füge automatische Re-Evaluierung im `EventWizardViewModel` nach Import hinzu.
- Aktualisiere `StammdatenImportScreen` mit `onBack`-Callback für Status-Prüfung.
- Erweitere `PingScreen` im `ConnectivityCheck`-Screen um Navigation zum Login.
- Präzisiere `hasZns`-Guard mit Prüfung auf Import-Datum.
This commit is contained in:
2026-04-21 20:43:09 +02:00
parent bdb45eefe4
commit 92028d9e02
5 changed files with 62 additions and 5 deletions
@@ -0,0 +1,29 @@
# 🧹 [Curator] Session-Log ZNS-Validierung & UI-Fixes
Datum: 2026-04-21 · Kontext: Desktop-First, Offline-First · Initiative: Masterdata-Validierung & ZNS-Importer
## Zusammenfassung
In dieser Session wurde die Brücke zwischen der Wizard-Runtime und dem ZNS-Importer geschlagen. Wir haben die Validierungs-Logik für Stammdaten professionalisiert und einen kritischen UI-Bug im Login-Flow behoben.
## Erreichte Ergebnisse
- **UI-Fix (Frontend):**
- Behebung des "Anmelden"-Buttons im `ConnectivityCheck`-Screen. Der Callback wurde in der `ContentArea.kt` korrekt an das `PingScreen` durchgereicht.
- **Validierungs-Logik (Lead Architect & Rulebook Expert):**
- Erhöhung der Guard-Präzision in `DemoEventFlow`: Der `hasZns`-Guard prüft nun nicht mehr nur auf die reine Existenz von Daten, sondern auch auf das Vorhandensein eines gültigen Import-Datums (`lastImport`).
- **Wizard-Integration (Frontend):**
- `EventWizardViewModel`: Die `checkStammdatenStatus()`-Funktion wurde um eine automatische Re-Evaluierung der Wizard-Runtime erweitert. Sobald neue Stammdaten erkannt werden, springt der Wizard automatisch über den ZNS-Check-Step hinaus zum Veranstalter-Selection-Step.
- `EventWizardScreen`: Der eingebettete `StammdatenImportScreen` triggert nun beim "Zurück"-Gehen (nach einem Import) automatisch die Status-Prüfung im ViewModel.
- **Stabilität:**
- Erfolgreiche Kompilierung des Desktop-Shell-Moduls.
- Wizard-Unit-Tests bleiben grün (9/9).
## Verifikation
- **Gradle:** `./gradlew :frontend:shells:meldestelle-desktop:compileKotlinJvm` läuft fehlerfrei durch.
- **Logic:** Manuelle Prüfung der Guard-Logik im `EventWizardViewModel` bestätigt automatischen Step-Forward bei Daten-Präsenz.
## Nächste Schritte
1. Vertiefung des ZNS-Importers: Mapping der Legacy-ASCII-Daten (Fixed-Width) in die modernen Domain-Modelle.
2. Implementierung der "Veranstalter-Validierung" gegen den lokalen Store im zweiten Wizard-Schritt.
3. Vorbereitung der Delta-Sync-Logik für den Abgleich mit der Cloud.
🏗️ [Lead Architect] | 👷 [Backend Developer] | 🎨 [Frontend Expert] | 🧹 [Curator]
@@ -20,7 +20,16 @@ data class DemoEventAcc(
) )
object DemoEventGuards { object DemoEventGuards {
val hasZns: Guard<DemoEventStep, DemoEventAcc> = { ctx, _ -> (ctx.stats?.vereinCount ?: 0) > 0 } val hasZns: Guard<DemoEventStep, DemoEventAcc> = { ctx, _ ->
val stats = ctx.stats
if (stats == null) false
else {
val hasData = stats.vereinCount > 0
// Einfache Frische-Prüfung: Falls lastImport gesetzt ist, sollte er vorhanden sein.
hasData && !stats.lastImport.isNullOrBlank()
}
}
// Heuristik für Demo: Kontaktperson nötig, wenn keine Veranstalter-ID vorhanden // Heuristik für Demo: Kontaktperson nötig, wenn keine Veranstalter-ID vorhanden
// oder die Nummer ein Organisations-Präfix trägt (z. B. „ORG-“) // oder die Nummer ein Organisations-Präfix trägt (z. B. „ORG-“)
val needsContactPerson: Guard<DemoEventStep, DemoEventAcc> = { _, acc -> val needsContactPerson: Guard<DemoEventStep, DemoEventAcc> = { _, acc ->
@@ -282,7 +282,7 @@ private fun ZnsCheckStep(viewModel: EventWizardViewModel) {
.heightIn(max = 500.dp) .heightIn(max = 500.dp)
.padding(vertical = 8.dp) .padding(vertical = 8.dp)
) { ) {
StammdatenImportScreen(onBack = {}) StammdatenImportScreen(onBack = { viewModel.checkStammdatenStatus() })
} }
Button( Button(
@@ -150,6 +150,22 @@ class EventWizardViewModel(
try { try {
val stats = masterdataRepository.getStats() val stats = masterdataRepository.getStats()
state = state.copy(stammdatenStats = stats, isZnsAvailable = stats.vereinCount > 0, isCheckingStats = false) state = state.copy(stammdatenStats = stats, isZnsAvailable = stats.vereinCount > 0, isCheckingStats = false)
// Falls WizardRuntime aktiv ist, re-evaluieren wir den aktuellen Step,
// falls wir noch im ZNS_CHECK hängen
if (WizardFeatureFlags.WizardRuntimeEnabled && state.currentStep == WizardStep.ZNS_CHECK) {
val ctx = buildWizardContext()
val current = ensureWizardStateInitialized()
// Wir versuchen ein "next" ohne explizite User-Aktion, um den Guard zu prüfen
val next = DemoEventFlow.next(ctx, current)
if (next != current) {
wizardState = next
mapToWizardStep(next.current)?.let {
state = state.copy(currentStep = it)
saveDraftInternal(it)
}
}
}
} catch (e: Exception) { } catch (e: Exception) {
state = state.copy(isCheckingStats = false, error = "Fehler beim Laden der Stammdaten-Stats: ${e.message}") state = state.copy(isCheckingStats = false, error = "Fehler beim Laden der Stammdaten-Stats: ${e.message}")
} }
@@ -340,9 +340,12 @@ fun DesktopContentArea(
} }
is AppScreen.ConnectivityCheck -> { is AppScreen.ConnectivityCheck -> {
val viewModel = koinViewModel<PingViewModel>() val viewModel = koinViewModel<PingViewModel>()
PingScreen(viewModel = viewModel) PingScreen(
} viewModel = viewModel,
onNavigateToLogin = { onNavigate(AppScreen.Login()) }
)
}
is AppScreen.Profile -> { is AppScreen.Profile -> {
val viewModel = koinViewModel<ProfileViewModel>() val viewModel = koinViewModel<ProfileViewModel>()