> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Wizard Development Guide

> Version: 1.1 Created: 2026-01-28 Last Updated: 2026-04-14

**Version:** 1.1\
**Created:** 2026-01-28\
**Last Updated:** 2026-04-14

> **Related Documents:**
>
> * `specs/_templates/WIZARD_SPEC_TEMPLATE.md` - Specification template
> * `specs/pf/specs/PF-41-configurable-module-wizards.md` - PF-41 infrastructure spec
> * `src/platform/wizards/README.md` - Platform wizard implementation
> * `docs/development/WIZARD_WORKFLOW_RECOMMENDATIONS.md` - Workflow recommendations

***

## Quick Start

### 1. Create Wizard Specification

```bash theme={null}
# Use the wizard template
create-spec --core hr --name leave-request-wizard --type wizard

# Or let auto-detection prompt you
create-spec --core hr --name leave-request-wizard
# → "Name contains 'wizard'. Use WIZARD_SPEC_TEMPLATE.md? (Y/n)"
```

**Output:** `specs/hr/ux/HR-UX-##-leave-request-wizard.md`

### 2. Validate Specification

```bash theme={null}
validate-spec --file specs/hr/ux/HR-UX-04-leave-request-wizard.md --type wizard
```

### 3. Generate Implementation Tasks

```bash theme={null}
generate-tasks HR-UX-04
```

### 4. Implement and Test

Follow the implementation plan in the spec, using PF-41 infrastructure.

***

## Wizard Development Lifecycle

```text theme={null}
┌─────────────────────────────────────────────────────────────────┐
│                  WIZARD DEVELOPMENT LIFECYCLE                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. SPECIFICATION         2. PLANNING          3. IMPLEMENTATION │
│  ┌──────────────┐        ┌──────────────┐     ┌──────────────┐  │
│  │ Create spec  │───────▶│ Choose PF-41 │────▶│ Build steps  │  │
│  │ using wizard │        │ approach     │     │ & components │  │
│  │ template     │        │              │     │              │  │
│  └──────────────┘        └──────────────┘     └──────────────┘  │
│         │                       │                    │           │
│         ▼                       ▼                    ▼           │
│  ┌──────────────┐        ┌──────────────┐     ┌──────────────┐  │
│  │ Define steps │        │ Design data  │     │ Register     │  │
│  │ & validation │        │ model        │     │ with PF-41   │  │
│  └──────────────┘        └──────────────┘     └──────────────┘  │
│                                                      │           │
│                                                      ▼           │
│  4. TESTING               5. DEPLOYMENT        6. ANALYTICS     │
│  ┌──────────────┐        ┌──────────────┐     ┌──────────────┐  │
│  │ Unit tests   │───────▶│ Feature flag │────▶│ Track usage  │  │
│  │ E2E tests    │        │ System templ │     │ & completion │  │
│  │ RLS tests    │        │              │     │              │  │
│  └──────────────┘        └──────────────┘     └──────────────┘  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

***

## Phase 1: Specification

### Using WIZARD\_SPEC\_TEMPLATE.md

The wizard specification template includes these key sections:

| Section                       | Purpose                   | Required    |
| ----------------------------- | ------------------------- | ----------- |
| Executive Summary             | Quick overview of wizard  | ✅           |
| Business Context              | Why this wizard is needed | ✅           |
| Objectives & Success Criteria | Measurable goals          | ✅           |
| Scope                         | What's in/out of scope    | ✅           |
| User Stories                  | User-facing requirements  | ✅           |
| **PF-41 Wizard Architecture** | Integration approach      | ✅           |
| **Wizard Step Definitions**   | Detailed step specs       | ✅           |
| **Navigation & Flow**         | Flow diagram and rules    | ✅           |
| Data Model                    | Wizard data types         | ✅           |
| Integration Points            | API/hook integrations     | ✅           |
| UI/UX Requirements            | Design requirements       | ✅           |
| Testing Strategy              | Test scenarios            | ✅           |
| Analytics Events              | Tracking events           | Recommended |
| Implementation Plan           | Phased tasks              | ✅           |

### Step Definition Requirements

Each wizard step must document:

```markdown theme={null}
### Step N: [Step Name]

