d56056d66cbbd2f3edc48f3d4ce3161c782fdb01
Builds the reusable multi-step wizard engine the plan front-loads in Phase 6, as
two protocol-free namespaces. This replaces the EDN-snapshot-in-a-hidden-field
round-trip for genuine multi-step flows: per-step validated data lives in the Ring
session and is combined only at the end — only an opaque wizard-id rides in the form.
- components/wizard_state.clj — pure session storage (Django formtools SessionStorage
model): create-wizard!, instance, exists?, current-step, context, step-data,
put-step (REPLACE not merge), set-step, get-all (combine at end), forget. State
namespaced by wizard-id at [:wizards <id> ...]; :context holds read-only step inputs
outside :step-data so it never merges into the result. Each fn is session -> session'.
- components/wizard2.clj — the engine: open-wizard, render-wizard, handle-step-submit,
wizard-form. A wizard is a config map (steps with :decode/:validate/:render/:next,
plus :init-fn/:done-fn/:submit-route). Steps' :render get {wizard-id, current-step,
context, all-data, step-data, errors, request}; nav posts a `direction` field
(next/back/submit). Two routes per wizard (open + submit); the engine threads the
session into the response itself — no wrap-wizard / wrap-decode-multi-form-state stack.
REPL-proven lifecycle (before wiring any modal):
1. OPEN -> seeds session state, renders step 1, form leaks NO accumulated data
2. NEXT -> stores {:info {:name "Acme"}}, advances to :terms
3. INVALID -> re-renders the same step with errors, no advance
4. DONE -> done-fn gets combined {:name "Acme" :days 30} (get-all), instance forgotten
5. BACK -> :terms -> :info, no validation
6. EXPIRED -> unknown wizard-id re-opens fresh instead of 500-ing
Inert infrastructure — nothing imports it yet (Transaction Rule migrates onto it next),
so the e2e suite is unaffected. cljfmt clean. Skill: form-vs-wizard.md updated from
aspirational to the realized engine API + the Phase-6 fit note (Transaction Rule
exercises render/nav/preview; the cross-step merge gets its workout in Phase 7+).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Description
No description provided
Languages
Clojure
90.9%
CSS
4.2%
Sass
2.3%
HTML
1.3%
HCL
0.4%
Other
0.7%