---
name: step-03-specify
description: Iterative per-module specification - sections, entities, BR, permissions, mockups, validation
model: opus
next_step: steps/step-03-specify.md OR steps/step-04-consolidation.md (conditional)
---

# Step 3: Specification (Iterative Per-Module)

## MANDATORY EXECUTION RULES

- ALWAYS use ULTRATHINK mode
- This step is EXECUTED ONCE PER MODULE in topological dependency order
- ALWAYS check workflow state to determine current module
- ALWAYS reference completed modules when specifying current one
- **MANDATORY:** Generate and validate an ASCII/SVG mockup for EVERY section (not optional)
- ALL questions via AskUserQuestion tool
- ALL communication in `{language}`
- NEVER skip per-module validation
- **WIREFRAME RULE:** Every section MUST have a wireframe in `specification.uiWireframes[]`. No section without a validated mockup.
- **ID NAMING RULE (MANDATORY, NO EXCEPTION):**
  All IDs MUST include a module prefix to guarantee application-wide uniqueness.
  The prefix is derived from the module code initials (2-4 chars):
    UserManagement → UM | VehicleManagement → VM | PartsInventory → PI
    RepairManagement → RM | MaintenanceSchedule → MS | DataSync → DS
    Notifications → NT | Dashboard → DB | Orders → OR | Customers → CU

  Patterns:
    UC-{PREFIX}-{NNN}        → UC-RM-001, UC-PI-003
    BR-{CAT}-{PREFIX}-{NNN}  → BR-VAL-RM-001, BR-CALC-PI-002
    FR-{PREFIX}-{NNN}        → FR-RM-001
    OBJ-{PREFIX}-{NNN}       → OBJ-RM-001
    AC-{PREFIX}-{NNN}        → AC-RM-001
    RISK-{PREFIX}-{NNN}      → RISK-RM-001

  NEVER use bare IDs (UC-001, BR-VAL-001) in multi-module mode.
- **SCHEMA CONFORMITY RULE:**
  ALL data MUST fit within the defined feature-schema.json structure.
  NEVER create custom top-level fields (KPIDefinitions, ChartConfigurations, etc.)
  Dashboard modules MUST use specification.dashboards[] (it exists in the schema).
  If truly needed, use specification.extensions: {} (additionalProperties: true).

## YOUR TASK

Specify one module completely: walk through its sections and resources with the client, define entities, business rules, use cases, permissions, mockups, and validate before moving to the next module.

---

## EXECUTION SEQUENCE

### 1. Determine Current Module

```
ba-reader.readApplicationContext({feature_id})
→ Read metadata.workflow: moduleOrder, currentModuleIndex, completedModules
→ currentModule = moduleOrder[currentModuleIndex]
→ Display: "═══ Module {currentModuleIndex + 1}/{moduleOrder.length}: {currentModule} ═══"
```

IF module already specified (status = "specified" in master):
  Increment currentModuleIndex, re-check
  IF all modules specified → Load step-04-consolidation.md, STOP

### 2. Initialize Module Feature.json

```
// Create or load module-level feature.json
ba-writer.create({
  scope: "module",
  applicationRef: {feature_id},
  moduleCode: {currentModule.code},
  path: "docs/business/{app}/{module_code}/business-analyse/v1.0/feature.json"
})

// Inherit application roles from master
ba-reader.readApplicationContext({feature_id})
→ Copy cadrage.applicationRoles → module.applicationContext.applicationRoles
```

Update module status in master: "pending" → "in-progress"

### 2-ter. Derive Module Discovery Section (MANDATORY)

> **The module feature.json MUST have a `discovery` section.** In multi-module mode, derive it from the parent application's `cadrage`. In single-module mode, it should already exist from step-01.

```
ba-reader.readApplicationContext({feature_id})
→ Read cadrage: problem, asIs, toBe, trigger, stakeholders, risks, acceptanceCriteria

// Filter to this module's scope
moduleScope = cadrage.coverageMatrix.filter(cm => cm.module === currentModule.code)
moduleStakeholders = cadrage.stakeholders.filter(s => s.tasks relevant to this module)
moduleRisks = cadrage.risks.filter(r => r related to this module)

ba-writer.enrichSection({
  featureId: {module_feature_id},
  section: "discovery",
  data: {
    problem: cadrage.problem,
    asIs: cadrage.asIs,
    toBe: cadrage.toBe,
    trigger: cadrage.trigger,
    stakeholders: moduleStakeholders,
    scope: {
      mustHave: moduleScope.filter(s => s.category === "mustHave").map(s => s.item),
      shouldHave: moduleScope.filter(s => s.category === "shouldHave").map(s => s.item),
      couldHave: moduleScope.filter(s => s.category === "couldHave").map(s => s.item),
      outOfScope: []
    },
    risks: moduleRisks,
    acceptanceCriteria: cadrage.acceptanceCriteria.filter(ac => relevant to module),
    codebaseContext: cadrage.codebaseContext
  }
})
```

> **STRUCTURE CARD: discovery** — Same format as cadrage but module-scoped.
> Fields: `problem`, `asIs`, `toBe`, `trigger`, `stakeholders[]`, `scope{}`, `risks[]`, `acceptanceCriteria[]`, `codebaseContext`, `openQuestions[]`

### 2-bis. Coverage Verification (MANDATORY)

> **Before specifying any module, verify that the coverageMatrix from cadrage covers this module.**

```
ba-reader.readApplicationContext({feature_id})
→ Read cadrage.coverageMatrix[]
→ Filter entries where module = {currentModule.code}
→ Group by category: mustHave, shouldHave, couldHave
```

Display to client:
```
Module {currentModule}: Coverage from original brief

| # | Requirement | Category |
|---|-------------|----------|
| 1 | {item} | {category} |
| ... | ... | ... |

Total: {N} requirements mapped to this module
  - Must-have: {count}
  - Should-have: {count}
  - Could-have: {count}
```

**VALIDATION:** If mustHave count = 0 AND module is in must priority:
  → WARNING: "Module {currentModule} is must-priority but has no must-have requirements in coverageMatrix. Verify cadrage coverage."

**POST-SPECIFICATION CHECK (at end of module, before advancing):**
  For EACH mustHave item in coverageMatrix for this module:
    → Verify at least 1 UC exists that covers this requirement
    → If uncovered: BLOCK and ask client to either add a UC or reclassify the requirement

### 3. Section Walkthrough with Client

> **This is the key interactive phase aligned with the 5-level SmartStack hierarchy.**
> Level 3 = Module, Level 4 = Section, Level 5 = Resource

#### 3a. Identify Module Sections

For each module, propose standard sections based on module type:

| Module Type | Typical Sections |
|-------------|-----------------|
| data-centric | list, detail, create, edit |
| workflow | list, detail, create, edit, approve, history |
| integration | list, detail, config, sync, logs |
| reporting | dashboard, detail, export, schedule |
| full-module | list, detail, create, edit, approve, history, reports, settings |

Ask via AskUserQuestion:

```
question: "Quelles sections le module {currentModule} doit-il avoir ?"
header: "Sections"
multiSelect: true
options:
  - label: "Liste"
    description: "Page de liste avec filtres, tri et pagination"
  - label: "Détail"
    description: "Page de détail d'un enregistrement"
  - label: "Création/Édition"
    description: "Formulaire de création et de modification"
  - label: "Validation/Approbation"
    description: "Workflow de validation avec changement de statut"
  - label: "Dashboard"
    description: "Tableau de bord avec KPIs, graphiques (Recharts) et métriques clés"
```

#### 3a-depth. Determine Specification Depth

> **Based on module complexity and type, determine how deeply to specify sections and resources.**
> **This avoids over-specifying simple modules and under-specifying complex ones.**

Read from application master:
```
ba-reader.readApplicationContext({feature_id})
→ module = modules.find(m => m.code === currentModule)
→ complexity = module.estimatedComplexity   // simple | medium | complex
→ featureType = module.featureType          // data-centric | workflow | integration | reporting | full-module
```

**Depth decision matrix:**

| Complexity | featureType | Depth | Behavior |
|---|---|---|---|
| simple | data-centric | **convention** | Auto-generate sections + resources from entities. Quick client validation. |
| simple | reporting | **convention** | Standard dashboard template. Quick validation. |
| simple | * | **convention** | Standard sections for featureType. Quick validation. |
| medium | data-centric | **override** | Auto-generate then ask client which sections to customize. |
| medium | workflow | **full** | State machine required → always full. |
| medium | * | **override** | Auto-generate then ask client to customize. |
| complex | * | **full** | Full specification: state machine, typed columns, conditional actions. |
| * | workflow | **full** | Always full for workflow modules (state machine is mandatory). |

Display to client:
```
"Module {currentModule}: complexité {complexity}, type {featureType} → profondeur: {depth}"
```

**IF depth = convention:**
  - Execute 3a-infer (auto-inference) → generates sections + resources
  - Execute 3b (wireframes) for each section
  - Skip 3a-bis detailed walkthrough → present auto-generated spec for quick validation
  - Ask client: "La spécification auto-générée convient-elle, ou souhaitez-vous personnaliser certaines sections ?"
    - If client says OK → proceed to step 4 (questionnaires)
    - If client wants changes → switch to **override** for specified sections

**IF depth = override:**
  - Execute 3a-infer (auto-inference) → generates base sections + resources
  - Ask client: "Quelles sections souhaitez-vous personnaliser ?"
  - For selected sections → execute full 3a-bis + 3b + 3b-ter
  - For other sections → keep auto-generated spec

**IF depth = full:**
  - Execute standard flow: 3a-bis → 3b → 3b-bis → 3b-ter → 3c → 3d (as currently defined below)
  - PLUS: 3a-state (state machine definition) for entities with status fields

#### 3a-infer. Auto-Infer Resources from Entities (Convention/Override)

> **For convention and override depths, auto-generate resource details from entity definitions.**
> **The goal: produce a complete spec without manual input, that the client only validates.**

**Prerequisites:** Entity attributes must be defined (from step 6) OR anticipated from decomposition.

**Inference rules - Entity attribute → SmartTable column:**

| Attribute Type | Column Format | Sortable | Filterable | Notes |
|---|---|---|---|---|
| string + unique | text | yes | yes | clickAction: navigate:detail |
| string | text | yes | yes | — |
| enum / status | badge | yes | yes (multi-select) | colorMap from lifeCycles if exists |
| FK:Entity | text (join .name) | yes | yes (entity-select) | Display related entity name |
| decimal | currency | yes | no | — |
| int | number | yes | no | — |
| datetime | date-relative | yes | yes (date-range) | — |
| bool | boolean | yes | yes (toggle) | — |
| text (long) | — | no | no | Hidden in table, visible in detail |

**Inference rules - Entity attribute → SmartForm field:**

| Attribute Type | Component | Required from | Notes |
|---|---|---|---|
| string | Input | entity.required | — |
| string (multiline) | TextArea | entity.required | rows: 4 |
| enum | Select | entity.required | source: enum name |
| FK:Entity | EntitySelect | entity.required | source: target entity, searchable |
| decimal | NumberInput | entity.required | — |
| int | NumberInput | entity.required | — |
| datetime | DatePicker | entity.required | — |
| bool | Toggle | — | default: false |

**Auto-generated sections per featureType:**

| featureType | Sections generated |
|---|---|
| data-centric | list, create, detail |
| workflow | list, create, detail, edit |
| integration | list, detail, config |
| reporting | dashboard |
| full-module | list, create, detail, edit, dashboard |

**For each auto-generated section:**

1. **list section:** SmartTable with all non-long-text attributes as columns (convention or columnDefs based on depth), actions = [view, edit, delete], defaultSort = { createdAt, desc }
2. **create section:** SmartForm with all writable attributes as fields, component inferred from type
3. **detail section:** DetailCard with all attributes + child SmartTable for each 1:N relationship
4. **edit section:** Same as create but pre-filled (mode: edit)
5. **dashboard section:** Trigger 3d (dashboard specification)

**If entity has a status/enum field AND lifeCycles exists:**
- list section: status column gets `format: badge`, `colorMap: stateMachine:{Entity}`
- list section: rowActions get `showWhen` conditions based on state machine transitions
- detail section: add StatusBadge resource + transition action buttons

Write auto-generated sections to `specification.sections[]` via ba-writer.enrichSection()

#### 3a-state. Define Entity State Machine (Full Depth)

> **For full depth modules with entities that have a status/enum field, define the complete state machine.**
> **This drives conditional actions, badges, and transition effects throughout the UI.**

For each entity with a status-like attribute:

1. **Identify states** from the enum values or business rules:
```
Ask client: "Quels sont les états possibles pour {Entity}.{statusField} ?"
```

2. **Define transitions** - for each state, ask:
```
Ask client: "Depuis l'état {state}, quelles transitions sont possibles ?"
```

3. **For each transition**, capture:
   - `action`: verb label (submit, approve, reject, cancel, archive)
   - `permission`: which permission is required
   - `guards`: which BR must pass (reference existing BR-XXX from analysis)
   - `effects`: what happens after (notification, email, field update)
   - `confirm`: does the user need to confirm?

4. **Assign colors** to states for badge rendering:
   - Draft/New → gray
   - In Progress/Submitted → blue
   - Approved/Active → green
   - Warning/Pending → yellow
   - Error/Rejected → red
   - Archived/Cancelled → purple

5. **Store** in `specification.lifeCycles[]`:
```json
{
  "entity": "{Entity}",
  "field": "status",
  "initialState": "{firstState}",
  "states": [
    { "id": "draft", "displayName": "Brouillon", "color": "gray", "allowedTransitions": ["submitted"], "isTerminal": false }
  ],
  "transitions": [
    {
      "from": "draft", "to": "submitted", "action": "submit",
      "permission": "business.{app}.{module}.submit",
      "guards": ["BR-VAL-{PREFIX}-001"],
      "effects": [{ "type": "notification", "target": "role:manager", "template": "{module}-submitted" }],
      "confirm": true
    }
  ]
}
```