**Purpose:** [What this step accomplishes]

**Step Type:** `form` / `custom` / `review`

**Component ID (if custom):** `{core}.{feature}.{step}`

**Fields/Components:**
| Field | Type | Required | Validation |
|-------|------|----------|------------|
| field1 | text | Yes | min 2 chars |
| field2 | select | No | - |

**Help Content:**
- **Title:** [Help title]
- **Content:** [Help text]

**Tooltip Definitions:**
| Term | Tooltip Key | Content |
|------|-------------|---------|
| term1 | `wizard_term_definition` | [Text] |

**Navigation:**
- **Can Skip:** Yes/No - [Reason]
- **Can Go Back:** Yes/No
- **Next Step:** [Next step name]

**Mobile Considerations:**
- [ ] Touch targets ≥44x44px
- [ ] Form fields stack vertically on mobile
- [ ] Native pickers for date/time on mobile
- [ ] Validation errors visible without scrolling
```

***

## Step Icons

Every wizard step SHOULD have an icon to improve visual scanning and user orientation. Icons appear inside the step circle indicator in all three layout variants (horizontal, timeline, sidebar).

### Two Layers of Icon Support

| Layer                                       | Type                                       | Where stored                      | Rendering                                   |
| ------------------------------------------- | ------------------------------------------ | --------------------------------- | ------------------------------------------- |
| **Presentational** (`WizardShellStep.icon`) | React component (`ComponentType`)          | In-memory step array              | Rendered directly by `WizardShell`          |
| **Template JSON** (`WizardStep.icon`)       | `string` key (e.g. `'user'`, `'calendar'`) | `pf_wizard_templates.steps` JSONB | Resolved via `resolveStepIcon()` at runtime |

### Using Icons with `WizardShell` (Presentational)

Pass Lucide icon components directly in the `steps` array:

```typescript theme={null}
import { WizardShell } from '@/platform/wizards';
import { User, Calendar, ClipboardCheck } from 'lucide-react';

const steps = [
  { id: 'info', title: 'Personal Info', icon: User },
  { id: 'dates', title: 'Schedule', icon: Calendar },
  { id: 'review', title: 'Review', icon: ClipboardCheck },
];

<WizardShell steps={steps} layout="timeline" /* ... */ />
```

### Using Icons in PF-41 Templates (JSON Config)

For configurable wizard templates stored in the database, use string icon keys from the `WIZARD_STEP_ICONS` catalog:

```typescript theme={null}
// Template step definition (JSON)
{
  "id": "step-1",
  "title": "Employee Info",
  "icon": "user",
  "component_type": "form",
  // ...
}
```

Resolve string keys to components using `resolveStepIcon()`:

```typescript theme={null}
import { resolveStepIcon } from '@/platform/wizards';

