@atlashub/smartstack-cli 4.74.0 → 4.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/dist/index.js +152 -31
  2. package/dist/index.js.map +1 -1
  3. package/dist/mcp-entry.mjs +14 -3
  4. package/dist/mcp-entry.mjs.map +1 -1
  5. package/package.json +1 -1
  6. package/templates/agents/ba-reader.md +17 -15
  7. package/templates/agents/ba-writer.md +49 -51
  8. package/templates/skills/apex/SKILL.md +2 -2
  9. package/templates/skills/apex/_shared.md +1 -1
  10. package/templates/skills/apex/references/checks/backend-checks.sh +21 -7
  11. package/templates/skills/apex/references/checks/frontend-checks.sh +26 -0
  12. package/templates/skills/apex/references/checks/infrastructure-checks.sh +47 -10
  13. package/templates/skills/apex/references/checks/seed-checks.sh +47 -7
  14. package/templates/skills/apex/references/core-seed-data.md +20 -18
  15. package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +3 -0
  16. package/templates/skills/apex/references/post-checks.md +23 -3
  17. package/templates/skills/apex/references/smartstack-api.md +4 -4
  18. package/templates/skills/apex/references/smartstack-frontend.md +54 -8
  19. package/templates/skills/apex/references/smartstack-layers.md +6 -6
  20. package/templates/skills/apex/steps/step-00-init.md +75 -1
  21. package/templates/skills/apex/steps/step-03-execute.md +16 -4
  22. package/templates/skills/apex/steps/step-03b-layer1-seed.md +65 -6
  23. package/templates/skills/apex/steps/step-03c-layer2-backend.md +50 -5
  24. package/templates/skills/apex/steps/step-03d-layer3-frontend.md +226 -4
  25. package/templates/skills/apex/steps/step-04-examine.md +163 -0
  26. package/templates/skills/apex-verify/SKILL.md +110 -0
  27. package/templates/skills/apex-verify/references/audit-rules.md +50 -0
  28. package/templates/skills/apex-verify/steps/step-00-init.md +119 -0
  29. package/templates/skills/apex-verify/steps/step-01-nav-audit.md +92 -0
  30. package/templates/skills/apex-verify/steps/step-02-crud-audit.md +127 -0
  31. package/templates/skills/apex-verify/steps/step-03-perm-audit.md +119 -0
  32. package/templates/skills/apex-verify/steps/step-04-route-audit.md +98 -0
  33. package/templates/skills/apex-verify/steps/step-05-report.md +110 -0
  34. package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +3 -0
  35. package/templates/skills/application/templates-frontend.md +2 -2
  36. package/templates/skills/business-analyse/SKILL.md +17 -3
  37. package/templates/skills/business-analyse/_shared.md +64 -0
  38. package/templates/skills/business-analyse/patterns/suggestion-catalog.md +34 -26
  39. package/templates/skills/business-analyse/questionnaire/01-context.md +13 -9
  40. package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +20 -27
  41. package/templates/skills/business-analyse/questionnaire.md +86 -9
  42. package/templates/skills/business-analyse/references/03-json-schemas.md +221 -0
  43. package/templates/skills/business-analyse/references/03-post-check-validation.md +208 -0
  44. package/templates/skills/business-analyse/references/03-smartstack-entity-guards.md +32 -0
  45. package/templates/skills/business-analyse/references/04-cross-module-validation.md +95 -0
  46. package/templates/skills/business-analyse/references/04-file-allocation.md +162 -0
  47. package/templates/skills/business-analyse/references/04-naming-audit-checks.md +174 -0
  48. package/templates/skills/business-analyse/references/04-semantic-validation-matrix.md +118 -0
  49. package/templates/skills/business-analyse/references/canonical-json-formats.md +7 -3
  50. package/templates/skills/business-analyse/references/domain-research-playbook.md +234 -0
  51. package/templates/skills/business-analyse/references/entity-sourcing-presentation.md +166 -0
  52. package/templates/skills/business-analyse/references/init-resume-logic.md +70 -0
  53. package/templates/skills/business-analyse/references/module-completeness-challenge.md +174 -0
  54. package/templates/skills/business-analyse/references/multi-app-detection.md +149 -0
  55. package/templates/skills/business-analyse/references/portal-classification.md +52 -0
  56. package/templates/skills/business-analyse/references/robustness-checks.md +1 -1
  57. package/templates/skills/business-analyse/references/validation-checklist.md +35 -6
  58. package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +50 -6
  59. package/templates/skills/business-analyse/steps/step-00-init.md +22 -190
  60. package/templates/skills/business-analyse/steps/step-01-cadrage.md +365 -269
  61. package/templates/skills/business-analyse/steps/step-02-structure.md +98 -20
  62. package/templates/skills/business-analyse/steps/step-03-specify.md +810 -229
  63. package/templates/skills/business-analyse/steps/step-04-consolidate.md +509 -278
  64. package/templates/skills/business-analyse-design/SKILL.md +10 -0
  65. package/templates/skills/business-analyse-design/references/screens-post-check.md +221 -0
  66. package/templates/skills/business-analyse-design/references/screens-type-mapping.md +138 -0
  67. package/templates/skills/business-analyse-design/references/smartcomponents-templates.md +225 -0
  68. package/templates/skills/{business-analyse → business-analyse-design}/references/spec-auto-inference.md +117 -117
  69. package/templates/skills/business-analyse-design/steps/step-01-screens.md +36 -162
  70. package/templates/skills/business-analyse-design/steps/step-02-wireframes.md +8 -7
  71. package/templates/skills/business-analyse-design/steps/step-03-navigation.md +89 -42
  72. package/templates/skills/business-analyse-develop/references/compact-loop.md +9 -0
  73. package/templates/skills/business-analyse-develop/references/handoff-quality-gate.md +132 -0
  74. package/templates/skills/business-analyse-develop/references/prd-v3-transformation.md +326 -0
  75. package/templates/skills/business-analyse-develop/references/report-reconciliation.md +140 -0
  76. package/templates/skills/business-analyse-develop/references/report-template.md +142 -0
  77. package/templates/skills/business-analyse-develop/steps/step-01-task.md +5 -177
  78. package/templates/skills/business-analyse-develop/steps/step-02-execute.md +17 -4
  79. package/templates/skills/business-analyse-develop/steps/step-03-commit.md +6 -2
  80. package/templates/skills/business-analyse-develop/steps/step-04-check.md +6 -0
  81. package/templates/skills/business-analyse-develop/steps/step-05-report.md +3 -269
  82. package/templates/skills/business-analyse-handoff/SKILL.md +10 -0
  83. package/templates/skills/business-analyse-handoff/references/agent-handoff-transform-prompt.md +211 -0
  84. package/templates/skills/business-analyse-handoff/references/context-isolation-pattern.md +47 -0
  85. package/templates/skills/business-analyse-handoff/references/handoff-file-inventory.md +49 -0
  86. package/templates/skills/business-analyse-handoff/references/handoff-global-validation.md +142 -0
  87. package/templates/skills/business-analyse-handoff/references/prd-validation-checks.md +125 -0
  88. package/templates/skills/business-analyse-handoff/references/project-index-update.md +98 -0
  89. package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +9 -160
  90. package/templates/skills/business-analyse-handoff/steps/step-02-export.md +10 -99
  91. package/templates/skills/business-analyse-html/SKILL.md +10 -0
  92. package/templates/skills/business-analyse-html/html/ba-interactive.html +504 -97
  93. package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +79 -2
  94. package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +6 -46
  95. package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +80 -11
  96. package/templates/skills/business-analyse-html/html/src/scripts/06-render-consolidation.js +2 -2
  97. package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +94 -36
  98. package/templates/skills/business-analyse-html/html/src/scripts/12-render-diagrams.js +162 -0
  99. package/templates/skills/business-analyse-html/html/src/styles/10-diagrams.css +73 -0
  100. package/templates/skills/business-analyse-html/html/src/template.html +2 -0
  101. package/templates/skills/business-analyse-html/references/02-embedded-artifacts-building.md +144 -0
  102. package/templates/skills/business-analyse-html/references/02-feature-data-building.md +143 -0
  103. package/templates/skills/business-analyse-html/references/02-mapping-tables.md +442 -0
  104. package/templates/skills/business-analyse-html/references/02-normalization-helpers.md +139 -0
  105. package/templates/skills/business-analyse-html/references/02-screen-format-detection.md +283 -0
  106. package/templates/skills/business-analyse-html/references/02-self-check-validation.md +199 -0
  107. package/templates/skills/business-analyse-html/references/data-build.md +24 -1
  108. package/templates/skills/business-analyse-html/references/data-mapping.md +119 -17
  109. package/templates/skills/business-analyse-html/steps/step-02-build-data.md +18 -555
  110. package/templates/skills/business-analyse-html/steps/step-04-verify.md +92 -3
  111. package/templates/skills/business-analyse-quick/SKILL.md +807 -0
  112. package/templates/skills/{sketch → business-analyse-quick}/references/domain-heuristics.md +59 -3
  113. package/templates/skills/business-analyse-quick/references/prd-schema.md +268 -0
  114. package/templates/skills/business-analyse-review/SKILL.md +10 -0
  115. package/templates/skills/business-analyse-review/references/review-data-mapping.md +6 -0
  116. package/templates/skills/business-analyse-status/SKILL.md +8 -0
  117. package/templates/skills/dev-start/SKILL.md +143 -307
  118. package/templates/skills/efcore/SKILL.md +13 -0
  119. package/templates/skills/sketch/SKILL.md +15 -153
  120. package/templates/skills/ui-components/SKILL.md +1 -1
  121. package/templates/skills/ui-components/patterns/data-table.md +1 -1
