13 KiB
Create rule flow (custom wizard) — canonical reference
Product/engineering reference for the custom “Create rule” experience: URL order, persistence, and entry points. Canon wizard alignment (docs, [screenId] routing, footer progress) shipped under CR-89 (Done). Draft resume vs profile, server hydration, and “new rule” vs continue draft are tracked with CR-86 (profile dashboard). See also docs/guides/backend-linear-tickets.md Ticket 17.
Product stages (Figma)
The Figma Create Community sequence is the source of truth for the first segment of the wizard (eight frames). After review, the flow continues with Create Custom CommunityRule and Review and complete stages. The shipped URL sequence in FLOW_STEP_ORDER follows that trajectory; stages are a product slice of that linear order, not separate routers today.
| Stage (Figma) | Purpose (summary) | CreateFlowStep values (in order) |
|---|---|---|
| Create Community | Intro, naming, structure, context, size, upload, save progress (email), then community review. | informational → community-name → community-structure → community-context → community-size → community-upload → community-save → review |
| Create Custom CommunityRule | Author the CommunityRule content and structure (core values + four card-stack categories). | core-values → communication-methods → membership-methods → decision-approaches → conflict-management |
| Review and complete | Stakeholders, final card, publish, success. | confirm-stakeholders → final-review → completed |
Treat these stages as the canonical product sections when adding chrome (e.g. stage headers, progress copy), breaking work across teams, or reusing flows in other surfaces. Layout kind is not encoded in the URL; it lives in CREATE_FLOW_SCREEN_REGISTRY (Figma node id + layoutKind per step). Figma defines eight layout kinds: informational, text, select, upload, review, card, right-rail, completed — CreateFlowLayoutKind and app/(app)/create/screens/ mirror that list (one folder per kind; multiple steps may share a kind, e.g. several select screens).
Create from template (future): A full template-driven create path is not finalized; it will likely live on additional route(s) (and may reuse these stages where it overlaps the custom trajectory). Today, /create/review-template/[slug] is only an auxiliary preview in the create shell; it is not a Figma stage and not the final template-create entry. See Out of scope in CR-89.
Step order and URLs
Order is defined in code by FLOW_STEP_ORDER and the CreateFlowStep type. Wizard steps use a single dynamic route: app/(app)/create/[screenId]/page.tsx, which validates screenId and renders CreateFlowScreenView. Implementation files are grouped under app/(app)/create/screens/ by Figma layout kind (subfolders: informational, text, select, upload, review, card, right-rail, completed). /create redirects to the first step.
| Order | Figma stage | Step ID (screenId) |
Path |
|---|---|---|---|
| 1 | Create Community | informational |
/create/informational |
| 2 | Create Community | community-name |
/create/community-name |
| 3 | Create Community | community-structure |
/create/community-structure |
| 4 | Create Community | community-context |
/create/community-context |
| 5 | Create Community | community-size |
/create/community-size |
| 6 | Create Community | community-upload |
/create/community-upload |
| 7 | Create Community | community-save |
/create/community-save |
| 8 | Create Community (review frame) | review |
/create/review |
| 9 | Create Custom CommunityRule | core-values |
/create/core-values |
| 10 | Create Custom CommunityRule | communication-methods |
/create/communication-methods |
| 11 | Create Custom CommunityRule | membership-methods |
/create/membership-methods |
| 12 | Create Custom CommunityRule | decision-approaches |
/create/decision-approaches |
| 13 | Create Custom CommunityRule | conflict-management |
/create/conflict-management |
| 14 | Review and complete | confirm-stakeholders |
/create/confirm-stakeholders |
| 15 | Review and complete | final-review |
/create/final-review |
| 16 | Review and complete | completed |
/create/completed |
Primary entry: marketing header “Create rule” navigates to /create, which redirects to /create/informational (see Top.container.tsx).
Active step for chrome and navigation is resolved from the pathname via parseCreateFlowScreenFromPathname inside useCreateFlowNavigation.
Auxiliary route (not a wizard step or Figma stage)
| Path | Purpose |
|---|---|
/create/review-template/[slug] |
Template preview in the create shell; uses the same layout/footer chrome as other create pages but is not part of FLOW_STEP_ORDER or the three Figma stages above. |
From that page, Customize pre-fills the custom-rule selections on the current CreateFlowState (via buildTemplateCustomizePrefill) and routes to /create/core-values when the community name (state.title) is already set, otherwise to /create/informational. Name-only is the gate because other community-stage fields (e.g. communityStructureChipSnapshots) are sticky once the user lands on those screens; a non-empty title is also the minimum bar buildPublishPayload enforces, so the two checks stay aligned. No query-param plumbing: state persists via the usual anonymous/server-draft mirrors.
Use without changes writes the template's body.sections into state.sections (and its description into state.summary when present), resets any prior Customize chip selections so they don't bleed into document.coreValues, and routes to /create/confirm-stakeholders. The user then exits via the normal final-review → handleFinalize → publishRule pipeline, which gates unauthenticated publishes with a 401 → openLogin redirect back to /create/final-review?syncDraft=1.
Entering a template before community stage is done. When state.title is empty, both handlers apply their side effects eagerly (prefill for Customize; sections + summary for Use without changes) and pin a pendingTemplateAction: { slug, mode } on CreateFlowState before routing to /create/informational. Once the user reaches /create/review, CommunityReviewScreen reads the action on mount, clears it via updateState, and router.replaces past itself — to /create/core-values for customize, /create/confirm-stakeholders for useWithoutChanges. The user never sees the community-review page in that flow because their intent was already expressed at the template-review step. replace (not push) keeps community-save as the Back-button target from the destination. The action is cleared on the first fire so later direct visits to /create/review render normally.
Direct entry vs in-flow template pick. The same /create/review-template/[slug] URL is reached from two different origins. We disambiguate at the click site, not on the review-template page, using clearCreateFlowPersistedDrafts — a tiny helper that wipes the anonymous draft from localStorage (both create-flow-anonymous and the core-value-details key) before the navigation fires. Because CreateFlowProvider reads localStorage in its useState initializer, the provider mounts empty and handleCustomizeTemplate / handleUseTemplateWithoutChanges naturally take the no-community branch — no per-handler marker plumbing needed.
| Origin | Click-site behavior | URL the user lands on |
|---|---|---|
Home marketing "Popular templates" (RuleStack.container.tsx) |
always calls clearCreateFlowPersistedDrafts() |
/create/review-template/[slug] |
/templates index (TemplatesPageClient.tsx) visited directly / via pasted URL |
fromFlow absent → calls clearCreateFlowPersistedDrafts() |
/create/review-template/[slug] |
In-flow: /create/review footer "Create from template" → /templates?fromFlow=1 → template click |
fromFlow=1 → skips the clear |
/create/review-template/[slug] |
Only one ?fromFlow=1 marker exists, on one hop (/create/review → /templates). It is not forwarded onto the review-template URL. The review-template handlers branch solely on state.title — they don't need to know the origin.
Server drafts (/api/drafts/me) are not touched here. Per product plan they are not auto-hydrated into the create flow; users select and load a specific saved draft from the profile page. So wiping localStorage is sufficient for the "fresh slate" invariant.
Final-review Rule category chips are derived from CreateFlowState via buildFinalReviewCategoriesFromState: for the Customize / plain custom-rule path it resolves selected{Communication,Membership,DecisionApproach,ConflictManagement}MethodIds against the curated method presets in messages/en/create/customRule/*.json, and buildCoreValuesForDocument supplies the Values row from coreValuesChipsSnapshot + selectedCoreValueIds. For the Use-without-changes path the template body lives in state.sections; the helper renders categoryName + entry titles directly. The demo chips shipped in finalReview.json remain the fallback only when nothing in state resolves to any chip (e.g. direct navigation for development).
Starting the wizard from a template at final-review directly is out of scope until a dedicated product ticket ships. A full create-from-template experience will likely use separate route(s) when product and eng define it (may still align conceptually with the same three stages where behavior overlaps the custom path).
Persistence and exit
| Mode | Where progress lives | Save & Exit / server draft |
|---|---|---|
| Anonymous | localStorage key create-flow-anonymous |
Exit opens save-progress magic link; after verify, optional PUT /api/drafts/me when NEXT_PUBLIC_ENABLE_BACKEND_SYNC=true (see Tickets 4–5 in guides/backend-linear-tickets.md). |
| Signed-in | In-memory React state in CreateFlowContext |
Save & Exit from the community-structure step onward (step index ≥ community-structure) may PUT /api/drafts/me when sync is on. Sign out is on profile, not in the create top nav. |
Details and edge cases (conflict confirm, banners, ?syncDraft=1) match Ticket 4, Ticket 5, and docs/guides/backend-roadmap.md §12.
Known implementation gaps
- Profile + drafts (CR-86): The profile page lists the server draft, Continue deep-links to
/create/{currentStep}, and Start new rule clears local + server draft before opening the wizard.SignedInDraftHydrationcallsrouter.replaceto the saved step when it applies a server draft so the URL matches hydrated state. Remaining edge cases (e.g. template review routes) are handled when they surface in QA. - Inner “text/select shells”: deferred until Create Community is stable; screens use
CreateFlowStepShellonly for Stage 1.
Related docs
- docs/guides/backend-roadmap.md §12 — Frontend hook-up
- docs/guides/backend-linear-tickets.md — Tickets 4, 5, 6, 17; profile/drafts — Ticket 15 / CR-86