meldestelle/docs/01_Architecture/Reference/Wizard-DSL-README.md
2026-04-21 16:21:22 +02:00

108 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
type: Reference
status: ACTIVE
owner: Lead Architect
date: 2026-04-21
---
# WizardDSL & Orchestrator Referenz
## Ziel
Deklarative Beschreibung von WizardFlows als Graph (Steps, Guards, Transitions) mit klaren SideEffects und OfflineDraftUnterstützung.
## KernInterfaces (Skizze)
```kotlin
interface StepId
data class WizardContext(
val origin: AppScreen,
val role: String?,
val isOnline: Boolean,
val stats: MasterdataStats?
)
data class WizardState<S: StepId, A>(
val current: S,
val history: List<S> = emptyList(),
val acc: A,
val errors: List<String> = emptyList()
)
typealias Guard<S, A> = (WizardContext, A) -> Boolean
data class Transition<S: StepId>(val target: S, val guard: Guard<S, *>? = null, val id: String)
interface StepEffects<S: StepId, A> {
suspend fun onEnter(ctx: WizardContext, state: WizardState<S, A>) {}
suspend fun onLeave(ctx: WizardContext, state: WizardState<S, A>) {}
suspend fun onComplete(ctx: WizardContext, state: WizardState<S, A>) {}
}
```
## DSL (Skizze)
```kotlin
class FlowBuilder<S: StepId, A> {
fun step(id: S, block: StepBuilder<S, A>.() -> Unit) { /* … */ }
}
class StepBuilder<S: StepId, A> {
fun onEnter(block: suspend (WizardContext, WizardState<S, A>) -> Unit) { /* … */ }
fun whenGuard(id: String, g: Guard<S, A>, go: S) { /* … */ }
fun otherwise(go: S) { /* … */ }
}
fun <S: StepId, A> flow(start: S, build: FlowBuilder<S, A>.() -> Unit): WizardRuntime<S, A> { /* … */ }
```
## Beispiel EventFlow (Auszug)
```kotlin
sealed interface EventStep: StepId {
data object ZnsCheck: EventStep
data object VeranstalterSelection: EventStep
data object AnsprechpersonMapping: EventStep
data object MetaData: EventStep
data object TurnierAnlage: EventStep
data object Summary: EventStep
}
data class EventAcc(
val veranstalterId: Uuid? = null,
val veranstalterNr: String = "",
val veranstalterName: String = "",
val ansprechpersonSatznr: String = "",
val name: String = "",
val ort: String = "",
val start: LocalDate? = null,
val end: LocalDate? = null,
val turniere: List<TurnierEntry> = emptyList()
)
object EventGuards {
val hasZns: Guard<EventStep, EventAcc> = { ctx, _ -> (ctx.stats?.vereinCount ?: 0) > 0 }
val needsContactPerson: Guard<EventStep, EventAcc> = { _, acc -> acc.veranstalterId == null || acc.veranstalterNr.startsWith("ORG-") }
}
val EventFlow = flow<EventStep, EventAcc>(start = EventStep.ZnsCheck) {
step(EventStep.ZnsCheck) {
onEnter { ctx, _ -> /* prefetch stats */ }
whenGuard("hasZns", EventGuards.hasZns, go = EventStep.VeranstalterSelection)
otherwise(go = EventStep.VeranstalterSelection)
}
step(EventStep.VeranstalterSelection) {
whenGuard("needsContact", EventGuards.needsContactPerson, go = EventStep.AnsprechpersonMapping)
otherwise(go = EventStep.MetaData)
}
}
```
## DevTools
- Strukturierte Logs je Transition (from, to, guard-id, result, duration).
- GraphExport (DOT/PlantUML) aus der DSL für Doku & Reviews.
## Tests (Empfehlungen)
- Unit: Guards (100% BranchAbdeckung), RuntimeHistory.
- Property: ResumeDeterminismus (Draft → korrekter Step).
- Snapshot: ComposePanels mit Beispielkontexten.
## Verweise
- ADR0025 Orchestrator · ADR0026 ValidationPolicy · ADR0027 DraftDomain & DeltaSync
- Roadmap: `docs/01_Architecture/MASTER_ROADMAP.md#3-initiative-wizard-orchestrator--offline-drafts-q2q3-2026`