---
name: step-05b-deploy
description: Generate prd.json, deploy artifacts, interactive HTML
model: sonnet
next_step: steps/step-05c-ralph-readiness.md
---

> **Context files:** _shared.md

# Step 5b: Deploy Artifacts & Interactive HTML

## MANDATORY EXECUTION RULES

- **ALWAYS** verify all module handoffs are complete before generating artifacts
- **ALWAYS** derive prd.json from feature.json (NEVER independently)
- **NEVER** invent entities/FRs/BRs not in feature.json
- **ALWAYS** update BA manifest at docs/index.json
- **ALWAYS** deploy ba-interactive.html PRE-POPULATED with all data
- **ALWAYS** follow references/html-data-mapping.md EXACTLY for FEATURE_DATA and EMBEDDED_ARTIFACTS mapping
- **FEATURE_DATA.moduleSpecs MUST be populated for EACH module** — empty moduleSpecs = BROKEN specification tabs
- **FEATURE_DATA.cadrage.scope must use HTML keys** (vital/important/optional/excluded) NOT feature.json keys (mustHave/shouldHave/couldHave/outOfScope)
- **FEATURE_DATA.metadata.analysisMode must be set** from master.metadata.analysisMode (always "interactive")
- **NEVER leave FEATURE_DATA or EMBEDDED_ARTIFACTS empty or partial**

## YOUR TASK

Generate deployment artifacts (prd.json, progress.txt, BA manifest) and deploy the interactive HTML document pre-populated with all analysis data.

---

## EXECUTION SEQUENCE

### 0. Pre-flight Verification

Before generating ANY artifact, verify step-05a completed successfully:

```
FOR each module in modules[]:
  Read module feature.json
  IF module.handoff === {} OR module.status !== "handed-off":
    → BLOCKING ERROR: Module {module.code} has no handoff data
    → Return to step-05a-handoff.md
```

IF all modules have valid handoff → proceed.

---

### 1. Generate prd.json (PROGRAMMATIC)

> **RULE:** prd.json is extracted by CLI code, **NEVER** generated by LLM.
> The `ss derive-prd` command performs a deterministic data transformation from feature.json.

**For each module:**

```
Execute: ss derive-prd --feature {moduleFeaturePath} --output .ralph/prd-{moduleCode}.json
```

**For consolidated view (multi-module, optional):**

```
Execute: ss derive-prd --application {masterFeaturePath}
→ Generates .ralph/prd-{moduleCode}.json for each module
```

**Verification:** After execution, read the generated prd.json and display summary:

```
prd.json generated for module {moduleCode}:
  - Use cases: {count}
  - Functional requirements: {count}
  - Business rules: {count}
  - API endpoints: {count}
  - Sections: {count}
  - Files to create: {count}
  - BR-to-code mappings: {count}
```

**Key guarantees:**
- Source MUST reference feature.json path (traceability)
- All data is EXACT COPY from feature.json (no transformation, no invention)
- prd.json $version: "3.0.0" (unified format with pre-computed tasks)
- source.type: "ba-handoff-programmatic"

**POST-CHECK (BLOCKING — DO NOT SKIP):**

After `ss derive-prd` execution, read the generated prd-{moduleCode}.json and verify structural integrity:

```javascript
const prd = readJSON(`.ralph/prd-${moduleCode}.json`);
const featureHandoff = moduleFeature.handoff.filesToCreate;

// 1. Verify structure: filesToCreate MUST be under implementation (NOT root level)
if (prd.filesToCreate && !prd.implementation?.filesToCreate) {
  BLOCKING_ERROR("prd.json has filesToCreate at ROOT level — this is NOT from ss derive-prd");
  BLOCKING_ERROR("Re-run: ss derive-prd --feature {path} --output .ralph/prd-{moduleCode}.json");
  STOP;
}

// 2. Verify ALL 7 categories present and match feature.json
const categories = ['domain', 'application', 'infrastructure', 'api', 'frontend', 'seedData', 'tests'];
for (const cat of categories) {
  const prdCount = prd.implementation.filesToCreate[cat]?.length ?? 0;
  const featureCount = featureHandoff[cat]?.length ?? 0;
  if (prdCount !== featureCount) {
    BLOCKING_ERROR(`${cat}: prd has ${prdCount} files but feature.json has ${featureCount}`);
  }
}
```