@@ -5,7 +5,7 @@ model: opus
5
5
  next_step: steps/step-03-render.md
6
6
  ---
7
7
 
8
- > **Reference files:** `references/data-mapping.md` | `references/data-build.md`
8
+ > **Reference files:** `references/data-mapping.md` | `references/02-mapping-tables.md` | `references/02-normalization-helpers.md` | `references/02-screen-format-detection.md` | `references/02-feature-data-building.md` | `references/02-embedded-artifacts-building.md` | `references/02-self-check-validation.md`
9
9
 
10
10
  # Step 2: Build Data Objects
11
11
 
@@ -21,577 +21,33 @@ Build `FEATURE_DATA` and `EMBEDDED_ARTIFACTS` objects from `{collected_data}` co
21
21
 
22
22
  Construct the complete FEATURE_DATA object following the exact mapping in `references/data-mapping.md`:
23
23
 
24
- **metadata:**
25
- ```javascript
26
- metadata: {
27
- applicationName: master.metadata.application,
28
- applicationId: master.id,
29
- version: master.version,
30
- createdAt: master.metadata.createdAt,
31
- lastModified: master.metadata.updatedAt,
32
- analysisMode: master.metadata.analysisMode || "interactive"
33
- }
34
- ```
24
+ > → **Load** `references/02-mapping-tables.md` for all field mappings (metadata, cadrage, stakeholders, scope, criteria, modules, dependencies, consolidation, handoff, moduleSpecs, wireframes, e2eFlows, dependencyGraph)
25
+ > → **Load** `references/02-normalization-helpers.md` for normalize* functions (normalizeColumn, normalizeField, normalizeFilter, normalizeSmartFilterField, normalizeAction, normalizeChart, normalizeKpi)
26
+ > → **Load** `references/02-screen-format-detection.md` for screens.json format detection and normalization (Format A/B-CANONICAL/B-LEGACY)
35
27
 