const steps = template.steps.map((step) => ({
  id: step.id,
  title: step.title,
  icon: resolveStepIcon(step.icon),
}));
```

### Available Icon Keys

The `WIZARD_STEP_ICONS` catalog in `@/platform/wizards` provides \~50 curated icons organized by category:

| Category         | Keys                                                           |
| ---------------- | -------------------------------------------------------------- |
| People           | `user`, `user-plus`, `users`, `badge-check`                    |
| Contact          | `mail`, `phone`, `map-pin`, `home`                             |
| Dates            | `calendar`, `clock`                                            |
| Documents        | `file-text`, `file-check`, `clipboard`, `upload`, `image-plus` |
| Finance          | `wallet`, `banknote`, `credit-card`, `circle-dollar-sign`      |
| Work             | `briefcase`, `building`, `laptop`, `package`                   |
| Health           | `stethoscope`, `heart`                                         |
| Security         | `shield`, `shield-check`, `lock`                               |
| Settings         | `settings`, `target`, `sparkles`                               |
| Wizard lifecycle | `review`, `complete`, `confirm`, `summary`, `info`             |

**Adding new icons:** Add to `src/platform/wizards/utils/stepIcons.ts`, update this table, and follow the [Icon Guide](ICON_GUIDE.md).

**Healthcare examples:** [`examples/wizard-templates/healthcare-icon-keys.json`](./examples/wizard-templates/healthcare-icon-keys.json) — copy-paste PF-41 snippets for `stethoscope`, `pill`, `syringe`.

**Unknown icon keys (fallback behavior):** If a template references an icon key that isn't in `WIZARD_STEP_ICONS` and doesn't match a module code, `resolveStepIcon()` returns the `FALLBACK_STEP_ICON` (`CircleHelp` from Lucide) so the step indicator stays visible instead of silently collapsing to the step number. In development, a one-time `console.warn` per unknown key surfaces the typo to the author; the warning is stripped from production builds. Authors should still pick a real key from the catalog — the fallback is a safety net, not a sanctioned wildcard. An empty/missing `icon` field is treated as the intentional "show the step number" mode and does **not** trigger the fallback.

### Icon Selection Rules

1. **Semantic relevance:** Choose icons that represent the step's purpose, not its position.
2. **Consistency:** Use the same icon for the same concept across wizards (e.g. `user` for personal info, `calendar` for scheduling).
3. **Review/completion steps:** Use `review` or `complete` — these are recognizable patterns.
4. **No icon is acceptable:** Steps without an icon fall back to step number display.
5. **Accessibility:** Step icons are decorative (step circle has `aria-label` with step title); no additional `aria-label` needed on icons.

### Icon Display Behavior

| State                     | What renders                                          |
| ------------------------- | ----------------------------------------------------- |
| Completed step            | Checkmark (`Check` icon) — always overrides step icon |
| Current step with icon    | Step icon in primary border circle                    |
| Current step without icon | Step number in primary border circle                  |
| Future step with icon     | Step icon in muted border circle                      |
| Future step without icon  | Step number in muted border circle                    |

***

## Phase 2: PF-41 Integration Decision

### Decision Tree

```text theme={null}
Is this wizard...
│
├─ A standardized process that organizations should customize?
│   └─ YES → Use System Template approach
│
├─ Highly integrated with module-specific logic?
│   └─ YES → Use Module-Specific approach
│
└─ Both complex logic AND needs customization?
    └─ YES → Use Hybrid approach
```

### Approach Comparison

| Aspect             | System Template   | Module-Specific   | Hybrid     |
| ------------------ | ----------------- | ----------------- | ---------- |
| **Customizable**   | ✅ Yes             | ❌ No              | ✅ Partial  |
| **Marketplace**    | ✅ Yes             | ❌ No              | ⚠️ Limited |
| **Implementation** | PF-41 templates   | Custom components | Mixed      |
| **Maintenance**    | Lower             | Higher            | Medium     |
| **Best For**       | Onboarding, setup | Complex workflows | Enterprise |

### Implementation Patterns

#### System Template (Recommended)

```typescript theme={null}
// src/cores/{core}/pages/{Wizard}Page.tsx
import { ModuleWizardRenderer } from '@/platform/wizards';
import { useActiveWizard } from '@/platform/wizards';

export function LeaveRequestWizardPage() {
  const { data: template } = useActiveWizard({
    module: 'hr',
    wizardType: 'leave_request',
  });

  return (
    <ModuleWizardRenderer
      template={template}
      onComplete={handleComplete}
      onCancel={handleCancel}
    />
  );
}
```

#### Module-Specific

```typescript theme={null}
// src/cores/{core}/wizards/{wizard}/WizardPage.tsx
import { WizardRenderer } from '@/platform/forms/components/wizard';
import { Step1, Step2, ReviewStep } from './steps';