Display verification table:

```
POST-CHECK: prd-{moduleCode}.json integrity
| Category       | feature.json | prd.json | Match |
|----------------|-------------|----------|-------|
| domain         | {n}         | {n}      | OK/FAIL |
| application    | {n}         | {n}      | OK/FAIL |
| infrastructure | {n}         | {n}      | OK/FAIL |
| api            | {n}         | {n}      | OK/FAIL |
| frontend       | {n}         | {n}      | OK/FAIL |
| seedData       | {n}         | {n}      | OK/FAIL |
| tests          | {n}         | {n}      | OK/FAIL |
```

IF ANY category shows FAIL → **STOP AND RE-RUN `ss derive-prd`**. DO NOT proceed with incomplete PRD.

---

### 2. Initialize Progress Tracker

> **Template:** Read `templates/tpl-progress.md` for the complete progress tracker template structure.
> Populate the template with module-specific data from feature.json handoff sections.

**Progress Tracker Rules:**
- One section per module, in topological order (dependencies first)
- CORE SeedData ALWAYS 5 entries (mandatory)
- Business SeedData varies by module
- Hierarchical task structure (module -> layer -> tasks)
- Each task is independent, assignable checkbox
- Effort estimate per module (simple/medium/complex)
- Summary with totals across all modules
- Cross-module tasks only if multi-module

---

### 3. Update BA Manifest (MANDATORY)

> **The BA manifest enables the SmartStack web app to discover and display all available business analyses.**
> It is a JSON index file at `docs/index.json` that lists all feature.json files.

**Path:** `docs/index.json` (project root relative)

**Schema:**
```json
{
  "version": "1.0",
  "updatedAt": "{ISO timestamp}",
  "analyses": [
    {
      "appCode": "{app_code}",
      "appName": "{application_name}",
      "moduleCode": null | "{module_code}",
      "moduleName": "{module_name}",
      "version": "{version}",
      "status": "handed-off",
      "featureDescription": "{feature_description}",
      "path": "{app_code}/business-analyse/v{version}/feature.json",
      "updatedAt": "{ISO timestamp}"
    }
  ]
}
```

> Note: The "path" field uses `{app_code}` directly without any prefix (e.g., `FreeBike/business-analyse/v1.0/feature.json`).

**Update logic:**

1. Read existing manifest at `docs/index.json` (or create empty `{ "version": "1.0", "updatedAt": "", "analyses": [] }`)

2. **PROJECT MODE (`workflow.mode === "project"`):**
   a. Add/update PROJECT-level entry:
      - Find existing entry where `projectId == {project_id}` AND `scope == "project"`
      - If found: update `status`, `updatedAt`
      - If not found: append new entry with `scope: "project"`, `projectId: "{project_id}"`, `path: "business-analyse/v{version}/feature.json"`
   b. For EACH APPLICATION:
      - Find existing entry where `appCode == {app_code}` AND `moduleCode == null` AND `version == {version}`
      - If found: update `status`, `updatedAt`, `featureDescription`
      - If not found: append new entry with `moduleCode: null` and `path: "{app_code}/business-analyse/v{version}/feature.json"`
   c. For EACH MODULE within each application:
      - Find existing entry where `appCode == {app_code}` AND `moduleCode == {module_code}` AND `version == {version}`
      - If found: update `status`, `updatedAt`, `featureDescription`
      - If not found: append new entry with `path: "{app_code}/{module_code}/business-analyse/v{version}/feature.json"`

3. **SINGLE-APP MODE (default):**
   a. For the APPLICATION-level feature.json:
      - Find existing entry where `appCode == {app_code}` AND `moduleCode == null` AND `version == {version}`
      - If found: update `status`, `updatedAt`, `featureDescription`
      - If not found: append new entry with `moduleCode: null` and `path: "{app_code}/business-analyse/v{version}/feature.json"`
   b. For EACH MODULE-level feature.json:
      - Find existing entry where `appCode == {app_code}` AND `moduleCode == {module_code}` AND `version == {version}`
      - If found: update `status`, `updatedAt`, `featureDescription`
      - If not found: append new entry with `moduleCode: "{module_code}"` and `path: "{app_code}/{module_code}/business-analyse/v{version}/feature.json"`