36
- **cadrage.context** (lean format MANDATORY fields logged if empty):
37
- ```javascript
38
- const problem = master.cadrage.problem || "";
39
- const trigger = master.cadrage.trigger || "";
40
- const currentSituation = master.cadrage.asIs || "";
41
- const desiredSituation = master.cadrage.toBe || "";
28
+ **Build moduleSpecs{} (ONE entry per module) + top-level fields:**
42
29
 
43
- // MANDATORY field check warn if core cadrage data is empty
44
- if (!problem) console.warn("⚠ cadrage.problem is empty — HTML will show blank problem section");
45
- if (!currentSituation && !desiredSituation) console.warn("⚠ cadrage has no current/desired situation");
46
-
47
- context: {
48
- problem: problem,
49
- trigger: trigger,
50
- currentSituation: currentSituation, // asIs → currentSituation
51
- desiredSituation: desiredSituation, // toBe → desiredSituation
52
- painPoints: (master.cadrage.stakeholders || []).flatMap(s => s.painPoints || []).join("\n"),
53
- acceptanceCriteria: (master.cadrage.acceptanceCriteria || []).map(ac => ac.criterion).join("\n")
54
- }
55
- ```
56
-
57
- **cadrage.stakeholders** (with frequency/access conversion):
58
- ```javascript
59
- stakeholders: master.cadrage.stakeholders.map(s => ({
60
- role: s.role,
61
- function: s.function || "",
62
- tasks: Array.isArray(s.tasks)
63
- ? s.tasks
64
- : typeof s.tasks === 'string'
65
- ? s.tasks.split(',').map(t => t.trim()).filter(Boolean)
66
- : [],
67
- frequency: mapFrequency(s.frequency), // "Quotidien"→"daily", "Hebdomadaire"→"weekly", "Mensuel"→"monthly"
68
- access: mapAccess(s.involvement), // "decision-maker"→"admin", "end-user"→"contributor", "observer"→"viewer"
69
- frustrations: (s.painPoints || []).join("\n")
70
- }))
71
- ```
72
-
73
- **cadrage.scope** (KEY CONVERSION — CRITICAL):
74
- ```javascript
75
- scope: {
76
- inscope: (master.cadrage.globalScope?.inScope || []).map(item => ({ name: item, description: "" })),
77
- outofscope: (master.cadrage.globalScope?.outOfScope || []).map(item => ({ name: item, description: "" }))
78
- }
79
- ```
80
-
81
- > Safety net: also check `master.cadrage.coverageMatrix` as alternative source for scope items.
82
-
83
- **cadrage.criteria** (acceptance criteria with validation.json fallback):
84
- ```javascript
85
- // Build structured criteria for the checklist UI
86
- let criteria = (master.cadrage.acceptanceCriteria || []).map(ac => ({
87
- text: ac.criterion || ac.text || "",
88
- validated: false
89
- }));
90
-
91
- // FALLBACK: if cadrage has no criteria, use validation.json acceptance criteria
92
- if (criteria.length === 0 && collected_data.master.validation) {
93
- const valAC = collected_data.master.validation.acceptanceCriteria || [];
94
- criteria = valAC.map(ac => ({
95
- text: (ac.module ? '[' + ac.module + '] ' : '') + (ac.criteria || ac.criterion || ac.text || ""),
96
- validated: false,
97
- module: ac.module || null,
98
- type: ac.type || null
99
- }));
100
- }
101
-
102
- cadrage.criteria = criteria;
103
- ```
104
-
105
- **modules[]:**
106
- ```javascript
107
- modules: master.modules.map(m => ({
108
- code: m.code,
109
- name: m.name || m.code, // display name (MANDATORY)
110
- description: m.description || "",
111
- featureType: m.featureType || "data-centric",
112
- entities: m.entities || [],
113
- anticipatedSections: (m.anticipatedSections || []).map(s =>
114
- typeof s === 'string'
115
- ? { code: s, name: s, description: "", resources: [] }
116
- : { code: s.code || s.name || "", name: s.label || s.name || s.code || "", description: s.description || "", resources: s.resources || [], route: s.route || "", permission: s.permission || "" }
117
- ),
118
- dependencies: m.dependencies || [],
119
- dependents: m.dependents || [],
120
- estimatedComplexity: m.estimatedComplexity || "medium",
121
- status: m.status || "handed-off"
122
- }))
123
- ```
124
-
125
- **moduleSpecs{} — ONE entry per module (CRITICAL):**
126
-
127
- > **FLAT-FILE ARCHITECTURE:** Module data comes from separate JSON files collected in step-01,
128
- > NOT from index.json fields. Use `collected_data.modules[moduleCode].entities`, `.usecases`, etc.
129
-
130
- For EACH module, use the flat file data from `collected_data.modules[moduleCode]`:
131
-
132
- ```javascript
133
- const mod = collected_data.modules[moduleCode];
134
-
135
- // NORMALIZE: usecases.json may use "useCases" (camelCase) or "usecases" (lowercase)
136
- const rawUCs = mod.usecases?.useCases || mod.usecases?.usecases || [];
137
- // NORMALIZE: rules.json may use "rules" or "businessRules"
138
- const rawBRs = mod.rules?.rules || mod.rules?.businessRules || [];
139
-
140
- moduleSpecs[moduleCode] = {
141
- useCases: rawUCs.map(uc => ({
142
- name: uc.name || uc.title || uc.id || "",
143
- sectionCode: uc.sectionCode || "",
144
- actor: uc.primaryActor || uc.actor || "",
145
- // SAFETY NET: steps may be strings[] (mainScenario) or objects[] ({step, action})
146
- steps: (uc.mainScenario || uc.steps || []).map(s =>
147
- typeof s === 'string' ? s : (s.action || s.description || "")
148
- ).join("\n"),
149
- alternative: (uc.alternativeScenarios || uc.alternativeFlows || []).map(a =>
150
- (a.name || a.trigger || "") + ": " + (a.steps || a.actions || []).map(s =>
151
- typeof s === 'string' ? s : (s.action || s.description || "")
152
- ).join(", ")
153
- ).join("\n")
154
- })),
155
- businessRules: rawBRs.map(br => ({
156
- name: br.name || br.id || "",
157
- sectionCode: br.sectionCode || "",
158
- category: br.category || "",
159
- statement: br.statement || br.description || "",
160
- example: (br.examples || []).map(e =>
161
- typeof e === 'string' ? e : ((e.input || "") + " → " + (e.expected || ""))
162
- ).join("; ")
163
- })),
164
- // ENTITY SAFETY NET: map fields[] → attributes[] if agent deviated
165
- entities: (mod.entities?.entities || []).map(ent => ({
166
- name: ent.name,
167
- description: ent.description || "",
168
- attributes: (ent.attributes || []).length > 0
169
- ? ent.attributes.map(a => ({ name: a.name, type: a.type || "string", required: a.required || false, description: a.description || "" }))
170
- : (ent.fields || []).map(f => ({ name: f.name, type: f.type || "string", required: f.required || false, description: f.description || "" })),
171
- relationships: (ent.relationships || []).map(r =>
172
- typeof r === 'string' ? r : r.target + " (" + r.type + ") - " + (r.description || ""))
173
- })),
174
- permissions: buildPermissionKeys(mod.permissions),
175
- apiEndpoints: mod.usecases?.apiEndpoints || []
176
- }
177
-
178
- // BUILD screens[] for HTML interactive mockups (SmartTable/SmartForm rendering)
179
- // NORMALIZE: screens.json may use "screens[]" (flat) or "sections[]" (nested) format
180
- const flatScr = mod.screens?.screens || [];
181
- const sectionScr = mod.screens?.sections || [];
182
- let screens = [];
183
-
184
- // Helper: normalize a column definition regardless of field naming convention
185
- function normalizeColumn(c) {
186
- return {
187
- field: c.code || c.name || c.id || c.field || c.fieldCode || "",
188
- label: c.label || c.displayName || c.code || c.name || "",
189
- type: c.renderAs === "badge" ? "badge" : (c.type || c.dataType || "text"),
190
- sortable: !!c.sortable
191
- };
192
- }
193
-
194
- // Helper: normalize a form field
195
- function normalizeField(f) {
196
- return {
197
- field: f.code || f.name || f.id || f.fieldCode || f.field || "",
198
- label: f.label || f.displayName || f.code || f.name || "",
199
- type: f.type || f.fieldType || f.dataType || "text",
200
- required: !!f.required
201
- };
202
- }
203
-
204
- // Helper: normalize a filter
205
- function normalizeFilter(f) {
206
- if (typeof f === 'string') return f;
207
- return f.label || f.displayName || f.filterLabel || f.name || f.code || f.filterCode || "";
208
- }
209
-
210
- // Helper: normalize an action
211
- function normalizeAction(a) {
212
- if (typeof a === 'string') return a;
213
- return a.code || a.id || a.label || a.actionCode || "";
214
- }
215
-
216
- // Helper: normalize a chart definition
217
- function normalizeChart(c) {
218
- if (typeof c === 'string') return { type: 'bar', label: c };
219
- return {
220
- type: c.type || c.chartType || 'bar',
221
- label: c.label || c.displayName || c.title || 'Graphique'
222
- };
223
- }
224
-
225
- // Helper: normalize a KPI — replace formula values with sample display values
226
- function normalizeKpi(k) {
227
- if (typeof k !== 'object') return { label: String(k), value: "0" };
228
- const label = k.label || k.displayName || "";
229
- const rawValue = k.value || k.metric || "0";
230
- let displayValue = rawValue;
231
- // Detect formula patterns (e.g., count(...), sum(...), ratio(...), avg(...))
232
- if (typeof rawValue === 'string' && rawValue.includes('(')) {
233
- const lbl = label.toLowerCase();
234
- if (rawValue.includes('ratio') || rawValue.includes('%') || lbl.includes('taux') || lbl.includes('rate'))
235
- displayValue = "87.5%";
236
- else if (rawValue.includes('avg') || lbl.includes('moyen') || lbl.includes('average'))
237
- displayValue = "12.4";
238
- else if (rawValue.includes('sum'))
239
- displayValue = (lbl.includes('jour') || lbl.includes('day') || lbl.includes('heure') || lbl.includes('hour')) ? "156" : "45,678";
240
- else
241
- displayValue = "1,234";
242
- }
243
- // Also handle format hint from the KPI definition
244
- if (k.format === 'percentage' && displayValue === rawValue) displayValue = "80%";
245
- return { label: label, value: displayValue };
246
- }
247
-
248
- if (flatScr.length > 0) {
249
- // FORMAT A: flat screens[] array (ba-003 style)
250
- const bySec = {};
251
- flatScr.forEach(s => {
252
- const sec = s.section || "default";
253
- if (!bySec[sec]) bySec[sec] = {
254
- sectionCode: sec,
255
- sectionLabel: s.sectionLabel || s.sectionDescription || sec,
256
- resources: []
257
- };
258
- bySec[sec].resources.push({
259
- code: s.screen || s.name || "",
260
- label: s.sectionLabel || s.description || s.screen || "",
261
- type: s.componentType || "unknown",
262
- columns: (s.columns || []).map(normalizeColumn),
263
- filters: (s.filters || []).map(normalizeFilter),
264
- fields: [],
265
- tabs: (s.tabs || []).map(t => ({
266
- label: t.label || t.tabLabel || t.code || "",
267
- fields: (t.fields || []).map(normalizeField)
268
- })),
269
- actions: (s.actions || []).map(normalizeAction),
270
- kpis: (s.kpis || []).map(normalizeKpi),
271
- charts: (s.charts || []).map(normalizeChart),
272
- options: s.options || [],
273
- permission: s.permission || "",
274
- notes: s.description || s.sectionDescription || ""
275
- });
276
- });
277
- screens = Object.values(bySec);
278
- } else if (sectionScr.length > 0) {
279
- // DETECT sub-format: canonical (resources[] inside sections) vs ba-004 (data on section itself)
280
- const hasNestedResources = sectionScr.some(sec => (sec.resources || []).length > 0);
281
-
282
- if (hasNestedResources) {
283
- // FORMAT B-CANONICAL: sections[] with resources[] (ba-005+ style — sectionCode/sectionLabel/resources[])
284
- // Resources have their own code/type/columns/tabs/kpis — iterate over them
285
- screens = sectionScr.map(sec => ({
286
- sectionCode: sec.sectionCode || sec.id || sec.code || "",
287
- sectionLabel: sec.sectionLabel || sec.displayName || sec.label || sec.sectionCode || "",
288
- resources: (sec.resources || []).map(res => ({
289
- code: res.code || res.id || "",
290
- label: res.label || res.displayName || res.code || "",
291
- type: res.type || res.componentType || res.layout || "unknown",
292
- columns: (res.columns || []).map(normalizeColumn),
293
- filters: (res.filters || []).map(normalizeFilter),
294
- fields: [],
295
- tabs: (res.tabs || []).map(t => ({
296
- label: t.label || t.displayName || t.code || t.id || "",
297
- fields: (t.fields || []).map(normalizeField)
298
- })),
299
- actions: (res.actions || []).map(normalizeAction),
300
- kpis: (res.kpis || []).map(normalizeKpi),
301
- charts: (res.charts || []).map(normalizeChart),
302
- options: res.options || [],
303
- permission: res.permission || "",
304
- notes: res.notes || res.description || ""
305
- }))
306
- }));
307
- } else {
308
- // FORMAT B-LEGACY: sections[] without resources[] (ba-004 style — data directly on section)
309
- const bySec = {};
310
- sectionScr.forEach(sec => {
311
- const secId = sec.id || sec.code || sec.sectionCode || "";
312
- const secLabel = sec.displayName || sec.label || sec.sectionLabel || secId;
313
- const componentType = sec.layout || sec.componentType || "unknown";
314
- if (!bySec[secId]) bySec[secId] = {
315
- sectionCode: secId,
316
- sectionLabel: secLabel,
317
- resources: []
318
- };
319
- bySec[secId].resources.push({
320
- code: secId,
321
- label: secLabel,
322
- type: componentType,
323
- columns: (sec.columns || []).map(normalizeColumn),
324
- filters: (sec.filters || []).map(normalizeFilter),
325
- fields: [],
326
- tabs: (sec.tabs || []).map(t => ({
327
- label: t.displayName || t.label || t.code || t.id || "",
328
- fields: (t.fields || []).map(normalizeField)
329
- })),
330
- actions: (sec.actions || []).map(normalizeAction),
331
- kpis: (sec.kpis || []).map(normalizeKpi),
332
- charts: (sec.charts || []).map(normalizeChart),
333
- options: sec.options || [],
334
- permission: (typeof sec.permissions === 'object' ? sec.permissions?.view : sec.permission) || "",
335
- notes: sec.description || ""
336
- });
337
- });
338
- screens = Object.values(bySec);
339
- }
340
- }
341
- moduleSpecs[moduleCode].screens = screens;
342
- ```
343
-
344
- > See `references/data-mapping.md` for `buildPermissionKeys()` implementation.
345
-
346
- **Enrich anticipatedSections with section-level UC/BR (AFTER moduleSpecs is built):**
347
-
348
- ```javascript
349
- // Post-processing: populate each section's useCases[] and businessRules[]
350
- // using the sectionCode field from moduleSpecs
351
- FEATURE_DATA.modules.forEach(m => {
352
- const spec = FEATURE_DATA.moduleSpecs[m.code];
353
- if (!spec) return;
354
- (m.anticipatedSections || []).forEach(section => {
355
- section.useCases = (spec.useCases || []).filter(uc => uc.sectionCode === section.code);
356
- section.businessRules = (spec.businessRules || []).filter(br => br.sectionCode === section.code);
357
- });
358
- });
359
- ```
360
-
361
- > This step is CRITICAL for the HTML viewer to display UC/BR grouped by section.
30
+ > **Load** `references/02-feature-data-building.md` for complete moduleSpecs construction logic, screen building, anticipatedSections enrichment, and top-level fields (dependencies, consolidation, handoff)
362
31
 