export function LeaveRequestWizard() {
  const [step, setStep] = useState(1);
  const [data, setData] = useState({});

  const steps = [
    { component: Step1, title: 'Leave Type' },
    { component: Step2, title: 'Dates' },
    { component: ReviewStep, title: 'Review' },
  ];

  return (
    <WizardRenderer
      steps={steps}
      currentStep={step}
      data={data}
      onStepChange={setStep}
      onDataChange={setData}
    />
  );
}
```

#### Hybrid

```typescript theme={null}
// Combine PF-41 form steps with custom components
import { ModuleWizardRenderer, registerWizardStep } from '@/platform/wizards';
import { CustomValidationStep } from './steps/CustomValidationStep';

// Register custom step
registerWizardStep({
  id: 'hr.leave.validation',
  module: 'hr',
  name: 'Custom Validation',
  component: CustomValidationStep,
});

// Template uses both form steps and custom step
```

***

## Phase 3: Implementation

### File Structure

```
src/cores/{core}/
├── wizards/
│   ├── register{Core}WizardSteps.ts    # Step registration (PF-41)
│   └── {wizard-name}/
│       ├── {WizardName}Page.tsx        # Wizard page component
│       ├── steps/
│       │   ├── Step1Component.tsx      # Custom step components
│       │   ├── Step2Component.tsx
│       │   └── ReviewStep.tsx
│       ├── hooks/
│       │   ├── useWizardData.ts        # Data fetching
│       │   └── useWizardValidation.ts  # Validation logic
│       └── types.ts                    # TypeScript types
```

### Custom Step Component Pattern

```typescript theme={null}
// src/cores/hr/wizards/leave-request/steps/LeaveTypeStep.tsx
import { WizardStepProps } from '@/platform/wizards';
import { FormField, FormItem, FormLabel } from '@/shared/ui/form';
import { useLeaveTypes } from '@/cores/hr/hooks/useLeaveTypes';

interface LeaveTypeStepProps extends WizardStepProps {
  // Step-specific props
}

export function LeaveTypeStep({ 
  data, 
  onDataChange, 
  onValidate 
}: LeaveTypeStepProps) {
  const { data: leaveTypes, isLoading } = useLeaveTypes();

  const handleTypeSelect = (typeId: string) => {
    onDataChange({ ...data, leaveTypeId: typeId });
  };

  return (
    <div className="space-y-4">
      <FormField
        name="leaveType"
        render={({ field }) => (
          <FormItem>
            <FormLabel>Select Leave Type</FormLabel>
            {/* ... form control */}
          </FormItem>
        )}
      />
    </div>
  );
}

// Validation function
LeaveTypeStep.validate = (data: WizardFormData) => {
  const errors: ValidationErrors = {};
  if (!data.leaveTypeId) {
    errors.leaveTypeId = 'Please select a leave type';
  }
  return errors;
};
```

### Step Registration (PF-41)

```typescript theme={null}
// src/cores/hr/wizards/registerHRWizardSteps.ts
import { registerWizardStep } from '@/platform/wizards';
import { lazy } from 'react';

export function registerHRWizardSteps() {
  // Leave Request Wizard Steps
  registerWizardStep({
    id: 'hr.leave.type-selection',
    module: 'hr',
    name: 'Leave Type Selection',
    description: 'Select leave type and view balance',
    component: lazy(() => import('./leave-request/steps/LeaveTypeStep')),
  });

  registerWizardStep({
    id: 'hr.leave.date-selection',
    module: 'hr',
    name: 'Date Selection',
    description: 'Select start and end dates',
    component: lazy(() => import('./leave-request/steps/DateSelectionStep')),
  });

  // ... additional steps
}
```

### Draft Persistence

```typescript theme={null}
import { useWizardDraft } from '@/platform/wizards';