4. Update root `updatedAt` to current timestamp
5. Write manifest back to `docs/index.json`

**Display confirmation:**
```
✓ BA manifest updated: docs/index.json
  Entries: {total_count} ({project_count} projects, {app_count} applications, {module_count} modules)
  Web viewer: /system/docs/ba
```

**Why a manifest?**
- The web app needs to discover available BAs without scanning the filesystem
- Static file serving (no backend API needed)
- Incremental updates: each handoff adds/updates only its entries
- Consumed by the SmartStack web app BA viewer at `/system/docs/ba`

---

### 4. Read Source Data for HTML

1. Read the HTML template from skill directory: `html/ba-interactive.html` (relative to `~/.claude/skills/business-analyse/`)
2. **SINGLE-APP MODE:** Read the master feature.json (application level)
3. **PROJECT MODE:** Read the project feature.json + ALL application feature.json files
4. Read EACH module feature.json (module level, across all applications in project mode)

> **Reference:** Read `references/html-data-mapping.md` for the complete FEATURE_DATA and EMBEDDED_ARTIFACTS mapping specification.

**Key requirements:**
- FEATURE_DATA must be pre-populated with ALL analysis data (empty data = BUG)
- FEATURE_DATA.**moduleSpecs** MUST be populated for EACH module across ALL applications (use cases, business rules, entities, permissions) — empty moduleSpecs = BROKEN specification tabs
- FEATURE_DATA.**cadrage.scope** must use HTML keys (vital/important/optional/excluded) NOT feature.json keys (mustHave/shouldHave/couldHave/outOfScope)
- FEATURE_DATA.**metadata.analysisMode** must be set from `master.metadata.analysisMode` (always "interactive")
- EMBEDDED_ARTIFACTS contains wireframes, E2E diagrams, dependency graph
- Both objects are serialized as JSON with 2-space indentation
- All data mapped from master and module feature.json files — follow `html-data-mapping.md` EXACTLY

**PROJECT MODE additions to FEATURE_DATA:**
- `FEATURE_DATA.project` — project-level metadata (name, applicationCount, applicationOrder)
- `FEATURE_DATA.applications` — array of application summaries with their modules
- `FEATURE_DATA.modules` — flattened list of ALL modules across ALL applications (each with `applicationCode` field)
- `FEATURE_DATA.consolidation.crossApplicationInteractions` — from project feature.json
- FEATURE_DATA.**metadata.workflowMode** must be `"project"` (enables multi-app tabs in HTML)

---

### 5-7. Build FEATURE_DATA, EMBEDDED_ARTIFACTS & Replace Placeholders

See [references/deploy-data-build.md](../references/deploy-data-build.md) for:
- Complete FEATURE_DATA object structure (metadata, cadrage, modules, moduleSpecs, consolidation, handoff)
- Complete EMBEDDED_ARTIFACTS object structure (wireframes, e2eFlows, dependencyGraph)
- 7-step build process for FEATURE_DATA
- 4-step artifact gathering for EMBEDDED_ARTIFACTS
- Placeholder replacement rules (8 placeholders)

**Critical reminders:**
- FEATURE_DATA.**moduleSpecs** MUST have ONE entry per module (empty = BUG)
- FEATURE_DATA.**cadrage.scope** converts `mustHave→vital`, `shouldHave→important`, `couldHave→optional`, `outOfScope→excluded`
- FEATURE_DATA.**metadata.analysisMode** from `master.metadata.analysisMode`
- Also reference `references/html-data-mapping.md` for the full mapping spec

---

### 7-bis. Generate SVG Wireframes (Parallel Enrichment)

> **After EMBEDDED_ARTIFACTS is built (sections 5-7) but BEFORE writing the HTML (section 8).**
> This step enriches each ASCII wireframe with a professional SVG version for dual-view rendering.

