108 lines
3.4 KiB
Markdown
108 lines
3.4 KiB
Markdown
---
|
||
type: Reference
|
||
status: ACTIVE
|
||
owner: Lead Architect
|
||
date: 2026-04-21
|
||
---
|
||
|
||
# Wizard‑DSL & Orchestrator – Referenz
|
||
|
||
## Ziel
|
||
Deklarative Beschreibung von Wizard‑Flows als Graph (Steps, Guards, Transitions) mit klaren Side‑Effects und Offline‑Draft‑Unterstützung.
|
||
|
||
## Kern‑Interfaces (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 – Event‑Flow (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).
|
||
- Graph‑Export (DOT/PlantUML) aus der DSL für Doku & Reviews.
|
||
|
||
## Tests (Empfehlungen)
|
||
- Unit: Guards (100% Branch‑Abdeckung), Runtime‑History.
|
||
- Property: Resume‑Determinismus (Draft → korrekter Step).
|
||
- Snapshot: Compose‑Panels mit Beispielkontexten.
|
||
|
||
## Verweise
|
||
- ADR‑0025 Orchestrator · ADR‑0026 Validation‑Policy · ADR‑0027 Draft‑Domain & Delta‑Sync
|
||
- Roadmap: `docs/01_Architecture/MASTER_ROADMAP.md#3-initiative-wizard-orchestrator--offline-drafts-q2q3-2026`
|