function MyWizard() {
  const { 
    draft, 
    saveDraft, 
    loadDraft, 
    clearDraft 
  } = useWizardDraft({
    wizardType: 'leave_request',
    userId: user.id,
  });

  // Auto-save on step change
  const handleStepComplete = (stepData: StepData) => {
    saveDraft({
      currentStep: step,
      data: { ...data, ...stepData },
    });
  };

  return (/* ... */);
}
```

***

## Phase 4: Testing

### Required Tests

| Test Type   | Location                             | Coverage Target     |
| ----------- | ------------------------------------ | ------------------- |
| Unit        | `tests/unit/{core}/{wizard}/`        | 80%                 |
| Integration | `tests/integration/{core}/{wizard}/` | Key flows           |
| E2E         | `tests/e2e/{core}/{wizard}/`         | Happy path + errors |
| RLS         | `tests/rls/{core}-{wizard}/`         | If new tables       |

### Unit Test Example

```typescript theme={null}
// tests/unit/hr/leave-request-wizard/LeaveTypeStep.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import { LeaveTypeStep } from '@/cores/hr/wizards/leave-request/steps/LeaveTypeStep';

describe('LeaveTypeStep', () => {
  it('validates leave type selection', () => {
    const errors = LeaveTypeStep.validate({});
    expect(errors.leaveTypeId).toBe('Please select a leave type');
  });

  it('passes validation with leave type selected', () => {
    const errors = LeaveTypeStep.validate({ leaveTypeId: 'vacation' });
    expect(errors).toEqual({});
  });

  it('shows available leave balances', async () => {
    render(<LeaveTypeStep data={{}} onDataChange={jest.fn()} />);
    expect(await screen.findByText('Vacation')).toBeInTheDocument();
    expect(await screen.findByText('16 hours available')).toBeInTheDocument();
  });
});
```

### E2E Test Example

```typescript theme={null}
// tests/e2e/hr/leave-request-wizard.spec.ts
import { test, expect } from '@playwright/test';

test.describe('Leave Request Wizard', () => {
  test('completes full wizard flow', async ({ page }) => {
    await page.goto('/hr/leave/request');

    // Step 1: Select leave type
    await page.click('[data-testid="leave-type-vacation"]');
    await page.click('[data-testid="next-button"]');

    // Step 2: Select dates
    await page.fill('[data-testid="start-date"]', '2026-02-15');
    await page.fill('[data-testid="end-date"]', '2026-02-20');
    await page.click('[data-testid="next-button"]');

    // Step 3: Add details
    await page.fill('[data-testid="notes"]', 'Family vacation');
    await page.click('[data-testid="next-button"]');

    // Step 4: Review and submit
    await expect(page.locator('[data-testid="summary-leave-type"]'))
      .toHaveText('Vacation');
    await page.click('[data-testid="submit-button"]');

    // Verify success
    await expect(page.locator('[data-testid="success-message"]'))
      .toBeVisible();
  });

  test('saves and resumes draft', async ({ page }) => {
    await page.goto('/hr/leave/request');

    // Complete step 1
    await page.click('[data-testid="leave-type-vacation"]');
    await page.click('[data-testid="next-button"]');

    // Navigate away
    await page.goto('/hr/dashboard');

    // Return to wizard
    await page.goto('/hr/leave/request');

    // Should resume at step 2
    await expect(page.locator('[data-testid="step-indicator"]'))
      .toHaveText('Step 2 of 4');
  });
});
```

***

## Phase 5: Analytics Integration

### Standard Events

All wizards should track these events:

```typescript theme={null}
import { trackWizardEvent } from '@/platform/wizards';

// Wizard started
trackWizardEvent('leave_request_wizard_started', {
  wizard_id: templateId,
  user_id: userId,
  device_type: isMobile ? 'mobile' : 'desktop',
  entry_point: 'dashboard_quick_action',
});

// Step completed
trackWizardEvent('leave_request_wizard_step_completed', {
  step_id: 'date-selection',
  step_name: 'Date Selection',
  time_spent_ms: 45000,
  fields_completed: 3,
});