See [references/wireframe-svg-style-guide.md](../references/wireframe-svg-style-guide.md) for the complete SVG style specification, prompt template, and orchestration process.

**Process summary:**

1. **Read** `references/wireframe-svg-style-guide.md` to get the prompt template
2. **Collect** all wireframes across ALL modules in `EMBEDDED_ARTIFACTS.wireframes` where `content` exists and `svgContent` is null
3. **Spawn parallel Task(sonnet) agents** — ONE per wireframe, ALL in a single message
4. **Collect and validate** results: strip markdown fences if present, verify SVG starts with `<svg` and contains `</svg>`
5. **Inject** valid SVGs into `EMBEDDED_ARTIFACTS.wireframes[moduleCode][index].svgContent`
6. **Display summary:**
   ```
   SVG wireframe generation:
     Total wireframes: {total}
     SVG generated: {successCount}/{total}
     Fallback (ASCII only): {failCount}/{total}
   ```

> **CRITICAL:** This step is NEVER blocking. If all SVG generations fail, deployment
> continues with ASCII-only wireframes. The HTML renderer checks for `svgContent` before
> showing the SVG view. SVG is an enhancement, not a requirement.

---

### 8. Write and Verify

1. Write the populated HTML to the output directory: `docs/{app}/business-analyse/v{version}/ba-interactive.html`
2. Display deployment confirmation:

```
[OK] Interactive HTML deployed:
  Path: docs/{app}/business-analyse/v{version}/ba-interactive.html
  Pre-populated with: {stakeholder_count} stakeholders, {module_count} modules,
    {total_uc} use cases, {total_br} business rules, {total_entity} entities
  Visual artifacts: {total_wireframes} wireframes, {e2e_flow_count} E2E diagrams
  Open in browser to review and edit the business analysis.
  Export JSON and re-import with: /business-analyse -x <exported-json-path>
```

---

## SELF-VERIFICATION (BEFORE COMPLETION)

Before displaying completion, VERIFY:

1. **`.ralph/prd-{module}.json`** exists for ALL modules (file size > 100 bytes each)
2. **`.ralph/progress.txt`** exists (file size > 500 bytes)
3. **`docs/index.json`** exists with correct entry count
4. **ba-interactive.html** exists and file size > 100KB
5. **FEATURE_DATA contains moduleSpecs** with entries for ALL modules
6. **cadrage.scope uses HTML keys** (vital/important/optional/excluded)

**IF any check fails → GENERATE the missing artifact before proceeding to completion.**

---

## POST-CHECK (BLOCKING)

After writing the HTML file, verify:

1. **File size > 100KB** (indicates pre-populated, not empty template)
   ```bash
   file_size=$(stat --format=%s "{output_path}/ba-interactive.html")
   if [ $file_size -lt 100000 ]; then
     BLOCKING_ERROR("ba-interactive.html is only ${file_size} bytes — not pre-populated")
   fi
   ```

2. **Grep for "moduleSpecs"** — MUST be present in generated HTML
   ```bash
   if ! grep -q '"moduleSpecs"' "{output_path}/ba-interactive.html"; then
     BLOCKING_ERROR("moduleSpecs not found in HTML — FEATURE_DATA not serialized correctly")
   fi
   ```

3. **moduleSpecs must have entries for ALL modules** (not empty object `{}`)
   ```bash
   # Count moduleSpecs entries — should equal module count
   moduleSpec_count=$(grep -o '"moduleCode"' "{output_path}/ba-interactive.html" | wc -l)
   if [ $moduleSpec_count -lt {module_count} ]; then
     BLOCKING_ERROR("moduleSpecs has only ${moduleSpec_count} entries but need {module_count}")
   fi
   ```

4. **cadrage.scope must use HTML keys** (vital/important/optional/excluded)
   ```bash
   if grep -q '"mustHave"' "{output_path}/ba-interactive.html"; then
     BLOCKING_ERROR("cadrage.scope still has feature.json keys (mustHave) — must convert to HTML keys (vital)")
   fi
   ```