363
32
  ### Post-Build Self-Check (MANDATORY — BLOCKING)
364
33
 
365
- After enriching anticipatedSections, run this self-check to detect data loss:
366
-
367
- ```javascript
368
- // SELF-CHECK: compare source file counts vs FEATURE_DATA counts
369
- const errors = [];
370
- FEATURE_DATA.modules.forEach(m => {
371
- const spec = FEATURE_DATA.moduleSpecs[m.code];
372
- const source = collected_data.modules[m.code];
373
- if (!spec) { errors.push(`MISSING moduleSpecs[${m.code}]`); return; }
374
-
375
- // Check useCases (handle both key conventions)
376
- const srcUC = (source?.usecases?.useCases || source?.usecases?.usecases || []).length;
377
- const bltUC = (spec.useCases || []).length;
378
- if (srcUC > 0 && bltUC === 0)
379
- errors.push(`${m.code}: useCases EMPTY but source has ${srcUC}`);
380
-
381
- // Check businessRules (handle both key conventions)
382
- const srcBR = (source?.rules?.rules || source?.rules?.businessRules || []).length;
383
- const bltBR = (spec.businessRules || []).length;
384
- if (srcBR > 0 && bltBR === 0)
385
- errors.push(`${m.code}: businessRules EMPTY but source has ${srcBR}`);
386
-
387
- // Check entities
388
- const srcEnt = (source?.entities?.entities || []).length;
389
- const bltEnt = (spec.entities || []).length;
390
- if (srcEnt > 0 && bltEnt === 0)
391
- errors.push(`${m.code}: entities EMPTY but source has ${srcEnt}`);
392
-
393
- // Check screens (handle both formats: screens[] and sections[])
394
- const srcScreens = (source?.screens?.screens || source?.screens?.sections || []).length;
395
- const bltScreenResources = (spec.screens || []).reduce(
396
- (acc, s) => acc + (s.resources || []).length, 0);
397
- if (srcScreens > 0 && bltScreenResources === 0)
398
- errors.push(`${m.code}: screens EMPTY (0 resources) but source has ${srcScreens} screens/sections`);
399
-
400
- // Check serialization: [object Object] in useCases steps = BUG
401
- (spec.useCases || []).forEach(uc => {
402
- if (uc.steps && uc.steps.includes("[object Object]"))
403
- errors.push(`${m.code}: UC "${uc.name}" has [object Object] in steps — steps[] contains objects not strings`);
404
- });
405
- });
406
-
407
- if (errors.length > 0) {
408
- Display("⛔ SELF-CHECK FAILED — data loss detected:");
409
- errors.forEach(e => Display(" - " + e));
410
- // FIX: re-map the failing modules from collected_data before continuing
411
- }
412
- ```
413
-
414
- > If self-check detects errors, you MUST re-read the source data and re-build the failing moduleSpecs entries.
415
- > Do NOT proceed with empty arrays when source data exists.
416
-
417
- **dependencies[] (TOP-LEVEL — CRITICAL for HTML navigation):**
418
- ```javascript
419
- dependencies: (master.consolidation?.crossModuleInteractions || master.dependencyGraph?.edges || []).map(i => ({
420
- from: i.fromModule || i.from || "",
421
- to: i.toModule || i.to || "",
422
- description: i.description || ""
423
- }))
424
- ```
34
+ > **Load** `references/02-self-check-validation.md` for complete self-check code and validation points.
425
35
 