// Wizard completed
trackWizardEvent('leave_request_wizard_completed', {
  total_time_ms: 120000,
  steps_completed: 4,
  steps_skipped: 0,
  entity_id: leaveRequestId,
});
```

### PF-41 Built-in Analytics

When using PF-41 `ModuleWizardRenderer`, analytics are tracked automatically:

```typescript theme={null}
<ModuleWizardRenderer
  template={template}
  trackAnalytics={true}  // Default: true
  onComplete={handleComplete}
/>
```

***

## Phase 6: Deployment

### Feature Flags

Use feature flags for gradual rollout:

```typescript theme={null}
import { useWizardFeatureFlags } from '@/platform/wizards';

function LeaveRequestPage() {
  const { useConfigurableWizard } = useWizardFeatureFlags('hr');

  if (useConfigurableWizard) {
    return <ConfigurableLeaveWizard />;
  }
  return <LegacyLeaveForm />;
}
```

### System Template Deployment

For PF-41 system templates, create a migration:

```sql theme={null}
-- supabase/migrations/YYYYMMDDHHMMSS_add_leave_request_wizard_template.sql
INSERT INTO pf_wizard_templates (
  module,
  wizard_type,
  name,
  description,
  wizard_config,
  steps,
  is_template,
  is_active
) VALUES (
  'hr',
  'leave_request',
  'Leave Request Wizard',
  'Guided workflow for requesting time off',
  '{"progress_style": "stepper", "validation_mode": "on_advance"}',
  '[{"id": "step-1", "title": "Leave Type", "component_type": "custom", "component_id": "hr.leave.type-selection"}, ...]'::jsonb,
  true,  -- System template
  true   -- Active
);
```

***

## Common Pitfalls

### 1. Missing PF-41 Integration Documentation

**Problem:** Spec doesn't document PF-41 approach.

**Solution:** Always include the "PF-41 Wizard Architecture" section, even for module-specific wizards:

```markdown theme={null}
## PF-41 Wizard Architecture

**Approach:** Module-Specific

**Rationale:** This wizard requires complex validation logic that integrates 
deeply with HR leave policy rules. A future enhancement will migrate to 
PF-41 hybrid approach for organization customization.
```

### 2. Incomplete Step Definitions

**Problem:** Steps missing validation rules, help content, or mobile considerations.

**Solution:** Use the complete step template and run `validate-spec --file <path> --type wizard` to catch gaps.

### 3. No Draft Persistence

**Problem:** Users lose progress when navigating away.

**Solution:** Always implement draft persistence using `useWizardDraft` or PF-41's built-in draft management.

### 4. Missing Analytics

**Problem:** No tracking of wizard usage and drop-off points.

**Solution:** Include the Analytics Events section in spec and implement tracking.

### 5. Poor Mobile Experience

**Problem:** Wizard unusable on mobile devices.

**Solution:**

* Use the mobile checklist per step
* Test on actual mobile devices
* Include mobile E2E tests

***

## Commands Reference

| Command                           | Purpose                                                                             |
| --------------------------------- | ----------------------------------------------------------------------------------- |
| `create-wizard-spec`              | Interactive wizard UX spec creation (step prompts, icon selection, PF-41 decisions) |
| `create-spec --type wizard`       | Quick wizard spec creation from template                                            |
| `validate-spec --type wizard`     | Validate wizard spec (icons, naming, validation pattern, PF-41, sections)           |
| `audit-wizard-specs`              | Audit all wizard specs across cores with scoring (icons, naming, compliance)        |
| `recommend-wizards`               | Analyze module specs for wizard candidates with scoring                             |
| `generate-wizard-lovable-prompts` | Generate Lovable browser walkthrough prompts from wizard specs                      |
| `generate-tasks`                  | Generate implementation tasks from spec                                             |
| `verify-task`                     | Verify task completion                                                              |

**Full workflow:**

```text theme={null}
recommend-wizards --core {core}
       ↓
create-wizard-spec --core {core} --name {name} --based-on {SPEC-ID}
       ↓
validate-spec --file specs/{core}/ux/{CORE}-UX-##-{name}.md --type wizard
       ↓