6. **Cross-validate:** Every `allowedTransitions` entry must have a matching `transitions[]` entry.

#### 3a-bis. Structure Sections with Resources (Levels 4 & 5)

> **DEPTH GATE:** Execute this section for **full** depth, or for individual sections flagged for customization in **override** depth. For **convention** depth, sections are auto-generated by 3a-infer — skip to 3b.

For EACH section confirmed in 3a, build the `specification.sections[]` structure:

1. For each resource in the section, determine:
   - The SmartStack component type (SmartTable, SmartForm, DetailCard, KpiPanel, Chart, Map, Timeline, etc.)
   - The entity it operates on
   - Columns/fields based on entity attributes
   - Permission (inherit from section or more specific)
   - Available actions

2. Link use cases to sections:
   - Each UC MUST belong to exactly ONE section
   - Map UC to section based on the primary action (list → UC-XX-001, create → UC-XX-003, etc.)

3. Link business rules to sections:
   - Each BR can belong to one or more sections
   - Map BR based on where it's enforced (validation BR → create/edit section, calc BR → detail section)

4. Build the section object:

> **STRUCTURE CARD: specification.sections[]** — Resources MUST include full depth definitions.
> ```json
> {
>   "code": "list",
>   "labels": { "fr": "Liste", "en": "List", "it": "Elenco", "de": "Liste" },
>   "route": "/business/{app}/{module}/list",
>   "icon": "list",
>   "permission": "business.{app}.{module}.read",
>   "wireframe": "{module}-list",
>   "useCases": ["UC-{PREFIX}-001", "UC-{PREFIX}-002"],
>   "businessRules": ["BR-VAL-{PREFIX}-001"],
>   "resources": [
>     {
>       "code": "{module}-grid",
>       "type": "SmartTable",
>       "entity": "{MainEntity}",
>       "permission": "business.{app}.{module}.read",
>       "columns": ["name", "status", "createdAt"],
>       "columnDefs": [
>         { "field": "code", "label": {"fr": "Code", "en": "Code"}, "format": "text", "sortable": true, "filterable": true, "clickAction": "navigate:detail" },
>         { "field": "name", "label": {"fr": "Nom", "en": "Name"}, "format": "text", "sortable": true, "filterable": true },
>         { "field": "status", "label": {"fr": "Statut", "en": "Status"}, "format": "badge", "sortable": true, "filterable": true, "colorMap": "stateMachine:{Entity}" },
>         { "field": "createdAt", "label": {"fr": "Créé le", "en": "Created"}, "format": "date-relative", "sortable": true }
>       ],
>       "actions": ["view", "edit", "delete"],
>       "rowActions": [
>         { "action": "view", "icon": "eye", "permission": "business.{app}.{module}.read" },
>         { "action": "edit", "icon": "edit", "permission": "business.{app}.{module}.update", "showWhen": {"status": ["draft"]} },
>         { "action": "delete", "icon": "trash", "permission": "business.{app}.{module}.delete", "confirm": true }
>       ],
>       "filters": ["status", "dateRange"],
>       "defaultSort": { "field": "createdAt", "direction": "desc" },
>       "defaultPageSize": 20,
>       "emptyState": { "icon": "inbox", "message": {"fr": "Aucun enregistrement", "en": "No records"}, "createAction": true }
>     }
>   ]
> }
> ```
>
> **SmartForm resource example (for create/edit sections):**
> ```json
> {
>   "code": "{module}-form",
>   "type": "SmartForm",
>   "entity": "{MainEntity}",
>   "permission": "business.{app}.{module}.create",
>   "fields": [
>     { "name": "code", "component": "Input", "required": true, "validation": "Unique, auto-generated" },
>     { "name": "name", "component": "Input", "required": true },
>     { "name": "type", "component": "Select", "required": true, "source": "EntityTypeEnum" },
>     { "name": "description", "component": "TextArea", "required": false },
>     { "name": "parentId", "component": "EntitySelect", "source": "ParentEntity", "required": true },
>     { "name": "startDate", "component": "DatePicker", "required": true },
>     { "name": "isActive", "component": "Toggle", "default": true }
>   ],
>   "formLayout": {
>     "type": "tabs",
>     "tabs": [
>       { "code": "general", "label": {"fr": "Général", "en": "General"}, "fields": ["code", "name", "type", "description"] },
>       { "code": "details", "label": {"fr": "Détails", "en": "Details"}, "fields": ["parentId", "startDate", "isActive"] }
>     ]
>   }
> }
> ```
> **MANDATORY for SmartTable:** `columnDefs`, `rowActions`, `defaultSort`, `emptyState`
> **MANDATORY for SmartForm:** `fields` with `component` type, `formLayout`

5. Write `specification.sections[]` via ba-writer.enrichSection()

**VALIDATION:** Every UC must appear in exactly one section.useCases[]. No orphan UCs.

#### 3b. For Each Section: Generate MANDATORY ASCII Mockup

> **BLOCKING RULE:** Every section MUST have a wireframe. No section proceeds to entity definition (step 6) without a validated mockup stored in `specification.uiWireframes[]`.

For each confirmed section, generate an ASCII mockup and validate with client:

Example for a list section:

```
╔═══════════════════════════════════════════════════════════╗
║  {Module} > Liste                                 [+ Nouveau] ║
╠═══════════════════════════════════════════════════════════╣
║  🔍 Rechercher...  │ Statut: [Tous ▾]  │ Date: [Ce mois ▾] ║
╠═══════════════════════════════════════════════════════════╣
║  # │ {Field1}  │ {Field2}    │ {Field3} │ Statut  │ ···  ║
║  1 │ VAL-001   │ Exemple 1   │ 12'500.- │ ● Brouillon │ ⋮ ║
║  2 │ VAL-002   │ Exemple 2   │  8'300.- │ ● Envoyé    │ ⋮ ║
╠═══════════════════════════════════════════════════════════╣
║  1-25 de 142  │  ◀  1  2  3  ···  6  ▶                   ║
╚═══════════════════════════════════════════════════════════╝
```

Store in specification.uiWireframes[] (**MANDATORY** for every section):

> **STRUCTURE CARD: specification.uiWireframes[]** — ALL fields below are MANDATORY.
> ```json
> {
>   "screen": "{module}-{section}",
>   "section": "{section}",
>   "description": "Description of the screen",
>   "mockupFormat": "ascii",
>   "mockup": "╔═══...",
>   "elements": ["DataGrid", "FilterBar", "Pagination", "CreateButton"],
>   "actions": ["filter", "sort", "create", "view-detail"],
>   "permissionsRequired": ["business.{app}.{module}.read"],
>   "componentMapping": [
>     { "wireframeElement": "DataGrid", "reactComponent": "SmartTable" },
>     { "wireframeElement": "FilterBar", "reactComponent": "SmartFilter" },
>     { "wireframeElement": "CreateButton", "reactComponent": "Button" }
>   ],
>   "layout": {
>     "type": "page",
>     "regions": [
>       { "id": "toolbar", "position": "top", "components": [
>         { "type": "FilterBar", "resourceRef": "{module}-filters" },
>         { "type": "ActionMenu", "resourceRef": "{module}-actions", "permission": "business.{app}.{module}.create" }
>       ]},
>       { "id": "content", "position": "main", "span": 12, "components": [
>         { "type": "SmartTable", "resourceRef": "{module}-grid" }
>       ]}
>     ]
>   }
> }
> ```
> **REQUIRED fields:** `screen`, `mockup`, `elements`, `section`, `componentMapping`, `layout` are ALL mandatory.
> A wireframe without `componentMapping` or `layout` will FAIL validation in step 9.
> **layout.regions[].components[].resourceRef** MUST match a `sections[].resources[].code`.