426
- > **WARNING:** `data.dependencies` is used by the sidebar (navigation), module rendering, consolidation views,
427
- > handoff summary, and export. If this array is missing, the entire HTML page crashes with a TypeError.
428
- > ALWAYS include it, even if empty (`dependencies: []`).
429
-
430
- **consolidation:**
431
- ```javascript
432
- consolidation: {
433
- interactions: (master.consolidation?.crossModuleInteractions || []).map(i => ({
434
- from: i.fromModule,
435
- to: i.toModule,
436
- description: i.description || ""
437
- })),
438
- sharedEntities: master.consolidation?.sharedEntities || [],
439
- e2eFlows: (master.consolidation?.e2eFlows || []).map(f => ({
440
- name: f.name,
441
- steps: (f.steps || []).map(s => ({ module: s.module, action: s.action })),
442
- actors: (f.steps || []).map(s => s.permission).join(", ")
443
- }))
444
- }
445
- ```
446
-
447
- **handoff:**
448
- ```javascript
449
- handoff: {
450
- complexity: master.handoff?.complexity,
451
- implementationStrategy: master.handoff?.implementationStrategy,
452
- moduleOrder: master.handoff?.moduleOrder,
453
- filesToCreate: master.handoff?.filesToCreate,
454
- brToCodeMapping: master.handoff?.brToCodeMapping,
455
- apiEndpointSummary: master.handoff?.apiEndpointSummary
456
- }
457
- ```
36
+ After building FEATURE_DATA, run the self-check to detect data loss. This compares source file counts (useCases, businessRules, entities, screens) against built FEATURE_DATA counts to catch normalization bugs before rendering.
458
37
 
