chore(docs): füge ADRs 0025–0027 und Wizard-DSL-Referenz hinzu, aktualisiere Roadmap und ADR-Index

Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-21 16:21:19 +02:00
parent 0ab1807235
commit ec124e9acd
7 changed files with 281 additions and 1 deletions
@@ -0,0 +1,107 @@
---
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`