5. **EMBEDDED_ARTIFACTS wireframes must use renamed fields** (`format`/`content`, NOT `mockupFormat`/`mockup`)
   ```bash
   # Check that wireframe field rename was applied (mockup → content, mockupFormat → format)
   if grep -q '"mockupFormat"' "{output_path}/ba-interactive.html"; then
     BLOCKING_ERROR("EMBEDDED_ARTIFACTS wireframes still use 'mockupFormat' — must rename to 'format'")
     BLOCKING_ERROR("See references/html-data-mapping.md for correct field mapping")
   fi
   if grep -q '"mockup":' "{output_path}/ba-interactive.html" | grep -v '"mockupNotes"'; then
     # Note: "mockup" in EMBEDDED_ARTIFACTS = wrong, must be "content"
     BLOCKING_ERROR("EMBEDDED_ARTIFACTS wireframes still use 'mockup' — must rename to 'content'")
   fi
   ```

6. **EMBEDDED_ARTIFACTS wireframes must exist for ALL modules** (not empty `{}`)
   ```bash
   # Each module should have at least one wireframe with "format" and "content"
   if ! grep -q '"format"' "{output_path}/ba-interactive.html"; then
     BLOCKING_ERROR("No wireframe 'format' field found — EMBEDDED_ARTIFACTS wireframes not populated")
   fi
   ```

7. **WIREFRAME KEY ALIGNMENT** — wireframe keys MUST match module codes exactly
   ```
   FOR each module in FEATURE_DATA.modules:
     moduleCode = module.code  (e.g., "GestionTemps")
     IF EMBEDDED_ARTIFACTS.wireframes[moduleCode] is undefined OR empty:
       BLOCKING_ERROR("Wireframe key mismatch: module code '${moduleCode}' not found in EMBEDDED_ARTIFACTS.wireframes")
       BLOCKING_ERROR("Available wireframe keys: ${Object.keys(EMBEDDED_ARTIFACTS.wireframes).join(', ')}")
       → FIX: Rename the wireframe key to match module.code exactly
   ```
   > **Why this matters:** The HTML renders wireframes via `EMBEDDED_ARTIFACTS.wireframes[code]`. If the key doesn't match the module code (e.g., "TimeTracking" vs "GestionTemps"), the wireframes tab shows "Aucune maquette disponible" even though data exists.

8. **MODULE COMPLETENESS** — every module must have spec data AND wireframes in HTML
   ```
   FOR each module in master.modules[]:
     IF FEATURE_DATA.moduleSpecs[module.code] is undefined:
       BLOCKING_ERROR("Module '${module.code}' missing from FEATURE_DATA.moduleSpecs")
     IF EMBEDDED_ARTIFACTS.wireframes[module.code] is undefined:
       BLOCKING_ERROR("Module '${module.code}' missing from EMBEDDED_ARTIFACTS.wireframes")
     IF module.featureJsonPath is null:
       BLOCKING_ERROR("Module '${module.code}' has no per-module feature.json (featureJsonPath is null)")

   expectedModules = master.modules.map(m => m.code).sort()
   specModules = Object.keys(FEATURE_DATA.moduleSpecs).sort()
   wireframeModules = Object.keys(EMBEDDED_ARTIFACTS.wireframes).sort()

   IF expectedModules.join(',') !== specModules.join(','):
     BLOCKING_ERROR("Module mismatch: expected [${expectedModules}] but moduleSpecs has [${specModules}]")
   IF expectedModules.join(',') !== wireframeModules.join(','):
     BLOCKING_ERROR("Module mismatch: expected [${expectedModules}] but wireframes has [${wireframeModules}]")
   ```