459
38
  ---
460
39
 
461
40
  ### 2. Build EMBEDDED_ARTIFACTS
462
41
 
463
- > **FIELD RENAME WARNING:** Module JSON uses `mockupFormat`/`mockup`. HTML reads `format`/`content`. You MUST rename.
464
-
465
- **wireframes{} — per moduleCode:**
466
-
467
- > **FLAT-FILE:** Wireframes come from `screens.json` in each module directory (collected in step-01),
468
- > NOT from `moduleFeature.specification.uiWireframes`.
469
-
470
- ```javascript
471
- const mod = collected_data.modules[moduleCode];
472
-
473
- // STEP 1: Collect wireframe sources from BOTH flat and nested structures
474
- // Flat: mod.screens.screens[] with mockupFormat/mockup at top level
475
- // Nested: mod.screens.sections[].resources[].wireframe (design step output)
476
- let rawWireframes = [];
477
-
478
- // Source A: flat screens[] array (original BA output or manually enriched)
479
- const flatScreens = mod.screens?.screens || [];
480
- rawWireframes.push(...flatScreens.filter(s => s.mockup || s.mockupFormat));
481
-
482
- // Source B: nested sections[].resources[].wireframe (design step output)
483
- const sections = mod.screens?.sections || [];
484
- for (const section of sections) {
485
- // B1: wireframe directly on section (ba-004 style: sections[].wireframe)
486
- if (section.wireframe) {
487
- rawWireframes.push({
488
- ...section.wireframe,
489
- section: section.wireframe.section || section.id || section.code || section.sectionCode || "",
490
- screen: section.wireframe.screen || section.id || section.code || section.sectionCode || ""
491
- });
492
- }
493
- // B2: wireframe on resources (nested: sections[].resources[].wireframe)
494
- for (const resource of (section.resources || [])) {
495
- if (resource.wireframe) {
496
- rawWireframes.push({
497
- ...resource.wireframe,
498
- section: resource.wireframe.section || section.sectionCode || section.id || "",
499
- screen: resource.wireframe.screen || `${section.sectionCode || section.id}-${resource.code}` || ""
500
- });
501
- }
502
- }
503
- }
504
-
505
- // Source C: screens/sections without mockup → auto-generate text description as wireframe fallback
506
- // C1: from flat screens[]
507
- const screensWithoutMockup = flatScreens.filter(s => !s.mockup && !s.mockupFormat);
508
- // C2: from sections[] (ba-004 style) — sections without wireframe property
509
- const sectionsWithoutWireframe = sections.filter(s => !s.wireframe);
510
- const allNoMockup = [
511
- ...screensWithoutMockup.map(s => ({
512
- type: s.componentType || "", columns: s.columns || [], tabs: s.tabs || [],
513
- kpis: s.kpis || [], screen: s.screen || "", section: s.section || "",
514
- description: s.sectionDescription || ""
515
- })),
516
- ...sectionsWithoutWireframe.map(s => ({
517
- type: s.layout || s.componentType || "", columns: s.columns || [], tabs: s.tabs || [],
518
- kpis: s.kpis || [], screen: s.id || s.code || "", section: s.id || s.code || "",
519
- description: s.description || ""
520
- }))
521
- ];
522
- for (const screen of allNoMockup) {
523
- const type = screen.type;
524
- let desc = "";
525
- if (type.includes("Table") || type.includes("Grid")) {
526
- const cols = screen.columns;
527
- desc = "Tableau avec " + cols.length + " colonnes : " + cols.map(c => c.label || c.displayName || c.code || c.name).join(", ");
528
- } else if (type.includes("Form")) {
529
- const tabs = screen.tabs;
530
- desc = "Formulaire " + (tabs.length > 0 ? "avec " + tabs.length + " onglet(s)" : "");
531
- } else if (type.includes("Dashboard")) {
532
- desc = "Tableau de bord avec " + (screen.kpis.length || "") + " KPIs";
533
- } else if (type.includes("Kanban")) {
534
- desc = "Vue Kanban";
535
- }
536
- if (desc) {
537
- rawWireframes.push({
538
- screen: screen.screen, section: screen.section,
539
- mockupFormat: "text", mockup: desc,
540
- description: screen.description, elements: [], componentMapping: []
541
- });
542
- }
543
- }
544
-
545
- // STEP 2: Map to HTML format (RENAME: mockupFormat → format, mockup → content)
546
- wireframes: {
547
- [moduleCode]: rawWireframes.map(wf => ({
548
- screen: wf.screen || wf.name || wf.title || wf.id || "",
549
- section: wf.section || "",
550
- format: wf.mockupFormat || "ascii", // RENAME: mockupFormat → format
551
- content: wf.mockup || wf.ascii || wf.content || "", // RENAME: mockup → content
552
- svgContent: null,
553
- description: wf.description || "",
554
- elements: wf.elements || [],
555
- actions: wf.actions || [],
556
- componentMapping: Array.isArray(wf.componentMapping) ? wf.componentMapping
557
- : typeof wf.componentMapping === 'object' && wf.componentMapping !== null
558
- ? Object.entries(wf.componentMapping).map(([k, v]) => ({ wireframeElement: k, reactComponent: v }))
559
- : [],
560
- layout: typeof wf.layout === 'object' ? wf.layout : null,
561
- permissionsRequired: wf.permissionsRequired || []
562
- }))
563
- }
564
- ```
565
-
566
- **e2eFlows[]:**
567
- ```javascript
568
- e2eFlows: (master.consolidation?.e2eFlows || []).map(flow => ({
569
- name: flow.name,
570
- diagram: flow.steps.map(s => s.action + "(" + s.module + ")").join(" ──→ "),
571
- steps: flow.steps || [],
572
- actors: [...new Set(flow.steps.map(s => s.permission?.split(".")[0]).filter(Boolean))].join(", "),
573
- modules: [...new Set(flow.steps.map(s => s.module))].join(" → ")
574
- }))
575
- ```
42
+ **Build wireframes{}, e2eFlows[], and dependencyGraph:**
576
43
 
