# FEATURE_DATA & EMBEDDED_ARTIFACTS Build Reference

> Reference for step-05b-deploy.md — complete mapping specification for the interactive HTML.

## FEATURE_DATA Object

```javascript
const FEATURE_DATA = {
  metadata: {
    applicationName: master.application_name,
    applicationId: master.feature_id,
    version: master.version,
    createdAt: ISO_TIMESTAMP,
    analysisMode: master.metadata.analysisMode || "interactive" // always "interactive" — analysis is always interactive
  },
  cadrage: {
    goal: master.cadrage.goal,
    vision: master.cadrage.vision,
    success_criteria: master.cadrage.success_criteria,
    scope: {
      // CONVERT feature.json keys to HTML keys:
      // mustHave → vital, shouldHave → important, couldHave → optional, outOfScope → excluded
      vital: master.globalScope.mustHave || [],
      important: master.globalScope.shouldHave || [],
      optional: master.globalScope.couldHave || [],
      excluded: master.globalScope.outOfScope || []
    },
    constraints: master.cadrage.constraints || [],
    risks: master.cadrage.risks || [],
    stakeholders: master.stakeholders || []
  },
  modules: [
    {
      moduleCode: module.code,
      moduleName: module.name,
      moduleDescription: module.description || "",
      // ... per-module fields from feature.json
    }
  ],
  moduleSpecs: {
    // CRITICAL: Must have ONE entry per module with ALL module data
    "{moduleCode}": {
      useCases: module.specification.useCases || [],
      businessRules: module.analysis.businessRules || [],
      // ENTITY SAFETY NET: map fields[] → attributes[] if agent deviated from canonical format
      entities: (module.analysis.entities || []).map(ent => ({
        name: ent.name,
        description: ent.description || "",
        attributes: (ent.attributes || []).length > 0
          ? ent.attributes.map(a => ({ name: a.name, description: a.description || "" }))
          : (ent.fields || []).map(f => ({ name: f.name, description: f.description || f.type || "" })),
        relationships: (ent.relationships || []).length > 0
          ? ent.relationships.map(r =>
              typeof r === 'string' ? r : `${r.target} (${r.type}) - ${r.description || ""}`)
          : (ent.fields || []).filter(f => f.foreignKey)
              .map(f => `${f.foreignKey.table} (N:1) - ${f.description || f.name}`)
      })),
      permissions: module.specification.permissions || [],
      apiEndpoints: module.specification.apiEndpoints || []
    }
  },
  consolidation: {
    integrations: master.consolidation.integrations || [],
    sharedEntities: master.consolidation.sharedEntities || [],
    sequenceDiagrams: master.consolidation.e2eFlows || []
  },
  handoff: {
    complexity: master.handoff.complexity,
    implementationStrategy: master.handoff.implementationStrategy,
    moduleOrder: master.handoff.moduleOrder,
    filesToCreate: master.handoff.filesToCreate,
    brToCodeMapping: master.handoff.brToCodeMapping,
    apiEndpointSummary: master.handoff.apiEndpointSummary
  }
};
```

### Build Process

1. Extract metadata from master feature.json
2. Extract cadrage from master feature.json (CONVERT scope keys)
3. Extract stakeholders from master.stakeholders
4. Iterate ALL modules and populate moduleSpecs (THIS IS CRITICAL — empty moduleSpecs = BUG)
5. For EACH module, extract: useCases, businessRules, entities, permissions, apiEndpoints
6. Extract consolidation data (integrations, shared entities, E2E flows)
7. Extract handoff section (complexity, strategy, module order, file counts)

## EMBEDDED_ARTIFACTS Object

> **CRITICAL:** The wireframes object is keyed by moduleCode (NOT a flat array).
> Field names MUST be renamed from feature.json: `mockupFormat` → `format`, `mockup` → `content`.
> The HTML renderer reads `wf.format` and `wf.content` — using feature.json names will produce EMPTY mockups.

```javascript
const EMBEDDED_ARTIFACTS = {
  wireframes: {
    // PER-MODULE keyed object (NOT a flat array)
    // FOR EACH module: extract from specification.uiWireframes[]
    [moduleCode]: moduleFeature.specification.uiWireframes.map(wf => ({
      screen: wf.screen || wf.name || wf.id || "",  // SAFETY NET: fallback name/id → screen
      section: wf.section || "",                      // e.g. "list"
      format: wf.mockupFormat || "ascii",             // RENAME: mockupFormat → format
      content: wf.mockup,                             // RENAME: mockup → content (ASCII art string)
      description: wf.description || "",
      elements: wf.elements || [],                    // [{ id, type, label }] or ["DataGrid", ...]
      actions: wf.actions || [],                      // [{ trigger, action }] or ["filter", ...]
      // SAFETY NET: convert object → array format if agent used { "Header": "PageHeader" } instead of [{ wireframeElement, reactComponent }]
      componentMapping: Array.isArray(wf.componentMapping) ? wf.componentMapping
        : typeof wf.componentMapping === 'object' && wf.componentMapping !== null
          ? Object.entries(wf.componentMapping).map(([k, v]) => ({ wireframeElement: k, reactComponent: v }))
          : [],
      layout: typeof wf.layout === 'object' ? wf.layout : null,  // SAFETY NET: ignore string layout ("grid")
      permissionsRequired: wf.permissionsRequired || []
    }))
  },
  e2eFlows: (master.consolidation?.e2eFlows || []).map(flow => ({
    name: flow.name,
    diagram: flow.steps.map(s => `${s.action}(${s.module})`).join(" ──→ "),
    steps: flow.steps || [],
    actors: [...new Set(flow.steps.map(s => s.permission?.split(".")[0]).filter(Boolean))].join(", "),
    modules: [...new Set(flow.steps.map(s => s.module))].join(" → ")
  })),
  dependencyGraph: {
    nodes: (master.modules || []).map(m => ({
      id: m.code, label: m.code, type: m.featureType || "data-centric"
    })),
    edges: (master.dependencyGraph?.edges || []).map(e => ({
      from: e.from, to: e.to, description: e.description || ""
    }))
  }
};
```

### Artifact Gathering

1. For EACH module: read `specification.uiWireframes[]`, **rename fields** (`mockupFormat`→`format`, `mockup`→`content`), store under `wireframes[moduleCode]`
2. Read master's `consolidation.e2eFlows[]` and build e2eFlows array with diagram generation
3. Read master's `dependencyGraph` and build nodes/edges
4. Serialize as JSON with 2-space indentation

## Placeholder Replacement

1. Serialize FEATURE_DATA as JSON (2-space indent)
2. Serialize EMBEDDED_ARTIFACTS as JSON (2-space indent)
3. Replace `{{FEATURE_DATA}}` with serialized FEATURE_DATA
4. Replace `{{EMBEDDED_ARTIFACTS}}` with serialized EMBEDDED_ARTIFACTS
5. Replace `{{APPLICATION_NAME}}`, `{{APPLICATION_ID}}`, `{{VERSION}}`, `{{CREATED_AT}}`
6. Verify: grep for `{{` to confirm all placeholders replaced
