diff --git a/docs/99_Journal/2026-04-21_ZNS_Validation_Integration.md b/docs/99_Journal/2026-04-21_ZNS_Validation_Integration.md index afa60dc8..89c7736a 100644 --- a/docs/99_Journal/2026-04-21_ZNS_Validation_Integration.md +++ b/docs/99_Journal/2026-04-21_ZNS_Validation_Integration.md @@ -11,19 +11,20 @@ In dieser Session wurde die Brücke zwischen der Wizard-Runtime und dem ZNS-Impo - **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. + - `EventWizardViewModel`: Einführung von `reEvaluateCurrentStep()`, um den Wizard-Status reaktiv auf Daten-Eingaben und Stammdaten-Updates zu aktualisieren. + - Automatischer Step-Forward: Sobald neue Stammdaten erkannt werden (z. B. nach einem ZNS-Import), springt der Wizard automatisch zum nächsten Schritt. + - `EventWizardScreen`: Der eingebettete `StammdatenImportScreen` nutzt nun `reEvaluateCurrentStep()`, um einen nahtlosen Übergang nach dem Import zu ermöglichen. - **Stabilität:** - - Erfolgreiche Kompilierung des Desktop-Shell-Moduls. + - Erfolgreiche Kompilierung des Desktop-Shell-Moduls (`:frontend:shells:meldestelle-desktop`). - 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. +- **Logic:** Reaktivität des ViewModels durch Einbindung von `reEvaluateCurrentStep()` in alle relevanten State-Änderungen sichergestellt. ## 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. +1. Implementierung der "Veranstalter-Validierung" gegen den lokalen Store im zweiten Wizard-Schritt (Prüfung der OEBS-Nummer). +2. Vorbereitung der Delta-Sync-Logik für den Abgleich mit der Cloud. +3. Optimierung der ZNS-Importer-Performance für große Datensätze. 🏗️ [Lead Architect] | 👷 [Backend Developer] | 🎨 [Frontend Expert] | 🧹 [Curator] diff --git a/frontend/features/veranstaltung-feature/src/jvmMain/kotlin/at/mocode/veranstaltung/feature/presentation/EventWizardScreen.kt b/frontend/features/veranstaltung-feature/src/jvmMain/kotlin/at/mocode/veranstaltung/feature/presentation/EventWizardScreen.kt index bdca07b6..d18db078 100644 --- a/frontend/features/veranstaltung-feature/src/jvmMain/kotlin/at/mocode/veranstaltung/feature/presentation/EventWizardScreen.kt +++ b/frontend/features/veranstaltung-feature/src/jvmMain/kotlin/at/mocode/veranstaltung/feature/presentation/EventWizardScreen.kt @@ -282,7 +282,7 @@ private fun ZnsCheckStep(viewModel: EventWizardViewModel) { .heightIn(max = 500.dp) .padding(vertical = 8.dp) ) { - StammdatenImportScreen(onBack = { viewModel.checkStammdatenStatus() }) + StammdatenImportScreen(onBack = { viewModel.reEvaluateCurrentStep() }) } Button( diff --git a/frontend/features/veranstaltung-feature/src/jvmMain/kotlin/at/mocode/veranstaltung/feature/presentation/EventWizardViewModel.kt b/frontend/features/veranstaltung-feature/src/jvmMain/kotlin/at/mocode/veranstaltung/feature/presentation/EventWizardViewModel.kt index f764a41f..fcf8ef02 100644 --- a/frontend/features/veranstaltung-feature/src/jvmMain/kotlin/at/mocode/veranstaltung/feature/presentation/EventWizardViewModel.kt +++ b/frontend/features/veranstaltung-feature/src/jvmMain/kotlin/at/mocode/veranstaltung/feature/presentation/EventWizardViewModel.kt @@ -153,18 +153,8 @@ class EventWizardViewModel( // 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) - } - } + if (state.currentStep == WizardStep.ZNS_CHECK) { + reEvaluateCurrentStep() } } catch (e: Exception) { state = state.copy(isCheckingStats = false, error = "Fehler beim Laden der Stammdaten-Stats: ${e.message}") @@ -272,6 +262,21 @@ class EventWizardViewModel( stats = state.stammdatenStats ) + fun reEvaluateCurrentStep() { + if (WizardFeatureFlags.WizardRuntimeEnabled) { + val ctx = buildWizardContext() + val current = ensureWizardStateInitialized() + val next = DemoEventFlow.next(ctx, current) + if (next != current) { + wizardState = next + mapToWizardStep(next.current)?.let { + state = state.copy(currentStep = it) + saveDraftInternal(it) + } + } + } + } + private fun buildAccFromState(): DemoEventAcc = DemoEventAcc( veranstalterId = state.veranstalterId?.toString(), veranstalterNr = state.veranstalterVereinsNummer @@ -344,14 +349,17 @@ class EventWizardViewModel( ort = standardOrt, logoUrl = logo ) + reEvaluateCurrentStep() } fun setAnsprechperson(satznummer: String, name: String) { state = state.copy(ansprechpersonSatznummer = satznummer, ansprechpersonName = name) + reEvaluateCurrentStep() } fun updateMetaData(name: String, ort: String, start: LocalDate?, end: LocalDate?, logo: String?) { state = state.copy(name = name, ort = ort, startDatum = start, endDatum = end, logoUrl = logo) + reEvaluateCurrentStep() } fun addTurnier(nummer: String = "", pfad: String? = null) { diff --git a/frontend/shells/meldestelle-desktop/src/jvmMain/kotlin/at/mocode/frontend/shell/desktop/screens/layout/components/ContentArea.kt b/frontend/shells/meldestelle-desktop/src/jvmMain/kotlin/at/mocode/frontend/shell/desktop/screens/layout/components/ContentArea.kt index d04dde11..788d18e5 100644 --- a/frontend/shells/meldestelle-desktop/src/jvmMain/kotlin/at/mocode/frontend/shell/desktop/screens/layout/components/ContentArea.kt +++ b/frontend/shells/meldestelle-desktop/src/jvmMain/kotlin/at/mocode/frontend/shell/desktop/screens/layout/components/ContentArea.kt @@ -340,12 +340,12 @@ fun DesktopContentArea( } is AppScreen.ConnectivityCheck -> { - val viewModel = koinViewModel() - PingScreen( - viewModel = viewModel, - onNavigateToLogin = { onNavigate(AppScreen.Login()) } - ) - } + val viewModel = koinViewModel() + PingScreen( + viewModel = viewModel, + onNavigateToLogin = { onNavigate(AppScreen.Login()) } + ) + } is AppScreen.Profile -> { val viewModel = koinViewModel()