577
- **dependencyGraph:**
578
- ```javascript
579
- dependencyGraph: {
580
- nodes: (master.modules || []).map(m => ({
581
- id: m.code, label: m.code, type: m.featureType || "data-centric"
582
- })),
583
- edges: (master.dependencyGraph?.edges || []).map(e => ({
584
- from: e.from, to: e.to, description: e.description || ""
585
- }))
586
- }
587
- ```
44
+ > → **Load** `references/02-embedded-artifacts-building.md` for complete construction logic: flat-file wireframe collection from screens.json (Sources A, B, C), field renaming (mockupFormat → format, mockup → content), e2eFlows, and dependencyGraph
588
45
 
589
46
  ---
590
47
 
591
48
  ### 3. Generate SVG Wireframes (Parallel, Optional)
592
49
 
593
- > This step is NEVER blocking — ASCII-only wireframes are acceptable.
594
- > **Reference:** `business-analyse/references/wireframe-svg-style-guide.md` for full agent prompt template
50
+ This step is NEVER blocking — ASCII-only wireframes are acceptable.
595
51
 
596
52
  1. Collect all wireframes where `content` exists and `svgContent` is null
597
53
  2. Spawn parallel Task(sonnet) agents — ONE per wireframe
@@ -607,6 +63,13 @@ dependencyGraph: {
607
63
  - cadrage.scope uses HTML keys (inscope/outofscope)
608
64
  - Wireframe fields use format/content (NOT mockupFormat/mockup)
609
65
  - Per-module: useCases/businessRules/entities count must match source (empty when source has data = BUG)
66
+ - dependencies[] must be present (even if empty) to prevent HTML crashes
67
+ - **Permissions:** `buildPermissionKeys()` supports 4 formats:
68
+ - **Format A:** `permissions.matrix[]` with `{role, permissions[]}`
69
+ - **Format B:** `permissions.permissionMatrix.roleAssignments[]`
70
+ - **Format C:** `permissions.roles[]` with `{role, permissions[]}`
71
+ - **Format D:** `permissions.permissionMatrix.roleAssignments[]` with wildcard expansion
72
+ - Pass optional `lang` parameter ('fr'|'en') for bilingual labels. Defaults to 'fr'.
610
73
 
611
74
  ## NEXT STEP
612
75