Ask client to validate each mockup via AskUserQuestion (batch 2-3 mockups at once if possible).

> **IF client rejects a mockup:** Revise and re-propose until validated. Do NOT proceed without client approval on the layout.

#### 3b-bis. Wireframe-to-Component Mapping

After client validates the mockup, map each wireframe element to a SmartStack React component:

| Wireframe Element | SmartStack Component | Notes |
|-------------------|---------------------|-------|
| DataGrid | `SmartTable` or `EntityCard` grid | Use EntityCard for card layouts |
| FilterBar | `SmartFilter` | Integrated with SmartTable |
| SearchInput | `SearchInput` | Debounced search |
| Pagination | Built into `SmartTable` | Server-side pagination |
| ActionButton | `Button` + `RequirePermission` | Always wrapped in permission check |
| StatusBadge | `StatusBadge` | Uses entity lifecycle states |
| DetailCard | `EntityDetailCard` | Standard detail layout |
| Form | `SmartForm` | FluentValidation-backed |
| KpiCard | `StatCard` (Recharts) | Dashboard KPI display |
| Chart:bar/line/pie | Recharts `BarChart`/`LineChart`/`PieChart` | CSS variables for colors |

Store the component mapping alongside the wireframe to ensure downstream skills use the correct components.

#### 3b-ter. Generate Structural Layout

For EACH wireframe generated in 3b, generate a `layout` object alongside the ASCII mockup:

1. From the ASCII mockup, extract the visual regions (header, toolbar, main content, sidebar, etc.)
2. For each region, map the visual elements to SmartStack component types
3. Build the layout structure:
```json
{
  "type": "page",
  "regions": [
    { "id": "toolbar", "position": "top", "components": [
      { "type": "FilterBar", "resourceRef": "{module}-filters" },
      { "type": "ActionMenu", "resourceRef": "{module}-actions", "permission": "business.{app}.{module}.create" }
    ]},
    { "id": "content", "position": "main", "span": 12, "components": [
      { "type": "SmartTable", "resourceRef": "{module}-grid" }
    ]}
  ]
}
```
4. Cross-validate: each component in layout.regions[].components[] MUST have a corresponding resource in sections[].resources[]
5. Write layout alongside mockup in uiWireframes[]

**RULE:** The layout is the source of truth for ralph-loop. The mockup is for human validation only.

#### 3c. Identify Resources per Section

For each section, identify what resources/components are needed:

- List section → DataGrid, FilterBar, SearchInput, ExportButton
- Detail section → DetailCard, StatusBadge, ActionButtons, Timeline
- Create section → Form, ValidationMessages, SubmitButton
- Approve section → StatusTransitionPanel, CommentBox, ApproveRejectButtons
- Dashboard section → StatCard, RechartsChart (Bar/Line/Pie/Area), DashboardGrid, FilterBar

#### 3d. Dashboard Specification (if section = dashboard)

When a "dashboard" section is selected, capture structured KPI and chart data **in addition** to the standard ASCII mockup.

1. **Ask client for KPIs** via AskUserQuestion (batch):
   - KPI name and metric description
   - Visualization type: `kpi-card`, `bar`, `line`, `pie`, `area`, `donut`, `stacked-bar`
   - Data source entity
   - Format: `number`, `currency`, `percent`, `duration`
   - Thresholds (warning/critical) if applicable

2. **Ask client for filters:**
   - Date range filter? Default period? (day/week/month/quarter/year)
   - Entity-based filters? (status, category, etc.)

3. **Ask client for refresh mode:**
   - Static (load on page open)
   - Polling (periodic refresh)
   - SignalR (real-time push)

4. **Store in specification.dashboards[]:**

```json
{
  "code": "{module}-dashboard",
  "title": "{Module} Dashboard",
  "description": "Vue d'ensemble des métriques {module}",
  "linkedUCs": ["UC-XXX"],
  "refreshMode": "static",
  "defaultPeriod": "month",
  "kpis": [
    {
      "code": "total-items",
      "label": "Total Items",
      "metric": "COUNT(entity)",
      "format": "number",
      "visualization": "kpi-card",
      "dataSource": "Entity",
      "thresholds": { "warning": 100, "critical": 50 }
    },
    {
      "code": "items-by-status",
      "label": "Items by Status",
      "metric": "COUNT(entity) GROUP BY status",
      "format": "number",
      "visualization": "pie",
      "dataSource": "Entity",
      "dimensions": ["status"]
    }
  ],
  "filters": [
    { "field": "dateRange", "type": "dateRange", "label": "Période" },
    { "field": "status", "type": "multiselect", "label": "Statut" }
  ],
  "permissionsRequired": ["business.{app}.{module}.read"]
}
```

5. **ALSO generate the standard ASCII mockup** for the dashboard with KPI cards + chart placeholders:

```
╔═══════════════════════════════════════════════════════════════╗
║  {Module} > Dashboard              Période: [Ce mois ▾]     ║
╠═══════════════════════════════════════════════════════════════╣
║  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    ║
║  │ KPI #1   │  │ KPI #2   │  │ KPI #3   │  │ KPI #4   │    ║
║  │  1,234   │  │  567     │  │  89.2%   │  │  12,400  │    ║
║  │  ↑ +12%  │  │  ↓ -3%  │  │  → 0%   │  │  ↑ +5%   │    ║
║  └──────────┘  └──────────┘  └──────────┘  └──────────┘    ║
╠═══════════════════════════════════════════════════════════════╣
║  ┌─────────────────────────┐  ┌─────────────────────────┐    ║
║  │  [Bar Chart]            │  │  [Pie Chart]            │    ║
║  │  Items by Month         │  │  Items by Status        │    ║
║  │  ████                   │  │      ████████           │    ║
║  │  ████ ████              │  │   ███      ███          │    ║
║  │  ████ ████ ████         │  │  ██   42%    ██         │    ║
║  └─────────────────────────┘  └─────────────────────────┘    ║
╚═══════════════════════════════════════════════════════════════╝
```

Store the mockup in specification.wireframes[] AS WELL (for visual reference).

### 4. Conditional Questionnaires

Based on module type, load questionnaires per-module:

| Condition | Category | Questionnaire |
|-----------|----------|---------------|
| Always | 04 | `questionnaire/04-data.md` |
| Has UI sections | 07 | `questionnaire/07-ui.md` |
| Has lifecycle | 11 | `questionnaire/11-data-lifecycle.md` |
| Has migration needs | 12 | `questionnaire/12-migration.md` |
| References other modules | 13 | `questionnaire/13-cross-module.md` |
| Documentation needed | 10 | `questionnaire/10-documentation.md` |

Ask via AskUserQuestion, 1-2 batches per category.

#### Store Documentation Requirements

If questionnaire 10 was loaded, persist answers in feature.json:

```
ba-writer.enrichSection({
  featureId: {feature_id},
  section: "documentation",
  data: {
    userDocRequired: {Q10.1 answer == "Yes"},
    techDocRequired: {Q10.2 answer == "Yes"},
    status: "pending"
  }
})
```

This data will be consumed by `/application` step-08 to auto-generate in-app documentation.

### 5. Cross-Module References

> Reference completed modules to help define current one.

```
completedModules = ba-reader.getCompletedModulesSummary({feature_id})
→ Returns max 100 lines summary: entity names, key BRs, permissions

Display: "Modules déjà spécifiés : {completedModules.map(m => m.code).join(', ')}"
```

For each completed module's entities, ask:

```
question: "Le module {currentModule} référence-t-il des entités de {completedModule} ?"
header: "Références"
multiSelect: true
options:
  - label: "{Entity1} (FK)"
    description: "Référence directe via clé étrangère"
  - label: "{Entity2} (Lookup)"
    description: "Table de référence / lookup"
  - label: "Aucune"
    description: "Pas de référence à {completedModule}"
```

### 6. Analysis Section

#### 6a. Objectives

Define measurable business objectives for this module:

> **STRUCTURE CARD: analysis.objectives[]**
> ```json
> { "id": "OBJ-{PREFIX}-001", "objective": "Reduce order processing time", "metric": "Average time to fulfillment", "target": "< 4 hours" }
> ```

#### 6b. Entity Definition

Define entities for this module (business attributes, not technical):

> **STRUCTURE CARD: analysis.entities[]** — Field names are EXACT. Do NOT deviate.
> ```json
> {
>   "name": "PascalCase",
>   "description": "1-2 sentences describing the entity purpose",
>   "attributes": [
>     {
>       "name": "attributeName",
>       "description": "What this attribute represents",
>       "required": true,
>       "unique": false,
>       "validation": "Format: XXX-NNNNN, max 100 chars, etc."
>     }
>   ],
>   "relationships": [
>     { "target": "OtherEntity", "type": "1:1|1:N|N:1|N:M", "description": "description" }
>   ]
> }
> ```
> **FORBIDDEN fields in attributes:** Do NOT use `type`, `values`, `rules`.
> Use `description` to explain what the attribute is, `validation` for format/constraint rules, `unique` as boolean.

#### 6c. Process Flow