generate-tasks {CORE}-UX-##
       ↓
implement (using WizardShell / DialogWizardShell / ModuleWizardRenderer)
       ↓
audit-wizard-specs --core {core}
```

***

## Resources

* **Specification Template:** `specs/_templates/WIZARD_SPEC_TEMPLATE.md`
* **PF-41 Spec:** `specs/pf/specs/PF-41-configurable-module-wizards.md`
* **Platform Implementation:** `src/platform/wizards/README.md`
* **Consolidation Plan:** `specs/cross-cutting/WIZARD-CONSOLIDATION-PLAN.md`
* **Cross-Cutting Patterns:** `specs/cross-cutting/WIZARD-PATTERN.md`
* **Cross-Cutting Rules:** `specs/cross-cutting/WIZARD-RULES.md`
* **Selection Guide:** `docs/guides/use-cases/wizard-selection.md`
* **UX Standard:** `docs/development/WIZARD_UX_STANDARD.md`
* **Icon Guide:** `docs/development/ICON_GUIDE.md`
* **Workflow Recommendations:** `docs/development/WIZARD_WORKFLOW_RECOMMENDATIONS.md`
* **Analytics Guide:** `docs/pf/wizard-analytics-guide.md`
* **Branching Guide:** `docs/pf/wizard-branching-guide.md`
* **Marketplace Guide:** `docs/pf/wizard-marketplace-guide.md`

***

## Architecture Recommendations

### Wizard Infrastructure Audit Findings (2026-04-14)

The platform currently has three distinct wizard rendering paths. This section documents known gaps, recommended consolidations, and standards to enforce going forward.

#### 1. Consolidate Step Registration at Bootstrap

Wizard step registration should happen centrally in `src/bootstrap/registerModuleWizardSteps.ts` so module entry points do not race dynamic step availability.

**Current baseline (recommended pattern):** register all core step modules in `registerAllModuleWizardSteps()`:

```typescript theme={null}
// src/bootstrap/registerModuleWizardSteps.ts
const WIZARD_MODULES = [
  { id: 'fa.wizards', load: () => import('@/cores/fa/wizards/registerFAWizardSteps') },
  { id: 'ce.screening', load: () => import('@/cores/ce/wizards/screening/registerScreeningWizardSteps') },
  { id: 'ce.partner-contract', load: () => import('@/cores/ce/wizards/partner-contract/registerPartnerContractWizardSteps') },
  { id: 'ce.sequences', load: () => import('@/cores/ce/wizards/sequences/registerCeSequenceWizardSteps') },
  { id: 'gr.wizards', load: () => import('@/cores/gr/wizards/registerGRWizardSteps') },
  { id: 'gr.training-course', load: () => import('@/cores/gr/wizards/training-course/registerTrainingCourseWizardSteps') },
  { id: 'hr.wizards', load: () => import('@/cores/hr/components/wizards/registerHRWizardSteps') },
  { id: 'hr.payroll-wizards', load: () => import('@/cores/hr/wizards/registerHRPayrollWizardSteps') },
  { id: 'rh.wizards', load: () => import('@/cores/rh/components/wizards/registerRHWizardSteps') },
] as const;