9. **MODULE DATA COMPLETENESS** — every module in FEATURE_DATA.modules[] must carry ALL fields from feature.json
   ```
   FOR each htmlModule in FEATURE_DATA.modules[]:
     masterModule = master.modules.find(m => m.code === htmlModule.code)

     // name MUST be display name, NOT code
     IF htmlModule.name === htmlModule.code AND masterModule.name !== masterModule.code:
       BLOCKING_ERROR("Module '${htmlModule.code}' has name === code. Expected: '${masterModule.name}'")

     // anticipatedSections MUST be present (drives Structure tab + navigation tree)
     IF masterModule.anticipatedSections?.length > 0 AND (!htmlModule.anticipatedSections OR htmlModule.anticipatedSections.length === 0):
       BLOCKING_ERROR("Module '${htmlModule.code}' lost anticipatedSections: master has ${masterModule.anticipatedSections.length}, HTML has 0")
       → FIX: Copy anticipatedSections from master.modules[].anticipatedSections

     // dependencies/dependents MUST be present (drives dependency graph)
     IF masterModule.dependencies?.length > 0 AND (!htmlModule.dependencies OR htmlModule.dependencies.length === 0):
       BLOCKING_ERROR("Module '${htmlModule.code}' lost dependencies array")
   ```

   Display verification table:
   ```
   POST-CHECK: Module data completeness
   | Module         | name    | sections | deps | wireframes | specs | Match |
   |----------------|---------|----------|------|------------|-------|-------|
   | {code}         | {name}  | {n}      | {n}  | {n}        | OK    | OK/FAIL |
   ```

**IF ANY CHECK FAILS → DO NOT PROCEED. Fix the data mapping and regenerate.**

---

## COMPLETION

> **IMPORTANT:** La BA ne lance JAMAIS /ralph-loop automatiquement.
> Il peut y avoir une phase de revue/modification de la documentation entre les deux étapes.
> L'utilisateur lance `/ralph-loop` manuellement quand il est prêt.

Display completion using the template from `templates/tpl-launch-displays.md`:

```
═══════════════════════════════════════════════════════════════
  [OK] BUSINESS ANALYSE TERMINEE - {application_name OR project_name}
═══════════════════════════════════════════════════════════════

{IF workflow.mode === "project":}
Project:   {project_name}
Apps:      {app_count} ({app_names})
{ENDIF}
Modules:   {count} ({names})
Strategy:  {strategy}
Files:     {total files across all modules}
Tasks:     {total tasks} ({core_count} CORE + {biz_count} business + {dev_count} development)
Complexity: {complexity}
Effort:    {total_days} days ({total_hours} hours)

[DIR] Artefacts générés:
  ✓ feature.json ({IF project: "project + " ENDIF}master + per-module) - spécification complète
  ✓ .ralph/prd-{module}.json - task breakdown per module
  {IF workflow.mode === "project":}
  ✓ .ralph/prd-CrossApplication.json - cross-application integration tests
  {ENDIF}
  ✓ .ralph/progress.txt - tracker de progression
  ✓ ba-interactive.html - document de revue interactif

[TARGET] Prochaines étapes:
  1. Ouvrir ba-interactive.html dans le navigateur
  2. Partager avec les stakeholders pour validation
  3. Si retours --> relancer /business-analyse pour une nouvelle itération
  4. Validation qualité ULTRATHINK (automatique):

     → Lancement automatique de step-05c-ralph-readiness.md...

  5. Une fois validé, lancer le développement:

     /ralph-loop

     Note: /ralph-loop -r sert UNIQUEMENT à reprendre une boucle interrompue.
           Après un /business-analyse, toujours utiliser /ralph-loop (sans -r).

═══════════════════════════════════════════════════════════════
```

---

## NEXT STEP

**MANDATORY:** Load `steps/step-05c-ralph-readiness.md` — ULTRATHINK quality review & readiness gate.

> **This step is NON-NEGOTIABLE.** The BA skill MUST run step-05c before completing.
> DO NOT skip this step. DO NOT display a "done" message without running step-05c first.

This validation ensures:
- ULTRATHINK deep quality review of the entire BA output
- All module handoffs are complete and content is coherent
- PRD files are structurally valid
- Cross-module references are resolvable
- Specification quality meets production standards
- No blocking issues before development

---

## MODE SUPPORT & TROUBLESHOOTING

See [references/deploy-modes.md](../references/deploy-modes.md) for:
- **Standard Mode** — full handoff (all 7 categories, complete mapping)
- **Micro Mode** — simplified CRUD (3 core SeedData, lightweight)
- **Delta Mode** — refactoring focus (affected modules only)
- **Troubleshooting** — 12 common issues with resolutions
