@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.
- package/dist/index.js +152 -31
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +14 -3
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/agents/ba-reader.md +17 -15
- package/templates/agents/ba-writer.md +49 -51
- package/templates/skills/apex/SKILL.md +2 -2
- package/templates/skills/apex/_shared.md +1 -1
- package/templates/skills/apex/references/checks/backend-checks.sh +21 -7
- package/templates/skills/apex/references/checks/frontend-checks.sh +26 -0
- package/templates/skills/apex/references/checks/infrastructure-checks.sh +47 -10
- package/templates/skills/apex/references/checks/seed-checks.sh +47 -7
- package/templates/skills/apex/references/core-seed-data.md +20 -18
- package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +3 -0
- package/templates/skills/apex/references/post-checks.md +23 -3
- package/templates/skills/apex/references/smartstack-api.md +4 -4
- package/templates/skills/apex/references/smartstack-frontend.md +54 -8
- package/templates/skills/apex/references/smartstack-layers.md +6 -6
- package/templates/skills/apex/steps/step-00-init.md +75 -1
- package/templates/skills/apex/steps/step-03-execute.md +16 -4
- package/templates/skills/apex/steps/step-03b-layer1-seed.md +65 -6
- package/templates/skills/apex/steps/step-03c-layer2-backend.md +50 -5
- package/templates/skills/apex/steps/step-03d-layer3-frontend.md +226 -4
- package/templates/skills/apex/steps/step-04-examine.md +163 -0
- package/templates/skills/apex-verify/SKILL.md +110 -0
- package/templates/skills/apex-verify/references/audit-rules.md +50 -0
- package/templates/skills/apex-verify/steps/step-00-init.md +119 -0
- package/templates/skills/apex-verify/steps/step-01-nav-audit.md +92 -0
- package/templates/skills/apex-verify/steps/step-02-crud-audit.md +127 -0
- package/templates/skills/apex-verify/steps/step-03-perm-audit.md +119 -0
- package/templates/skills/apex-verify/steps/step-04-route-audit.md +98 -0
- package/templates/skills/apex-verify/steps/step-05-report.md +110 -0
- package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +3 -0
- package/templates/skills/application/templates-frontend.md +2 -2
- package/templates/skills/business-analyse/SKILL.md +17 -3
- package/templates/skills/business-analyse/_shared.md +64 -0
- package/templates/skills/business-analyse/patterns/suggestion-catalog.md +34 -26
- package/templates/skills/business-analyse/questionnaire/01-context.md +13 -9
- package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +20 -27
- package/templates/skills/business-analyse/questionnaire.md +86 -9
- package/templates/skills/business-analyse/references/03-json-schemas.md +221 -0
- package/templates/skills/business-analyse/references/03-post-check-validation.md +208 -0
- package/templates/skills/business-analyse/references/03-smartstack-entity-guards.md +32 -0
- package/templates/skills/business-analyse/references/04-cross-module-validation.md +95 -0
- package/templates/skills/business-analyse/references/04-file-allocation.md +162 -0
- package/templates/skills/business-analyse/references/04-naming-audit-checks.md +174 -0
- package/templates/skills/business-analyse/references/04-semantic-validation-matrix.md +118 -0
- package/templates/skills/business-analyse/references/canonical-json-formats.md +7 -3
- package/templates/skills/business-analyse/references/domain-research-playbook.md +234 -0
- package/templates/skills/business-analyse/references/entity-sourcing-presentation.md +166 -0
- package/templates/skills/business-analyse/references/init-resume-logic.md +70 -0
- package/templates/skills/business-analyse/references/module-completeness-challenge.md +174 -0
- package/templates/skills/business-analyse/references/multi-app-detection.md +149 -0
- package/templates/skills/business-analyse/references/portal-classification.md +52 -0
- package/templates/skills/business-analyse/references/robustness-checks.md +1 -1
- package/templates/skills/business-analyse/references/validation-checklist.md +35 -6
- package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +50 -6
- package/templates/skills/business-analyse/steps/step-00-init.md +22 -190
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +365 -269
- package/templates/skills/business-analyse/steps/step-02-structure.md +98 -20
- package/templates/skills/business-analyse/steps/step-03-specify.md +810 -229
- package/templates/skills/business-analyse/steps/step-04-consolidate.md +509 -278
- package/templates/skills/business-analyse-design/SKILL.md +10 -0
- package/templates/skills/business-analyse-design/references/screens-post-check.md +221 -0
- package/templates/skills/business-analyse-design/references/screens-type-mapping.md +138 -0
- package/templates/skills/business-analyse-design/references/smartcomponents-templates.md +225 -0
- package/templates/skills/{business-analyse → business-analyse-design}/references/spec-auto-inference.md +117 -117
- package/templates/skills/business-analyse-design/steps/step-01-screens.md +36 -162
- package/templates/skills/business-analyse-design/steps/step-02-wireframes.md +8 -7
- package/templates/skills/business-analyse-design/steps/step-03-navigation.md +89 -42
- package/templates/skills/business-analyse-develop/references/compact-loop.md +9 -0
- package/templates/skills/business-analyse-develop/references/handoff-quality-gate.md +132 -0
- package/templates/skills/business-analyse-develop/references/prd-v3-transformation.md +326 -0
- package/templates/skills/business-analyse-develop/references/report-reconciliation.md +140 -0
- package/templates/skills/business-analyse-develop/references/report-template.md +142 -0
- package/templates/skills/business-analyse-develop/steps/step-01-task.md +5 -177
- package/templates/skills/business-analyse-develop/steps/step-02-execute.md +17 -4
- package/templates/skills/business-analyse-develop/steps/step-03-commit.md +6 -2
- package/templates/skills/business-analyse-develop/steps/step-04-check.md +6 -0
- package/templates/skills/business-analyse-develop/steps/step-05-report.md +3 -269
- package/templates/skills/business-analyse-handoff/SKILL.md +10 -0
- package/templates/skills/business-analyse-handoff/references/agent-handoff-transform-prompt.md +211 -0
- package/templates/skills/business-analyse-handoff/references/context-isolation-pattern.md +47 -0
- package/templates/skills/business-analyse-handoff/references/handoff-file-inventory.md +49 -0
- package/templates/skills/business-analyse-handoff/references/handoff-global-validation.md +142 -0
- package/templates/skills/business-analyse-handoff/references/prd-validation-checks.md +125 -0
- package/templates/skills/business-analyse-handoff/references/project-index-update.md +98 -0
- package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +9 -160
- package/templates/skills/business-analyse-handoff/steps/step-02-export.md +10 -99
- package/templates/skills/business-analyse-html/SKILL.md +10 -0
- package/templates/skills/business-analyse-html/html/ba-interactive.html +504 -97
- package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +79 -2
- package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +6 -46
- package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +80 -11
- package/templates/skills/business-analyse-html/html/src/scripts/06-render-consolidation.js +2 -2
- package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +94 -36
- package/templates/skills/business-analyse-html/html/src/scripts/12-render-diagrams.js +162 -0
- package/templates/skills/business-analyse-html/html/src/styles/10-diagrams.css +73 -0
- package/templates/skills/business-analyse-html/html/src/template.html +2 -0
- package/templates/skills/business-analyse-html/references/02-embedded-artifacts-building.md +144 -0
- package/templates/skills/business-analyse-html/references/02-feature-data-building.md +143 -0
- package/templates/skills/business-analyse-html/references/02-mapping-tables.md +442 -0
- package/templates/skills/business-analyse-html/references/02-normalization-helpers.md +139 -0
- package/templates/skills/business-analyse-html/references/02-screen-format-detection.md +283 -0
- package/templates/skills/business-analyse-html/references/02-self-check-validation.md +199 -0
- package/templates/skills/business-analyse-html/references/data-build.md +24 -1
- package/templates/skills/business-analyse-html/references/data-mapping.md +119 -17
- package/templates/skills/business-analyse-html/steps/step-02-build-data.md +18 -555
- package/templates/skills/business-analyse-html/steps/step-04-verify.md +92 -3
- package/templates/skills/business-analyse-quick/SKILL.md +807 -0
- package/templates/skills/{sketch → business-analyse-quick}/references/domain-heuristics.md +59 -3
- package/templates/skills/business-analyse-quick/references/prd-schema.md +268 -0
- package/templates/skills/business-analyse-review/SKILL.md +10 -0
- package/templates/skills/business-analyse-review/references/review-data-mapping.md +6 -0
- package/templates/skills/business-analyse-status/SKILL.md +8 -0
- package/templates/skills/dev-start/SKILL.md +143 -307
- package/templates/skills/efcore/SKILL.md +13 -0
- package/templates/skills/sketch/SKILL.md +15 -153
- package/templates/skills/ui-components/SKILL.md +1 -1
- 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-
|
|
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
|
-
|
|
26
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|