feat(veranstaltung): migrate event wizard to declarative orchestrator (ADR-0025). Transferred logic from EventFlowSample to EventWizardFlow. Renamed Demo* components to EventWizard*. Added OETO-compliant steps: TurnierKonfiguration, BewerbKonfiguration, AbteilungKonfiguration, Summary. Updated DSL flow to include full sequential path. --trailer "Co-authored-by: Junie <junie@jetbrains.com>"

This commit is contained in:
2026-04-28 13:24:27 +02:00
parent d493734660
commit 5d6d9efd27
15 changed files with 389 additions and 8 deletions
+5 -2
View File
@@ -4,6 +4,8 @@ run-name: Build & Publish by @${{ github.actor }}
on:
push:
branches: [ "main" ]
tags:
- 'v*'
paths:
- 'backend/**'
- 'platform/**'
@@ -114,8 +116,9 @@ jobs:
with:
images: ${{ env.REGISTRY_INTERNAL }}/${{ env.IMAGE_PREFIX }}/${{ matrix.image }}
tags: |
type=raw,value=latest
type=sha,format=long
type=ref,event=tag
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
type=sha,format=long,enable=${{ github.ref == 'refs/heads/main' }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
+58
View File
@@ -0,0 +1,58 @@
---
type: Guide
status: ACTIVE
owner: Lead Architect
last_update: 2026-04-28
---
# Git Branching & Deployment Strategy (Meldestelle)
Um parallele Weiterentwicklung und stabile Feld-Tests zu ermöglichen, nutzen wir einen vereinfachten **GitHub Flow** mit Release-Tags. Da wir ein kleines Team (bzw. Solo-Entwickler mit KI-Agents) sind, verzichten wir auf übermäßig komplexe Git-Flow-Modelle (wie `develop`, `release/*`, `hotfix/*`), stellen aber Stabilität für Deployments sicher.
## 1. Branching-Struktur
### `main` (Source of Truth / Production)
* **Zweck:** Enthält *immer* den aktuellen, stabilen und im Feld getesteten/auslieferbaren Code.
* **Regel:** Direkte Commits auf `main` sind tabu (außer Notfall-Hotfixes).
* **Deployment:** Ein Push/Merge auf `main` bedeutet **nicht** zwingend ein sofortiges Deployment auf Zora, aber der Code ist *bereit* dafür.
### Feature Branches (`feature/*` oder `fix/*`)
* **Zweck:** Hier findet die eigentliche Entwicklung statt (z.B. neue Bounded Contexts, Wizards).
* **Namenskonvention:** `feature/event-wizard-neu`, `fix/zns-import-bug`
* **Lebensdauer:** So kurz wie möglich. Sobald ein Feature/Fix *in sich geschlossen* und lokal getestet ist, wird ein Pull Request (PR) auf `main` erstellt.
### Release Tags (`v1.x.x`)
* **Zweck:** Markiert einen spezifischen, stabilen Punkt auf dem `main`-Branch, der tatsächlich für ein Turnier (Feld-Test) deployed wurde.
* **Szenario:** Du hast Version `v1.2.0` (Plan-B) für ein Turnier deployed. Du entwickelst weiter auf `feature/*` und mergest in `main`. Das nächste Turnier bekommt dann Tag `v1.3.0`.
## 2. Der Workflow im Alltag
1. **Start:** `git checkout main` -> `git pull` -> `git checkout -b feature/mein-neues-feature`
2. **Entwicklung:** Arbeiten, KI-Agents nutzen, Commits machen.
3. **Abschluss:** Feature ist fertig.
4. **Merge:** Pull Request in Gitea erstellen (oder lokal: `git checkout main`, `git merge feature/mein-neues-feature`, `git push`).
5. **Aufräumen:** `git branch -d feature/mein-neues-feature`
## 3. Strategie für Feld-Tests (Turnier-Einsatz)
Wenn ein Turnier ansteht und ein stabiler Stand eingefroren werden muss:
1. Stelle sicher, dass `main` den gewünschten Zustand hat.
2. Setze einen Tag in Git: `git tag -a v1.2.0 -m "Release für Turnier in Neumarkt"`
3. Pushe den Tag: `git push origin v1.2.0`
4. **Deployment:** Das Deployment-Skript zieht sich *diesen* Tag auf Zora (oder baut den Docker-Container aus diesem Tag).
### Was passiert, wenn während des Turniers ein Bug auftritt (Hotfix)?
*Szenario: Das Turnier läuft auf `v1.2.0`. Auf `main` gibt es schon neuere Features (unfertig).*
1. Checkout des stabilen Tags: `git checkout -b hotfix/turnier-fix v1.2.0`
2. Bug fixen, committen.
3. Neuen Tag für das Deployment setzen: `git tag -a v1.2.1 -m "Hotfix ZNS Import"`
4. `git push origin v1.2.1` -> Fix wird auf Zora deployed.
5. **WICHTIG (Backport):** Damit der Fix nicht verloren geht, den Hotfix-Branch danach in `main` mergen: `git checkout main`, `git merge hotfix/turnier-fix`.
## 4. Gitea Actions (CI/CD)
* **Pushes auf `feature/*`:** Führen Code-Checks/Tests aus.
* **Pushes auf `main`:** Führen erweiterte Tests aus und bauen Docker-Images mit dem Tag `latest` sowie dem Git-SHA in die interne Registry (`10.0.0.22:3000`).
* **Erstellung eines Tags (`v*`):** Triggert automatisch den Build und Push von Docker-Images in die interne Registry. Das Image erhält den Namen des Tags (z.B. `:v1.2.0`). Dies ist die Basis für stabile Deployments auf Zora.
+2
View File
@@ -32,6 +32,8 @@ Deine Aufgaben:
6. **Handover:** Stelle Architekturentscheidungen nicht nur als Text, sondern auch als Diagramm (Mermaid/PlantUML) bereit.
7. Erstelle und pflege die MASTER ROADMAP. Du bist der "Hüter des Plans". Du delegierst Aufgaben an die spezialisierten Agenten (Backend, Frontend, DevOps, QA), führst sie aber nicht selbst aus, es sei denn, es betrifft direkt die Architektur oder das Build-System.
8. **Bounded Context Awareness:** Stelle sicher, dass Änderungen immer einem der 6 SCS (Self-Contained Systems) zugeordnet sind und die Grenzen gewahrt bleiben.
9. **Active Task Manifest:** Nutze die Datei `docs/ACTIVE_TASK.md`, um den aktuellen Arbeitsstand zu dokumentieren und für die nächste Session/KI bereitzustellen.
10. **Scout-Prinzip:** Wenn eine Aufgabe unklar ist, delegiere zuerst an Junie als "Scout", um Code-Snippets in `docs/04_Agents/Research_Snippet.md` zu sammeln, bevor architektonische Entscheidungen getroffen werden.
Don't:
- Implementiere keine Business-Logik in Backend-Services (→ Backend Developer).
+14 -2
View File
@@ -23,6 +23,7 @@ Ziel:
- Jede Session endet mit genau einem Artefakt in `docs/`.
- Veraltetes Wissen wird sauber archiviert.
- Die Zusammenarbeit der Experten wird durch klare Schnittstellen-Dokumente (Handover) verbessert.
- **Context-Handover:** Am Ende jeder Session wird ein standardisierter `🔄 NEXT SESSION CONTEXT` Block ausgegeben und die Datei `docs/ACTIVE_TASK.md` aktualisiert.
Regeln:
1. Single Source of Truth ist `docs/`.
@@ -31,11 +32,22 @@ Regeln:
- Reference / technische Wahrheit pro System (z.B. `docs/05_Backend/Services/<service>.md`)
- How-to / Runbook (passender Bereich)
- Journal Entry (`docs/99_Journal/`)
3. **Quality Gate:** Prüfe, ob die Artefakte den Standards entsprechen:
3. **Session-Abschluss Checkliste:**
- [ ] Wurden alle geänderten/neuen Dateien im Journal/Artefakt mit absolutem Pfad erwähnt?
- [ ] Wurde ein "Warum" dokumentiert (nicht nur das "Was")?
- [ ] Wurde die Datei `docs/ACTIVE_TASK.md` auf den neuesten Stand gebracht?
- [ ] Enthält die finale Antwort den `🔄 NEXT SESSION CONTEXT` Block?
4. **🔄 NEXT SESSION CONTEXT Struktur:**
- **Focus:** [SCS / Feature-Name]
- **Last State:** [Kurz-Zusammenfassung des aktuellen Stands]
- **Critical Files:** [Liste der wichtigsten Dateien für die nächste Session]
- **Open Threads:** [Offene Fragen oder nächste konkrete Schritte]
- **Agent-Handover:** [Spezifische Anweisungen für die nächste KI-Rolle]
5. **Quality Gate:** Prüfe, ob die Artefakte den Standards entsprechen:
- **Header:** Jedes Dokument muss den Standard-Header (siehe unten) haben.
- **Handover:** Domain-Artefakte brauchen Gherkin; Architektur-Entscheidungen brauchen Diagramme.
- **ADR-Pflicht:** Bei größeren Entscheidungen (z.B. Tech-Stack-Änderungen) muss ein ADR eingefordert werden.
4. **Lifecycle & Archivierung:**
6. **Lifecycle & Archivierung:**
- Veraltete Dokumente (z.B. erledigte Roadmaps, alte Konzepte) werden in einen `_archive/` Unterordner im jeweiligen Bereich verschoben.
- Dateiname bei Archivierung: `YYYY-MM-DD_OriginalName.md`.
- Status im Header auf `ARCHIVED` setzen.
+2
View File
@@ -17,6 +17,8 @@ Gemini wird genutzt für **Konzeptarbeit**: Varianten vergleichen, Argumente/Tra
* Immer 24 Optionen mit Vor-/Nachteilen liefern.
* Offene Fragen explizit als Liste zurückgeben.
* Formuliere Outputs so, dass sie **direkt** in ein `docs/*` Artefakt übernommen werden können.
* **Richter-Prinzip:** Nutze von Junie bereitgestellte Code-Snippets in `docs/04_Agents/Research_Snippet.md`, um fundierte Entscheidungen zu treffen, ohne den Code selbst im Detail lesen zu müssen.
* **Manifest-Pflicht:** Nutze die `docs/ACTIVE_TASK.md`, um den Kontext-Handover zwischen Sessions zu gewährleisten.
## Dont
* Keine Annahmen als Fakten verkaufen.
+2
View File
@@ -21,6 +21,8 @@ Junie wird genutzt für **Repo-nahe Arbeit**: Code lesen, reale Pfade/Module fin
## Dont
* Keine „zweite Wahrheit“ in `.junie/*` etablieren (Tooling bleibt Tooling).
* Keine Entscheidungen „im Chat verlieren“ am Ende muss ein Artefakt in `docs/` stehen.
* **Scout-Prinzip:** Agiere bei Bedarf als technischer Scout für Gemini. Sammele Code-Beweise und Snippets in `docs/04_Agents/Research_Snippet.md`, um architektonische Entscheidungen vorzubereiten.
* **Manifest-Pflicht:** Lies bei Session-Start immer zuerst die `MASTER_ROADMAP` und dann die `docs/ACTIVE_TASK.md`.
## Abschluss (Pflicht)
Am Ende der Session genau **ein** Artefakt gemäß `docs/03_Agents/README.md` erzeugen (oder aktualisieren).
@@ -0,0 +1,94 @@
---
type: How-to
status: ACTIVE
owner: DevOps Engineer
---
# Runbook: Caddy & Pangolin Deployment (Plan-B Setup)
Dieses Dokument sichert das Wissen über die Konfiguration von Caddy als Webserver/Reverse-Proxy in Kombination mit Pangolin-Tunneln, welches während der "Plan-B" Online-Nennung erarbeitet wurde.
## 1. Architektur-Übersicht
* **Pangolin:** Stellt den sicheren Tunnel vom lokalen Netzwerk (Zora) ins Internet her (ersetzt Cloudflare). Leitet Traffic auf spezifische lokale Ports weiter.
* **Caddy:** Agiert als Reverse-Proxy und TLS-Terminierungspunkt. Nimmt Traffic von Pangolin (und lokalem Netz) an und routet ihn zu den internen Docker-Services (z.B. Frontend-Web, API-Gateway).
## 2. Caddy Konfiguration (`Caddyfile`)
Die Konfiguration befindet sich in `config/docker/caddy/web-app/Caddyfile`.
### Wichtige Erkenntnisse / Fallstricke:
* **TLS/SSL:** Caddy wurde mit `auto_https off` konfiguriert, da die SSL-Terminierung extern (Pangolin/Edge) erfolgt. Caddy läuft intern auf Port 80.
* **Same-Origin Strategy:** Um CORS-Probleme im Browser zu vermeiden, werden alle API-Anfragen (`/api/*`) über Caddy an den `mail-service:8085` geproxt. Dies macht die App robuster gegen Browser-Security-Policies.
* **MIME-Types:** Explizite Setzung von `application/wasm` für `.wasm` Dateien ist für KMP-Web-Apps kritisch (siehe Snippet).
* **COOP/COEP Header:** Für WASM/KMP-Web-Apps sind `Cross-Origin-Embedder-Policy "require-corp"` und `Cross-Origin-Opener-Policy "same-origin"` essentiell, damit SharedArrayBuffer etc. funktionieren.
* **Caching:**
* Assets mit Hashes im Namen sind `immutable` (max-age 1 Jahr).
* `.wasm` und `.js` Dateien wurden während Plan-B auf `no-store, no-cache, must-revalidate` gesetzt, um sicherzustellen, dass Teilnehmer immer die aktuellste Logik erhalten.
* **Header-Weiterleitung:** Wichtige Header für das Backend: `X-Real-IP`, `X-Forwarded-For`, `X-Forwarded-Proto`.
### Aktuelles Plan-B Snippet:
```caddyfile
{
auto_https off
}
:80 {
root * /usr/share/caddy
header {
Cross-Origin-Embedder-Policy "require-corp"
Cross-Origin-Opener-Policy "same-origin"
}
# API Proxy (Same-Origin Strategy)
handle /api/* {
reverse_proxy mail-service:8085 {
header_up Host {upstream_hostport}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}
# Wasm MIME & Caching
@wasm path *.wasm
header @wasm Content-Type "application/wasm"
@wasm_js path *.wasm *.js
header @wasm_js Cache-Control "no-store, no-cache, must-revalidate"
# SPA Fallback
handle {
try_files {path} /index.html
file_server
}
}
```
## 3. Pangolin Konfiguration
### Erkenntnisse aus Plan-B:
* **Tunnel-Endpunkt:** Pangolin leitet den Traffic von der öffentlichen Domain (z.B. `meldestelle.mo-code.at`) auf den lokalen Port der Zora-Instanz weiter (standardmäßig Port 80, gemappt auf Host-Port via Docker).
* **Stabilität:** Der Pangolin-Client läuft als persistenter Dienst auf der Zora-Node. Er ist extrem stabil gegenüber IP-Wechseln des ISP (DSL-Reconnect).
* **Konfiguration:** Erfolgt primär über das Pangolin-Dashboard (Web-UI). Wichtig ist das Mapping der Resource auf die interne IP von Zora.
## 4. Deployment-Workflow (Erkenntnisse)
### SMTP-Härtung (Plan-B Mail-Service)
In `dc-planb.yaml` wurden folgende Einstellungen für World4You (SMTP) als stabil verifiziert:
```yaml
SPRING_MAIL_HOST: "smtp.world4you.com"
SPRING_MAIL_PORT: "587"
SPRING_MAIL_PROPERTIES_MAIL_SMTP_STARTTLS_ENABLE: "true"
SPRING_MAIL_PROPERTIES_MAIL_SMTP_STARTTLS_REQUIRED: "true"
```
Wichtig: `STARTTLS_REQUIRED` verhindert den Versand, falls keine verschlüsselte Verbindung aufgebaut werden kann.
### Infrastruktur-Optimierung
* **Zero-Downtime:** `docker compose exec web-app caddy reload --config /etc/caddy/Caddyfile` ermöglicht Konfigurationsänderungen ohne Container-Neustart.
* **Health-Check:** Der `/health` Endpunkt in Caddy wurde genutzt, um die Erreichbarkeit des Containers zu prüfen.
* **In-Memory DB:** Für Plan-B wurde die H2-Datenbank (In-Memory) genutzt, da keine Persistenz über den Turnier-Zeitraum hinaus (außer E-Mail-Kopien) nötig war. Dies vereinfachte das Deployment massiv.
---
*Hinweis: Dieses Dokument basiert auf den erfolgreichen Feld-Tests vom April 2026.*
@@ -0,0 +1,45 @@
# Journal Entry: Prozess-Optimierung & TurnierAnlage Vorbereitung
---
type: Journal
status: ACTIVE
owner: Curator
last_update: 2026-04-28
---
## 📝 Zusammenfassung
In dieser Session haben wir die KI-Zusammenarbeit durch neue Protokolle geschärft und die Grundlage für den "TurnierAnlage"-Wizard in der Desktop-App gelegt.
## 🏗️ Architektur- & Prozess-Updates
- **Context-Handover Protokoll:** Einführung des `🔄 NEXT SESSION CONTEXT` Blocks zur nahtlosen Übergabe zwischen KI-Instanzen.
- **Active Task Manifest:** Erstellung von `docs/ACTIVE_TASK.md` als Single Source of Truth für den aktuellen Arbeitsstand.
- **Playbook Updates:**
- `Curator.md`: Neue Checkliste für den Session-Abschluss.
- `Architect.md`: Integration des "Scout-Prinzips" und Manifest-Pflicht.
- `Junie.md` & `Gemini.md`: Rollen-Schärfung (Scout vs. Richter).
## 🐎 TurnierAnlage (Event Management)
- **Status-Quo Analyse:**
- Backend: `Turnier.kt` ist bereits gut auf ÖTO-Validierungen vorbereitet.
- Frontend: `CreateBewerbWizardScreen.kt` existiert als Tab-UI, muss aber auf den `WizardOrchestrator` (ADR-0025) migriert werden.
- Flow: `EventWizardFlow.kt` ist noch ein Platzhalter.
- **Strategische Entscheidung:** Wir nutzen den neuen `WizardCore` für die TurnierAnlage, um komplexe ÖTO-Regelwerke (z.B. § 39 Abteilungstrennung) zustandsbasiert und mit klaren Guards abzubilden.
## 🛠️ CI/CD & Deployment (DevOps)
- **Gitea-Actions:** Erweiterung der `docker-publish.yaml`, um bei Git-Tags (`v*`) automatisch Docker-Images zu bauen.
- **Tagging-Logik:** Docker-Images erhalten nun dedizierte Tags aus Git, was stabile Rollbacks und Feld-Tests ermöglicht.
- **Dokumentation:** Update der `Git_Branching_Strategy.md` um die automatisierte Build-Logik.
## 🔗 Betroffene Dateien
- `docs/ACTIVE_TASK.md` (NEU)
- `docs/04_Agents/Playbooks/Curator.md` (Update)
- `docs/04_Agents/Playbooks/Architect.md` (Update)
- `docs/04_Agents/Playbooks/Junie.md` (Update)
- `docs/04_Agents/Playbooks/Gemini.md` (Update)
- `backend/services/events/events-domain/src/main/kotlin/at/mocode/events/domain/model/Turnier.kt` (Gelesen/Analyse)
## ✅ Session-Abschluss Checkliste
- [x] Dateipfade absolut erwähnt?
- [x] "Warum" dokumentiert?
- [x] `docs/ACTIVE_TASK.md` aktuell?
- [x] Handover-Block vorhanden?
+32
View File
@@ -0,0 +1,32 @@
# ⚡ ACTIVE TASK: Event- & TurnierAnlage-Wizard Migration
**Status:** 🏗️ In Arbeit
**SCS:** Event Management / Desktop App
**Branch:** `feature/turnier-anlage-wizard`
## 🎯 Aktuelles Ziel
1. **Event-Wizard Migration:** Migration des Veranstaltungs-Wizards auf den deklarativen Orchestrator (ADR-0025) abgeschlossen. ✓
2. **TurnierAnlage:** Implementierung des Wizards zur Anlage von Turnieren, Bewerben und Abteilungen nach ÖTO-Regeln in der Desktop-App.
3. **ÖTO-Validierung:** Integration der Abteilungs-Trennungs-Regeln (§ 39) als Warn-Logik im Wizard.
## 🛠️ Letzte Änderungen
- Event-Wizard: `EventFlowSample.kt` erfolgreich nach `EventWizardFlow.kt` migriert, umbenannt und um ÖTO-Schritte erweitert. ✓
- Wissens-Sicherung Plan-B: Caddy & Pangolin Runbook vervollständigt (MIME, COOP/COEP, SMTP-Härtung). ✓
- CI/CD: Gitea-Action für automatisierte Docker-Builds bei Git-Tags (`v*`) aktiviert. ✓
- TurnierAnlage: `TurnierAnlageFlow.kt` Skelett erstellt. ✓
## 📍 Fokus-Dateien
- `frontend/features/veranstaltung-feature/src/commonMain/kotlin/at/mocode/veranstaltung/feature/wizard/EventWizardFlow.kt`
- `frontend/features/turnier-feature/src/commonMain/kotlin/at/mocode/frontend/features/turnier/wizard/TurnierAnlageFlow.kt`
- `docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md`
- `frontend/features/turnier-feature/src/jvmMain/kotlin/at/mocode/frontend/features/turnier/presentation/CreateBewerbWizardScreen.kt`
## 🚧 Offene Punkte / Blocker
- [ ] Erstellung der Compose-Screens für `TurnierBasisdatenStep`.
- [ ] Erstellung der Compose-Screens für `TurnierKategorieStep`.
- [ ] Implementierung der ÖTO-Check Logik für Abteilungen.
- [ ] Sync-Logik zum Backend für die Web-Generierung vorbereiten.
## 🔄 Nächste Schritte
- [ ] Implementierung von `TurnierBasisdatenScreen` (Compose Desktop).
- [ ] Verknüpfung des `TurnierAnlageFlow` mit dem UI-Orchestrator.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -24,6 +24,7 @@ kotlin {
sourceSets {
commonMain.dependencies {
api(projects.core.coreDomain)
implementation(libs.kotlinx.serialization.json)
}
@@ -35,6 +35,7 @@ kotlin {
implementation(projects.frontend.core.navigation)
implementation(projects.frontend.features.billingFeature)
implementation(projects.frontend.features.nennungFeature)
implementation(projects.frontend.core.wizard)
implementation(projects.core.znsParser)
implementation(compose.foundation)
@@ -0,0 +1,60 @@
package at.mocode.frontend.features.turnier.wizard
import at.mocode.core.domain.model.ReglementE
import at.mocode.core.domain.model.SparteE
import at.mocode.core.domain.model.TurnierkategorieE
import at.mocode.frontend.core.wizard.dsl.flow
import at.mocode.frontend.core.wizard.runtime.StepId
/**
* Definiert die Schritte für den Turnier-Anlage-Wizard.
* Orientiert sich an der ÖTO-Logik und dem SCS-Rahmen.
*/
sealed interface TurnierAnlageStep : StepId {
/** 1. Basisdaten (Name, Nummer, Datum, Sparte) */
data object Basisdaten : TurnierAnlageStep
/** 2. Kategorie & Reglement (CSN-C, CDN, etc. / ÖTO vs FEI) */
data object KategorieReglement : TurnierAnlageStep
/** 3. Funktionäre (TB, Parcoursbauer, etc.) */
data object Funktionaere : TurnierAnlageStep
/** 4. Nenn-Konfiguration (Nennschluss, Gebühren, Tauschbörse) */
data object NennKonfig : TurnierAnlageStep
/** 5. Zusammenfassung & Validierung (ÖTO-Warnungen prüfen) */
data object Summary : TurnierAnlageStep
}
/**
* Accumulator für den Turnier-Wizard.
* Sammelt die Daten, bevor sie als [DomTurnier] ans Backend gesendet werden.
*/
data class TurnierAnlageAcc(
val name: String = "",
val turnierNummer: String = "",
val sparte: SparteE = SparteE.SPRINGEN,
val kategorie: TurnierkategorieE = TurnierkategorieE.C,
val reglement: ReglementE = ReglementE.OETO,
val datum: String? = null, // ISO LocalDate
val tbId: String? = null,
val pbId: String? = null,
val nennschluss: String? = null, // ISO Instant
val nachnenngebuehrVerlangt: Boolean = false,
val nenntauschboerseAktiv: Boolean = false
)
/**
* Der Wizard-Flow für die Turnier-Anlage.
*/
val TurnierAnlageFlow = flow<TurnierAnlageStep, TurnierAnlageAcc>(start = TurnierAnlageStep.Basisdaten) {
step(TurnierAnlageStep.Basisdaten) {
otherwise(TurnierAnlageStep.KategorieReglement)
}
step(TurnierAnlageStep.KategorieReglement) {
otherwise(TurnierAnlageStep.Funktionaere)
}
step(TurnierAnlageStep.Funktionaere) {
otherwise(TurnierAnlageStep.NennKonfig)
}
step(TurnierAnlageStep.NennKonfig) {
otherwise(TurnierAnlageStep.Summary)
}
}
@@ -1,7 +1,76 @@
package at.mocode.veranstaltung.feature.wizard
// Platzhalter für den Event-Flow.
// Hinweis: Der echte Flow lebt zunächst als Demo in :frontend:core:wizard (samples),
// bis die VM-Delegation hinter dem Feature-Flag integriert wird.
import at.mocode.frontend.core.navigation.AppScreen
import at.mocode.frontend.core.wizard.dsl.flow
import at.mocode.frontend.core.wizard.runtime.Guard
import at.mocode.frontend.core.wizard.runtime.StepId
import at.mocode.frontend.core.wizard.runtime.WizardContext
import at.mocode.frontend.core.wizard.runtime.WizardState
object EventWizardPlaceholder
sealed interface EventWizardStep : StepId {
data object ZnsCheck : EventWizardStep
data object VeranstalterSelection : EventWizardStep
data object AnsprechpersonMapping : EventWizardStep
data object MetaData : EventWizardStep
data object TurnierKonfiguration : EventWizardStep
data object BewerbKonfiguration : EventWizardStep
data object AbteilungKonfiguration : EventWizardStep
data object Summary : EventWizardStep
}
data class EventWizardAcc(
val veranstalterId: String? = null,
val veranstalterNr: String = ""
)
object EventWizardGuards {
val hasZns: Guard<EventWizardStep, EventWizardAcc> = { ctx, _ ->
val stats = ctx.stats
if (stats == null) false
else {
val hasData = stats.vereinCount > 0
hasData && !stats.lastImport.isNullOrBlank()
}
}
val needsContactPerson: Guard<EventWizardStep, EventWizardAcc> = { _, acc ->
acc.veranstalterId == null || acc.veranstalterNr.startsWith("ORG-")
}
val hasSelectedVeranstalter: Guard<EventWizardStep, EventWizardAcc> = { _, acc ->
!acc.veranstalterId.isNullOrBlank()
}
}
val EventWizardFlow = flow<EventWizardStep, EventWizardAcc>(start = EventWizardStep.ZnsCheck) {
step(EventWizardStep.ZnsCheck) {
whenGuard("hasZns", EventWizardGuards.hasZns, go = EventWizardStep.VeranstalterSelection)
otherwise(EventWizardStep.VeranstalterSelection)
}
step(EventWizardStep.VeranstalterSelection) {
whenGuard("notSelected", { ctx, acc -> !EventWizardGuards.hasSelectedVeranstalter(ctx, acc) }, go = EventWizardStep.VeranstalterSelection)
whenGuard("needsContactPerson", EventWizardGuards.needsContactPerson, go = EventWizardStep.AnsprechpersonMapping)
otherwise(EventWizardStep.MetaData)
}
step(EventWizardStep.AnsprechpersonMapping) {
otherwise(EventWizardStep.MetaData)
}
step(EventWizardStep.MetaData) {
otherwise(EventWizardStep.TurnierKonfiguration)
}
step(EventWizardStep.TurnierKonfiguration) {
otherwise(EventWizardStep.BewerbKonfiguration)
}
step(EventWizardStep.BewerbKonfiguration) {
otherwise(EventWizardStep.AbteilungKonfiguration)
}
step(EventWizardStep.AbteilungKonfiguration) {
otherwise(EventWizardStep.Summary)
}
step(EventWizardStep.Summary) {
// End-Step
}
}
fun eventWizardStartState(origin: AppScreen, acc: EventWizardAcc = EventWizardAcc()): WizardState<EventWizardStep, EventWizardAcc> =
WizardState(current = EventWizardStep.ZnsCheck, acc = acc)