export function registerAllModuleWizardSteps(): void {
  for (const moduleSpec of WIZARD_MODULES) {
    // Load each module independently so one failure cannot block app boot.
    void moduleSpec.load();
  }
}
```

#### 2. Deprecate Custom Stepper UIs

Custom stepper usage should be triaged as either (a) migration target or (b) documented exception:

| Custom stepper              | Location                                                     | Recommendation                                                                               |
| --------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
| `PayrollWizardStepper`      | `src/cores/hr/components/payroll/`                           | Deprecated / removed (migrated to PF-41 renderer flows)                                      |
| `KioskProgressStepper`      | `src/cores/pm/components/kiosk/`                             | Migrated to `WizardShell` horizontal header                                                  |
| `MigrationStepper`          | `src/platform/settings/pages/data-migration/`                | **Exception:** tab/segmented navigation, not a sequential wizard                             |
| `StepIndicator` (inline)    | `src/cores/pm/components/PreadmissionFormRenderer.tsx`       | **Exception:** schema-driven section renderer, not PF-41 wizard navigation                   |
| `ApprovalChainStepper`      | `src/cores/fw/components/approvals/ApprovalChainStepper.tsx` | **Exception:** approval-state tracker (read-only process visualization), not step navigation |
| `PDSACycleDetail` phase row | `src/cores/gr/components/PDSACycleDetail.tsx`                | **Exception:** business process phase viewer (Plan/Do/Study/Act), not a wizard               |
| `StepIndicator` (inline)    | `src/platform/organizations/OnboardingDialog.tsx`            | Migrated to `DialogWizardShell`                                                              |

New wizard builds MUST NOT create custom steppers. Allowed exceptions are limited to non-wizard patterns (parallel tabs, schema-section progress) and should be explicitly documented in spec/guide artifacts.

#### 3. Icon String Resolution for Template Wizards

The `WizardStep.icon` field (JSON config) accepts a string, while `WizardShellStep.icon` (presentational) accepts a React component. The `resolveStepIcon()` utility bridges this gap. `ModuleWizardRenderer` and any code converting template steps to shell steps SHOULD use `resolveStepIcon()` to map string keys to components.

#### 4. Standardize Wizard Validation Patterns

Three validation patterns exist across wizard implementations:

| Pattern                                  | Used by                                          | Recommendation                                                                  |
| ---------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------- |
| PF-41 `validation.rules` on `WizardStep` | Template-driven `ModuleWizardRenderer` flows     | Preferred for form steps                                                        |
| `StepComponentProps`-driven validation   | Custom `registerWizardStep` components           | Preferred for new custom steps (`static .validate()` is legacy-compatible only) |
| Inline `react-hook-form` validation      | Ad-hoc `WizardShell` / `DialogWizardShell` flows | Acceptable for shell-only implementations                                       |

Avoid mixing patterns within the same wizard. Template-driven wizards should use PF-41 validation exclusively.

#### 5. Wizard Selection Decision Tree

```text theme={null}
Need a multi-step flow?
│
├─ Parallel tab navigation (non-sequential)?
│   └─ Not a wizard — use tabs / segmented controls
│
├─ Form data capture only (no business logic)?
│   └─ Use FW-31 MultiPageFormRenderer
│
├─ Guided business process with custom logic?
│   │
│   ├─ Organizations should customize steps?
│   │   └─ PF-41 System Template + ModuleWizardRenderer
│   │
│   ├─ Tightly coupled to module internals?
│   │   └─ WizardShell + custom step components
│   │
│   └─ Both customizable AND complex?
│       └─ PF-41 Hybrid (form + custom steps via registerWizardStep)
│
└─ Short dialog-based flow (≤4 steps)?
    └─ DialogWizardShell
```

#### 6. Standard Step Naming Conventions

Steps across all wizards SHOULD follow these naming patterns for consistency:

| Step purpose              | Recommended title      | Icon key          |
| ------------------------- | ---------------------- | ----------------- |
| Personal/demographic data | "Personal Information" | `user`            |
| Contact details           | "Contact Information"  | `mail`            |
| Employment/role details   | "Employment Details"   | `briefcase`       |
| Address/location          | "Address"              | `map-pin`         |
| Schedule/dates            | "Schedule"             | `calendar`        |
| Financial/payment         | "Payment Information"  | `wallet`          |
| Document upload           | "Documents"            | `file-text`       |
| Credentials/compliance    | "Credentials"          | `shield-check`    |
| Consent/agreements        | "Consent & Agreements" | `clipboard-check` |
| Settings/config           | "Configuration"        | `settings`        |
| Summary/review            | "Review & Submit"      | `review`          |
| Success/completion        | "Complete"             | `complete`        |

***

**Last Updated:** 2026-05-13