Define the main business process flow for this module (not lifecycle — that's in 8j):

> **STRUCTURE CARD: analysis.processFlow**
> ```json
> {
>   "entryPoints": ["User navigates to module", "System event triggers action"],
>   "mainFlow": [
>     { "step": 1, "actor": "Manager", "action": "Opens the list", "system": "Displays filtered records" },
>     { "step": 2, "actor": "Manager", "action": "Creates a record", "system": "Validates BR-VAL-{PREFIX}-001" },
>     { "step": 3, "actor": "System", "action": "Saves record", "system": "Sends notification" }
>   ],
>   "decisionPoints": [
>     { "condition": "Is amount > threshold?", "ifTrue": "Route to approver", "ifFalse": "Auto-approve", "rule": "BR-WF-{PREFIX}-001" }
>   ],
>   "alternativeFlows": ["Bulk import via CSV", "Automatic sync from SFTP"]
> }
> ```
> **FORBIDDEN:** Do NOT put lifecycle/state machine data here. Use `specification.lifeCycles[]` for that.

#### 6d. Data Lifecycle

Define data retention and lifecycle policies:

> **STRUCTURE CARD: analysis.dataLifecycle**
> ```json
> {
>   "retentionPeriod": "7 years",
>   "archiveStrategy": "Move to cold storage after 2 years",
>   "gdprCompliance": "PII anonymized on request, data export available",
>   "states": [
>     { "name": "active", "transitions": ["archived", "deleted"] },
>     { "name": "archived", "transitions": ["active"] },
>     { "name": "deleted", "transitions": [] }
>   ]
> }
> ```

### 7. Business Rules Extraction

Extract business rules specific to this module:

> **STRUCTURE CARD: analysis.businessRules[]** — Field names are EXACT. Do NOT deviate.
> ```json
> {
>   "id": "BR-VAL-{PREFIX}-001",
>   "name": "Short rule name",
>   "category": "validation|calculation|workflow|security|data",
>   "statement": "IF {condition} THEN {consequence} ELSE {alternative}",
>   "priority": "must|should|could",
>   "conditions": ["Condition 1", "Condition 2"],
>   "examples": [{ "input": "Order total $5000, budget $2000", "expected": "Order rejected" }],
>   "testability": "Via unit test with mock data / integration test"
> }
> ```
> **MANDATORY fields:** `id`, `name`, `category`, `statement`, `priority`
> **FORBIDDEN fields:** Do NOT use `rule`, `condition` (singular), `action`. Use `name` + `statement` (IF/THEN/ELSE format) + `conditions` (array).
> **ID PATTERN:** `BR-{CAT}-{PREFIX}-{NNN}` where CAT = VAL|CALC|WF|SEC|DATA, PREFIX = module initials (2-4 chars)
> **category values:** lowercase only: `validation`, `calculation`, `workflow`, `security`, `data`

### 8. Full Specification

Generate the complete specification for this module. **Each subsection below includes a STRUCTURE CARD showing the EXACT JSON format. Follow them precisely.**

#### 8a. Actors

Inherited from application roles → mapped to module permissions.

> **STRUCTURE CARD: specification.actors[]**
> ```json
> {
>   "role": "Sales Manager",
>   "description": "Creates and approves orders",
>   "permissions": [
>     "business.{app}.{module}.read",
>     "business.{app}.{module}.create",
>     "business.{app}.{module}.update"
>   ]
> }
> ```
> **MANDATORY fields:** `role`, `permissions` (array of permission paths)
> **FORBIDDEN fields:** Do NOT use `systemRole`. Use `permissions` array.

#### 8b. Use Cases (UC-{PREFIX}-NNN)

Per section: list, create, read, update, delete, approve, etc.

> **STRUCTURE CARD: specification.useCases[]**
> ```json
> {
>   "id": "UC-{PREFIX}-001",
>   "name": "Create Order",
>   "primaryActor": "Sales Representative",
>   "permission": "business.{app}.{module}.create",
>   "preconditions": ["Customer exists", "Products in stock"],
>   "postconditions": ["Order created with Draft status"],
>   "mainScenario": [
>     "1. User navigates to creation form",
>     "2. User fills in required fields",
>     "3. System validates data (BR-VAL-{PREFIX}-001)",
>     "4. System creates the record",
>     "5. System displays confirmation"
>   ],
>   "alternativeScenarios": [
>     { "name": "Validation failure", "steps": ["1. System detects invalid data", "2. System highlights errors"] }
>   ],
>   "errorScenarios": [
>     { "name": "Server error", "steps": ["1. System shows error message", "2. Data preserved for retry"] }
>   ],
>   "linkedRules": ["BR-VAL-{PREFIX}-001", "BR-WF-{PREFIX}-002"]
> }
> ```
> **MANDATORY fields:** `id`, `name`, `primaryActor`, `permission`, `mainScenario`, `linkedRules`
> **FORBIDDEN fields:** Do NOT use `actor` (use `primaryActor`), `linkedBRs` (use `linkedRules`), `linkedFRs` (not in UC, FRs link to UCs instead)

#### 8c. Functional Requirements (FR-{PREFIX}-NNN)

Linked to BRs and UCs.

> **STRUCTURE CARD: specification.functionalRequirements[]**
> ```json
> {
>   "id": "FR-{PREFIX}-001",
>   "statement": "System MUST validate customer budget before order creation",
>   "priority": "must|should|could",
>   "linkedRules": ["BR-VAL-{PREFIX}-001"],
>   "linkedUseCases": ["UC-{PREFIX}-001"],
>   "acceptanceCriteria": [
>     "Order rejected if total > budget",
>     "Error message displayed with remaining budget"
>   ]
> }
> ```
> **MANDATORY fields:** `id`, `statement`, `priority`, `linkedUseCases`
> **FORBIDDEN fields:** Do NOT use `name`/`description` (use `statement` with System MUST/SHOULD/COULD format), `linkedUCs` (use `linkedUseCases`), `linkedBRs` (use `linkedRules`)

#### 8d. Permission Matrix

Roles × resources × operations with full paths.

> **STRUCTURE CARD: specification.permissionMatrix**
> ```json
> {
>   "permissions": [
>     { "path": "business.{app}.{module}.read", "action": "read", "description": "View records" },
>     { "path": "business.{app}.{module}.create", "action": "create", "description": "Create new records" },
>     { "path": "business.{app}.{module}.update", "action": "update", "description": "Update existing records" },
>     { "path": "business.{app}.{module}.delete", "action": "delete", "description": "Delete records" },
>     { "path": "business.{app}.{module}.export", "action": "export", "description": "Export data" }
>   ],
>   "roleAssignments": [
>     { "role": "{App} Admin", "permissions": ["business.{app}.{module}.read", "business.{app}.{module}.create", "business.{app}.{module}.update", "business.{app}.{module}.delete", "business.{app}.{module}.export"] },
>     { "role": "{App} Manager", "permissions": ["business.{app}.{module}.read", "business.{app}.{module}.create", "business.{app}.{module}.update"] },
>     { "role": "{App} Viewer", "permissions": ["business.{app}.{module}.read"] }
>   ]
> }
> ```
> **STRUCTURE:** Object with 2 arrays: `permissions[]` and `roleAssignments[]`
> **FORBIDDEN:** Do NOT use a flat array with `resource`/`roles` fields. Always use the nested structure above.

#### 8e. Navigation

Module → Sections → Resources (levels 3-4-5 of the hierarchy).

> **STRUCTURE CARD: specification.navigation**
> ```json
> {
>   "entries": [
>     { "level": "module", "code": "{module}", "labels": {"fr": "...", "en": "..."}, "route": "/business/{app}/{module}", "icon": "list" },
>     { "level": "section", "code": "list", "labels": {"fr": "Liste", "en": "List", "it": "Elenco", "de": "Liste"}, "route": "/business/{app}/{module}/list", "icon": "list" },
>     { "level": "section", "code": "dashboard", "labels": {"fr": "Dashboard", "en": "Dashboard"}, "route": "/business/{app}/{module}/dashboard", "icon": "chart-bar", "isNew": true }
>   ]
> }
> ```

#### 8f. SeedData Core

5 MANDATORY typed arrays — each with structured objects, NOT flat strings or objects.

> **STRUCTURE CARD: specification.seedDataCore**
> ```json
> {
>   "navigationModules": [
>     { "code": "{module}", "label": "{Module Name}", "icon": "list", "route": "/business/{app}/{module}", "parentCode": "{app}", "sort": 1 }
>   ],
>   "navigationTranslations": [
>     { "moduleCode": "{module}", "language": "fr", "label": "..." },
>     { "moduleCode": "{module}", "language": "en", "label": "..." },
>     { "moduleCode": "{module}", "language": "it", "label": "..." },
>     { "moduleCode": "{module}", "language": "de", "label": "..." }
>   ],
>   "permissions": [
>     { "path": "business.{app}.{module}.read", "action": "read", "description": "View {module}" },
>     { "path": "business.{app}.{module}.create", "action": "create", "description": "Create {module}" }
>   ],
>   "rolePermissions": [
>     { "role": "{App} Admin", "permissionPath": "business.{app}.{module}.*" },
>     { "role": "{App} Manager", "permissionPath": "business.{app}.{module}.read" }
>   ],
>   "permissionConstants": [
>     { "constantName": "{Module}Read", "path": "business.{app}.{module}.read" },
>     { "constantName": "{Module}Create", "path": "business.{app}.{module}.create" }
>   ]
> }
> ```
> **MANDATORY:** All 5 arrays must be present. Each element must be an object, NOT a string.
> **FORBIDDEN:** Do NOT use `navigationModule` (singular string), `permissions` as flat string array, `rolePermissions` as flat object, `permissionsConstants` as comma-separated string.

#### 8g. Gherkin Scenarios

BDD acceptance tests per UC.

> **STRUCTURE CARD: specification.gherkinScenarios[]**
> ```json
> {
>   "feature": "{Module} Management",
>   "scenarios": [
>     {
>       "name": "Create a new record with valid data",
>       "tags": ["@{module}", "@create", "@smoke"],
>       "given": ["An authenticated user with role Manager", "No existing record with code 'TEST-001'"],
>       "when": ["The user fills the creation form", "The user submits the form"],
>       "then": ["The record is created with Draft status", "A success message is displayed"]
>     }
>   ]
> }
> ```
> **STRUCTURE:** Object with `feature` string + `scenarios[]` array. Each scenario has `given`, `when`, `then` as ARRAYS of strings.
> **FORBIDDEN:** Do NOT use flat arrays of `{uc, scenario, given, when, then}` where given/when/then are single strings.

#### 8h. Validations

Field validation rules per entity.

> **STRUCTURE CARD: specification.validations[]**
> ```json
> {
>   "entity": "Order",
>   "field": "amount",
>   "rules": ["required", "decimal", "min:0.01", "max:999999.99"],
>   "errorMessageKey": "validation.{module}.amount.invalid"
> }
> ```
> **MANDATORY fields:** `entity`, `field`, `rules` (array), `errorMessageKey`
> **FORBIDDEN fields:** Do NOT use `rule` (singular string) or `message` (use `errorMessageKey`).

#### 8i. Business Messages

Minimum 4: success, error CRUD, error validation, error permission.

> **STRUCTURE CARD: specification.messages[]**
> ```json
> {
>   "code": "{MODULE}-SUCCESS-CREATE",
>   "type": "success|error|warning|info",
>   "title": "Record Created",
>   "message": "The record {code} has been created successfully.",
>   "i18nKey": "message.{module}.created"
> }
> ```
> **MANDATORY fields:** `code`, `type`, `message`, `i18nKey`
> **FORBIDDEN:** Do NOT omit `title` or `i18nKey`. Every message MUST have an i18n key.

#### 8j. Entity Lifecycle

State machines for entities with status/state.
**Note:** If depth = full and 3a-state was executed, lifeCycles are already defined. Verify completeness and add any missing states/transitions.

> **STRUCTURE CARD: specification.lifeCycles[]**
> ```json
> {
>   "entity": "Order",
>   "field": "status",
>   "initialState": "draft",
>   "states": [
>     { "id": "draft", "displayName": "Brouillon", "color": "gray", "allowedTransitions": ["submitted"], "isTerminal": false },
>     { "id": "submitted", "displayName": "Soumis", "color": "blue", "allowedTransitions": ["approved", "rejected"], "isTerminal": false },
>     { "id": "approved", "displayName": "Approuvé", "color": "green", "allowedTransitions": ["archived"], "isTerminal": false },
>     { "id": "rejected", "displayName": "Rejeté", "color": "red", "allowedTransitions": [], "isTerminal": true },
>     { "id": "archived", "displayName": "Archivé", "color": "purple", "allowedTransitions": [], "isTerminal": true }
>   ],
>   "transitions": [
>     {
>       "from": "draft", "to": "submitted", "action": "submit",
>       "label": { "fr": "Soumettre", "en": "Submit" },
>       "permission": "business.{app}.{module}.update",
>       "guards": ["BR-VAL-{PREFIX}-001"],
>       "effects": [{ "type": "notification", "target": "role:manager", "template": "{module}-submitted" }],
>       "confirm": true
>     }
>   ]
> }
> ```
> **MANDATORY:** `states` MUST be an array of OBJECTS with `id`, `displayName`, `color`, `allowedTransitions`, `isTerminal`. NEVER use flat string arrays.
> **Colors:** gray (draft/new), blue (in-progress), green (active/approved), yellow (warning/pending), orange (review), red (error/rejected), purple (archived/terminal)
> **FORBIDDEN:** Do NOT use `states: ["Active", "Inactive"]` (flat strings), `terminalStates` (use `isTerminal: true` on each state).

#### 8k. API Endpoints

RESTful routes following SmartStack patterns.

> **STRUCTURE CARD: specification.apiEndpoints[]**
> ```json
> {
>   "method": "GET|POST|PUT|PATCH|DELETE",
>   "path": "/api/business/{app}/{module}",
>   "permission": "business.{app}.{module}.read",
>   "requestDto": "Get{Module}Query",
>   "responseDto": "{Module}Dto[]",
>   "description": "List all records with pagination and filters"
> }
> ```
> **MANDATORY fields:** `method`, `path`, `permission`, `description`
> **Recommended:** Include `requestDto` and `responseDto` for implementation clarity.

#### 8l. i18n Keys

Translation keys for all UI text (4 languages: fr, en, it, de).

> **STRUCTURE CARD: specification.i18nKeys**
> ```json
> {
>   "title": { "fr": "{Module}", "en": "{Module}", "it": "{Module}", "de": "{Module}" },
>   "list": { "title": { "fr": "Liste", "en": "List" }, "empty": { "fr": "Aucun enregistrement", "en": "No records" } },
>   "create": { "title": { "fr": "Nouveau", "en": "New" } },
>   "detail": { "title": { "fr": "Détail", "en": "Detail" } },
>   "buttons": { "create": { "fr": "Créer", "en": "Create" }, "edit": { "fr": "Modifier", "en": "Edit" }, "delete": { "fr": "Supprimer", "en": "Delete" } },
>   "validation": { "required": { "fr": "Ce champ est requis", "en": "This field is required" } }
> }
> ```

### 9. Per-Module Validation

> **Fused from old step-03-validate.md, run INLINE after specification.**

#### 9a. Completeness Checks

| Section | Minimum | Status |
|---------|---------|--------|
| actors | 2 | PASS/FAIL |
| useCases | 2 | PASS/FAIL |
| functionalRequirements | 4 | PASS/FAIL |
| permissionMatrix | 1 resource × 2 roles | PASS/FAIL |
| entities | 1 | PASS/FAIL |
| wireframes | 1 per section (BLOCKING) | PASS/FAIL |
| gherkinScenarios | 2 per UC | PASS/FAIL |
| validations | 1 | PASS/FAIL |
| messages | 4 | PASS/FAIL |
| lifeCycles | 1 (if entity has status) | PASS/FAIL |
| seedDataCore | 5 sections present | PASS/FAIL (BLOCKING) |

#### 9b. Consistency Checks

- Every UC has ≥1 linked FR
- Every FR has ≥1 linked BR
- All BR references exist in analysis.businessRules
- All actors appear in permissionMatrix
- Permission paths use full format: `business.{app}.{module}.{resource}.{action}`
- rolePermissions paths match permissions paths
- API routes use consistent prefix

#### 9c. Convention Checks

- UC-NNN format
- FR-NNN format
- BR-{CATEGORY}-NNN format
- Entity names PascalCase
- Field names camelCase
- Permission paths dot-separated lowercase

#### 9d. Decision

IF validation PASS:
  Display summary, ask client for confirmation

IF validation FAIL:
  Display errors, offer:
  ```
  options:
    - label: "Auto-corriger"
      description: "Corriger automatiquement les erreurs détectées"
    - label: "Réviser manuellement"
      description: "Revenir aux sections problématiques"
    - label: "Forcer la validation"
      description: "Accepter malgré les erreurs (risqué)"
  ```

#### 9e. Write Module Validation Section (MANDATORY)

> **The module feature.json MUST have a `validation` section recording the results of steps 9a-9d.**

```
ba-writer.enrichSection({
  featureId: {module_feature_id},
  section: "validation",
  data: {
    validatedAt: "{ISO timestamp}",
    completenessChecks: [
      { "section": "useCases", "count": {count}, "minimum": 2, "status": "PASS|FAIL" },
      { "section": "functionalRequirements", "count": {count}, "minimum": 4, "status": "PASS|FAIL" },
      { "section": "wireframes", "count": {count}, "minimum": {section_count}, "status": "PASS|FAIL" },
      { "section": "seedDataCore", "count": 5, "minimum": 5, "status": "PASS|FAIL" }
    ],
    consistencyChecks: [
      { "check": "UC-FR linkage", "passed": {n}, "warnings": {n}, "errors": {n}, "status": "PASS|FAIL" },
      { "check": "BR references valid", "passed": {n}, "warnings": {n}, "errors": {n}, "status": "PASS|FAIL" },
      { "check": "Permission path format", "passed": {n}, "warnings": {n}, "errors": {n}, "status": "PASS|FAIL" }
    ],
    conventionChecks: [
      { "check": "ID naming with module prefix", "status": "PASS|FAIL", "details": "..." },
      { "check": "Entity names PascalCase", "status": "PASS|FAIL", "details": "..." }
    ],
    semanticChecks: [
      { "check": "orphan-permissions", "module": "{currentModule}", "status": "PASS|WARNING|ERROR", "details": "...", "autoFixed": false },
      { "check": "uc-sans-fr", "module": "{currentModule}", "status": "PASS|WARNING|ERROR", "details": "...", "autoFixed": false },
      { "check": "missing-wireframes", "module": "{currentModule}", "status": "PASS|WARNING|ERROR", "details": "...", "autoFixed": false }
    ],
    warnings: ["List of non-blocking warnings"],
    decision: {
      "approved": true,
      "reason": "All checks passed",
      "approvalMode": "standard",
      "approvedBy": "Client",
      "approvedAt": "{ISO timestamp}"
    }
  }
})
```

### 10. Module Summary with Roles & Permissions

Display comprehensive summary:

```
═══════════════════════════════════════════════════════════
  MODULE SPÉCIFIÉ: {currentModule} ({currentModuleIndex + 1}/{total})
═══════════════════════════════════════════════════════════

| Aspect | Valeur |
|--------|--------|
| Entités | {count} ({entity names}) |
| Business Rules | {count} (VAL: X, CALC: Y, WF: Z) |
| Use Cases | {count} (UC-001 → UC-NNN) |
| Exigences | {count} FRs |
| Sections | {count} ({section names}) |
| Maquettes | {count} wireframes |
| Permissions | {count} paths |
| Tests Gherkin | {count} scénarios |
| Messages | {count} |

### Rôles & Permissions pour {currentModule}
| Rôle | Permissions |
|------|------------|
| {App} Admin | business.{app}.{module}.* |
| {App} Manager | read, create, update, assign |
| {App} Contributor | read, create, update |
| {App} Viewer | read |

→ Validation: {PASS/FAIL}
═══════════════════════════════════════════════════════════
```

Ask via AskUserQuestion:

```
question: "Le module {currentModule} est-il correctement spécifié ?"
header: "Module"
options:
  - label: "Validé"
    description: "Passer au module suivant"
  - label: "Réviser"
    description: "Modifier des éléments du module"
```

### 11. Write Module Feature.json

```
// Write analysis section with ALL subsections
ba-writer.enrichSection({
  featureId: {module_feature_id},
  section: "analysis",
  data: {
    objectives: [{id, objective, metric, target}],       // from 6a
    entities: [{name, description, attributes, relationships}],  // from 6b — SCHEMA FORMAT
    businessRules: [{id, name, category, statement, priority, conditions, examples, testability}],  // from 7 — SCHEMA FORMAT
    processFlow: {entryPoints, mainFlow, decisionPoints, alternativeFlows},  // from 6c
    dataLifecycle: {retentionPeriod, archiveStrategy, gdprCompliance, states}  // from 6d
  }
})

// Write specification section with ALL subsections
ba-writer.enrichSection({
  featureId: {module_feature_id},
  section: "specification",
  data: {
    actors: [{role, description, permissions}],                   // 8a
    useCases: [{id, name, primaryActor, permission, mainScenario, linkedRules}],  // 8b
    functionalRequirements: [{id, statement, priority, linkedRules, linkedUseCases, acceptanceCriteria}],  // 8c
    permissionMatrix: {permissions: [], roleAssignments: []},     // 8d
    navigation: {entries: []},                                    // 8e
    seedDataCore: {navigationModules, navigationTranslations, permissions, rolePermissions, permissionConstants},  // 8f
    gherkinScenarios: [{feature, scenarios: [{name, tags, given, when, then}]}],  // 8g
    validations: [{entity, field, rules, errorMessageKey}],       // 8h
    messages: [{code, type, title, message, i18nKey}],            // 8i
    lifeCycles: [{entity, field, initialState, states: [{id, displayName, color, allowedTransitions, isTerminal}], transitions}],  // 8j
    apiEndpoints: [{method, path, permission, requestDto, responseDto, description}],  // 8k
    i18nKeys: {...},                                              // 8l
    sections: [{code, labels, route, icon, permission, wireframe, useCases, businessRules, resources}],  // from 3a-bis
    dashboards: [{code, title, kpis, filters, refreshMode}],     // from 3d
    uiWireframes: [{screen, section, mockup, elements, actions, componentMapping, layout}]  // from 3b
  }
})

// Write validation results from step 9
// (Already written in step 9e above)

ba-writer.updateStatus({module_feature_id}, "specified")

// Update master
ba-writer.updateModuleStatus({feature_id}, {currentModule.code}, "specified")
```

### 12. Loop Decision

```
ba-writer.advanceModuleLoop({feature_id})
→ Increments currentModuleIndex
→ Updates completedModules
→ Updates currentModule

IF currentModuleIndex < moduleOrder.length:
  Display: "→ Module suivant: {nextModule} ({currentModuleIndex + 1}/{total})"
  Load: steps/step-03-specify.md (RE-ENTER this step)

IF currentModuleIndex >= moduleOrder.length:
  Display: "═══ Tous les modules spécifiés! Passage à la consolidation... ═══"
  ba-writer.updateStatus({feature_id}, "specified")
  Load: steps/step-04-consolidation.md
```

---

## SINGLE-MODULE MODE

When only 1 module in moduleOrder:

- Same full specification flow
- Skip cross-module references (section 5)
- After validation → direct to step-04-consolidation.md (auto-consolidation)

---

## RESUME SUPPORT

IF the step is resumed (e.g., after interruption):

```
Read metadata.workflow.currentModuleIndex
Read metadata.workflow.currentModule
→ Resume at the correct module
→ If module has partial data, show what exists and continue from there
```

---

## CONTEXT MANAGEMENT

| Loaded | Not Loaded |
|--------|------------|
| _shared.md | Other module feature.json (full) |
| feature-schema.json | Questionnaires not needed |
| Questionnaires for this module | Templates |
| Completed modules summary (100 lines max) | React viewer files |

---

## STATE VARIABLES

| Variable | Description |
|----------|-------------|
| `{currentModule}` | Current module being specified |
| `{currentModuleIndex}` | Index in moduleOrder |
| `{completedModules}` | Array of already specified module codes |
| `{module_feature_id}` | Feature ID for the module-level feature.json |

---

## SUCCESS METRICS

- All sections walked through with client
- ASCII mockups generated and validated for EVERY section (1 wireframe per section minimum)
- Entities defined with business attributes
- Business rules extracted and categorized
- Per-module validation PASS
- Client confirmed module specification
- Module feature.json written
- Master updated with module status
- Loop advanced correctly

## FAILURE MODES

- Validation FAIL → offer auto-correct / manual revise / force
- Client rejects → revise specific sections
- Cross-module reference error → clarify with client
- Interruption → resumable via workflow state

---

## NEXT STEP

Conditional:

- IF modules remaining → Re-load `./step-03-specify.md`
- IF all modules done → Load `./step-04-consolidation.md`
