@atlashub/smartstack-cli 4.74.0 → 4.75.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 +111 -36
- 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/_shared.md +1 -1
- package/templates/skills/apex/references/checks/backend-checks.sh +21 -7
- package/templates/skills/apex/references/checks/infrastructure-checks.sh +47 -10
- package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +3 -0
- package/templates/skills/apex/references/post-checks.md +5 -2
- package/templates/skills/apex/references/smartstack-frontend.md +53 -7
- package/templates/skills/apex/steps/step-00-init.md +74 -0
- package/templates/skills/apex/steps/step-03-execute.md +16 -4
- package/templates/skills/apex/steps/step-03b-layer1-seed.md +39 -6
- package/templates/skills/apex/steps/step-03c-layer2-backend.md +50 -5
- package/templates/skills/apex/steps/step-03d-layer3-frontend.md +102 -2
- package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +3 -0
- package/templates/skills/business-analyse/SKILL.md +14 -0
- package/templates/skills/business-analyse/_shared.md +27 -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 +213 -0
- package/templates/skills/business-analyse/references/03-post-check-validation.md +144 -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/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/validation-checklist.md +30 -1
- package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +37 -4
- 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 +652 -229
- package/templates/skills/business-analyse/steps/step-04-consolidate.md +308 -287
- 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 +208 -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 +306 -81
- package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +15 -2
- package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +6 -46
- package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +88 -33
- package/templates/skills/business-analyse-html/html/src/scripts/12-render-diagrams.js +116 -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 +141 -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 +22 -1
- package/templates/skills/business-analyse-html/references/data-mapping.md +40 -5
- package/templates/skills/business-analyse-html/steps/step-02-build-data.md +12 -555
- package/templates/skills/business-analyse-review/SKILL.md +10 -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
|
@@ -194,31 +194,36 @@ function renderSmartFormMockup(res) {
|
|
|
194
194
|
html += '<div class="mock-form-tab-content' + (ti === 0 || isOnly ? ' active' : '') + '"';
|
|
195
195
|
html += ' data-mockup="' + mockupId + '" data-tab="' + ti + '">';
|
|
196
196
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
// Tab-level subtable: the entire tab is a subtable (type: "subtable", entity, columns)
|
|
198
|
+
if (tab.type === 'subtable') {
|
|
199
|
+
html += renderSubtableMockup(tab);
|
|
200
|
+
} else {
|
|
201
|
+
var fields = tab.fields || [];
|
|
202
|
+
var rows = [];
|
|
203
|
+
for (var i = 0; i < fields.length; i += 2) {
|
|
204
|
+
rows.push(fields.slice(i, i + 2));
|
|
205
|
+
}
|
|
202
206
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
207
|
+
rows.forEach(function(row) {
|
|
208
|
+
if (row.length === 1 && row[0].type === 'subtable') {
|
|
209
|
+
html += renderSubtableMockup(row[0]);
|
|
210
|
+
} else {
|
|
211
|
+
html += '<div class="mock-form-row">';
|
|
212
|
+
row.forEach(function(field) {
|
|
213
|
+
html += '<div class="mock-form-group">';
|
|
214
|
+
html += '<label class="mock-label">' + escapeHtml(field.label || field.field);
|
|
215
|
+
if (field.required) html += ' <span style="color:var(--error);">*</span>';
|
|
216
|
+
html += '</label>';
|
|
217
|
+
html += renderFormFieldMockup(field);
|
|
218
|
+
html += '</div>';
|
|
219
|
+
});
|
|
214
220
|
html += '</div>';
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
});
|
|
221
|
+
}
|
|
222
|
+
});
|
|
219
223
|
|
|
220
|
-
|
|
221
|
-
|
|
224
|
+
if (fields.length === 0) {
|
|
225
|
+
html += '<div style="padding:2rem;text-align:center;color:var(--text-muted);font-style:italic;">Contenu de l\'onglet « ' + escapeHtml(tab.label) + ' »</div>';
|
|
226
|
+
}
|
|
222
227
|
}
|
|
223
228
|
|
|
224
229
|
html += '</div>';
|
|
@@ -263,20 +268,39 @@ function renderSubtableMockup(field) {
|
|
|
263
268
|
|
|
264
269
|
/* ---------- SmartCard ---------- */
|
|
265
270
|
function renderSmartCardMockup(res) {
|
|
266
|
-
var
|
|
271
|
+
var fields = res.fields || res.columns || [];
|
|
267
272
|
var html = '<div class="mock-header"><span class="mock-title">' + escapeHtml(res.label || 'Cartes') + '</span></div>';
|
|
268
273
|
html += '<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:1rem;">';
|
|
269
274
|
|
|
270
275
|
for (var i = 0; i < 4; i++) {
|
|
271
276
|
html += '<div style="background:var(--bg-hover);border:1px solid var(--border);border-radius:8px;padding:1rem;">';
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
277
|
+
// Title/Subtitle pattern (SmartCard with title + subtitle + fields + actions)
|
|
278
|
+
if (res.title) {
|
|
279
|
+
html += '<div style="font-weight:600;color:var(--text-bright);margin-bottom:0.25rem;">' + escapeHtml(res.title) + ' #' + (i + 1) + '</div>';
|
|
280
|
+
}
|
|
281
|
+
if (res.subtitle) {
|
|
282
|
+
html += '<div style="font-size:0.8rem;color:var(--accent);margin-bottom:0.5rem;">' + escapeHtml(res.subtitle) + '</div>';
|
|
283
|
+
}
|
|
284
|
+
// Fields
|
|
285
|
+
fields.forEach(function(col, ci) {
|
|
286
|
+
var label = col.label || col.field || (typeof col === 'string' ? col : '');
|
|
287
|
+
var iconMap = { calendar: '📅 ', 'dollar-sign': '💰 ', 'alert-circle': '⚠ ', mail: '✉ ', building: '🏢 ', user: '👤 ' };
|
|
288
|
+
var icon = col.icon ? (iconMap[col.icon] || '● ') : '';
|
|
289
|
+
if (!res.title && ci === 0) {
|
|
275
290
|
html += '<div style="font-weight:600;color:var(--text-bright);margin-bottom:0.5rem;">' + escapeHtml(label) + ' #' + (i + 1) + '</div>';
|
|
276
291
|
} else {
|
|
277
|
-
html += '<div style="font-size:0.8rem;color:var(--text-muted);margin-bottom:0.25rem;">' + escapeHtml(label) + ': <span style="color:var(--text);">valeur</span></div>';
|
|
292
|
+
html += '<div style="font-size:0.8rem;color:var(--text-muted);margin-bottom:0.25rem;">' + icon + escapeHtml(label) + ': <span style="color:var(--text);">valeur</span></div>';
|
|
278
293
|
}
|
|
279
294
|
});
|
|
295
|
+
// Actions
|
|
296
|
+
if (res.actions && res.actions.length > 0) {
|
|
297
|
+
html += '<div style="margin-top:0.75rem;display:flex;gap:0.4rem;">';
|
|
298
|
+
res.actions.forEach(function(a) {
|
|
299
|
+
var actionLabel = typeof a === 'string' ? a.replace(/-/g, ' ') : (a.label || a.action || '');
|
|
300
|
+
html += '<span class="mock-btn" style="font-size:0.75rem;">' + escapeHtml(actionLabel) + '</span>';
|
|
301
|
+
});
|
|
302
|
+
html += '</div>';
|
|
303
|
+
}
|
|
280
304
|
html += '</div>';
|
|
281
305
|
}
|
|
282
306
|
html += '</div>';
|
|
@@ -285,7 +309,7 @@ function renderSmartCardMockup(res) {
|
|
|
285
309
|
|
|
286
310
|
/* ---------- SmartKanban ---------- */
|
|
287
311
|
function renderSmartKanbanMockup(res) {
|
|
288
|
-
var options = res.options
|
|
312
|
+
var options = (res.options && res.options.length > 0) ? res.options : (res.columns && res.columns.length > 0) ? res.columns : ['À faire', 'En cours', 'Terminé'];
|
|
289
313
|
var html = '<div class="mock-header"><span class="mock-title">' + escapeHtml(res.label || 'Kanban') + '</span></div>';
|
|
290
314
|
html += '<div style="display:flex;gap:1rem;overflow-x:auto;padding-bottom:0.5rem;">';
|
|
291
315
|
|
|
@@ -359,11 +383,42 @@ function kpiDisplayValue(kpi) {
|
|
|
359
383
|
|
|
360
384
|
/* ---------- SmartFilter ---------- */
|
|
361
385
|
function renderSmartFilterMockup(res) {
|
|
362
|
-
var
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
386
|
+
var filters = res.filters || [];
|
|
387
|
+
if (filters.length === 0) {
|
|
388
|
+
// Fallback: legacy options[] format (tag pills)
|
|
389
|
+
var options = res.options || [];
|
|
390
|
+
if (options.length === 0) return '<div style="padding:1rem;text-align:center;color:var(--text-muted);">Aucun filtre défini</div>';
|
|
391
|
+
var html = '<div style="display:flex;gap:0.4rem;flex-wrap:wrap;padding:0.5rem 0;">';
|
|
392
|
+
html += '<span style="padding:0.3rem 0.7rem;border-radius:16px;font-size:0.8rem;background:var(--primary);color:#fff;cursor:pointer;">Tous</span>';
|
|
393
|
+
options.forEach(function(opt) {
|
|
394
|
+
html += '<span style="padding:0.3rem 0.7rem;border-radius:16px;font-size:0.8rem;background:var(--bg-hover);color:var(--text);border:1px solid var(--border);cursor:pointer;">' + escapeHtml(typeof opt === 'string' ? opt : opt.label || '') + '</span>';
|
|
395
|
+
});
|
|
396
|
+
html += '</div>';
|
|
397
|
+
return html;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Rich filter bar: render each filter based on its type
|
|
401
|
+
var html = '<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:flex-end;padding:0.5rem 0;">';
|
|
402
|
+
filters.forEach(function(f) {
|
|
403
|
+
var label = typeof f === 'string' ? f : (f.label || f.field || '');
|
|
404
|
+
var type = typeof f === 'string' ? 'text' : (f.type || 'text');
|
|
405
|
+
html += '<div style="display:flex;flex-direction:column;gap:0.2rem;">';
|
|
406
|
+
html += '<span style="font-size:0.7rem;color:var(--text-muted);">' + escapeHtml(label) + '</span>';
|
|
407
|
+
switch (type) {
|
|
408
|
+
case 'select':
|
|
409
|
+
var opts = f.options || ['Option 1', 'Option 2'];
|
|
410
|
+
html += '<span class="mock-input" style="width:auto;min-width:130px;font-size:0.8rem;color:var(--text-muted);">' + escapeHtml(opts[0]) + ' ▾</span>';
|
|
411
|
+
break;
|
|
412
|
+
case 'lookup':
|
|
413
|
+
html += '<span class="mock-input" style="width:auto;min-width:130px;font-size:0.8rem;color:var(--accent);">' + escapeHtml(f.entity || label) + ' 🔍</span>';
|
|
414
|
+
break;
|
|
415
|
+
case 'daterange':
|
|
416
|
+
html += '<span class="mock-input" style="width:auto;min-width:180px;font-size:0.8rem;color:var(--text-muted);">01/01/2025 — 31/12/2025 📅</span>';
|
|
417
|
+
break;
|
|
418
|
+
default:
|
|
419
|
+
html += '<span class="mock-input" style="width:auto;min-width:160px;font-size:0.8rem;color:var(--text-muted);">Rechercher... 🔍</span>';
|
|
420
|
+
}
|
|
421
|
+
html += '</div>';
|
|
367
422
|
});
|
|
368
423
|
html += '</div>';
|
|
369
424
|
return html;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/* ==========================================
|
|
2
|
+
MERMAID DIAGRAM RENDERING
|
|
3
|
+
Renders ERD, state machines, and sequence diagrams
|
|
4
|
+
from consolidation.mermaidDiagrams data.
|
|
5
|
+
========================================== */
|
|
6
|
+
|
|
7
|
+
function renderMermaidDiagrams() {
|
|
8
|
+
const data = window.FEATURE_DATA;
|
|
9
|
+
if (!data) return;
|
|
10
|
+
|
|
11
|
+
const diagrams = data.consolidation?.mermaidDiagrams;
|
|
12
|
+
if (!diagrams) return;
|
|
13
|
+
|
|
14
|
+
// 1. ERD in consol-datamodel (prepend before entity cards)
|
|
15
|
+
if (diagrams.erd) {
|
|
16
|
+
const erdContainer = document.getElementById('dataModelContainer');
|
|
17
|
+
if (erdContainer) {
|
|
18
|
+
const erdDiv = document.createElement('div');
|
|
19
|
+
erdDiv.className = 'diagram-container diagram-erd';
|
|
20
|
+
erdDiv.innerHTML =
|
|
21
|
+
'<div class="diagram-section-header">Diagramme Entit\u00e9-Relation (ERD)</div>' +
|
|
22
|
+
'<div class="mermaid">' + escapeHtml(diagrams.erd) + '</div>';
|
|
23
|
+
erdContainer.insertBefore(erdDiv, erdContainer.firstChild);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 2. State machine diagrams — inject in module spec sections or consol-datamodel
|
|
28
|
+
if (diagrams.stateMachines && Object.keys(diagrams.stateMachines).length > 0) {
|
|
29
|
+
const smContainer = document.getElementById('dataModelContainer');
|
|
30
|
+
if (smContainer) {
|
|
31
|
+
const smSection = document.createElement('div');
|
|
32
|
+
smSection.innerHTML = '<div class="diagram-section-header">Cycles de vie (State Machines)</div>';
|
|
33
|
+
|
|
34
|
+
Object.entries(diagrams.stateMachines).forEach(function(entry) {
|
|
35
|
+
var entity = entry[0];
|
|
36
|
+
var def = entry[1];
|
|
37
|
+
var smDiv = document.createElement('div');
|
|
38
|
+
smDiv.className = 'diagram-container diagram-state-machine';
|
|
39
|
+
smDiv.innerHTML =
|
|
40
|
+
'<h4>' + escapeHtml(entity) + '</h4>' +
|
|
41
|
+
'<div class="mermaid">' + escapeHtml(def) + '</div>';
|
|
42
|
+
smSection.appendChild(smDiv);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
smContainer.appendChild(smSection);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 3. Sequence diagrams in consol-flows
|
|
50
|
+
if (diagrams.sequences && Object.keys(diagrams.sequences).length > 0) {
|
|
51
|
+
var flowsContainer = document.getElementById('consolFlowsContainer');
|
|
52
|
+
// Fallback: try the consol-flows section
|
|
53
|
+
if (!flowsContainer) {
|
|
54
|
+
var consolFlows = document.getElementById('consol-flows');
|
|
55
|
+
if (consolFlows) {
|
|
56
|
+
flowsContainer = consolFlows.querySelector('.section-body') || consolFlows;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (flowsContainer) {
|
|
61
|
+
var seqSection = document.createElement('div');
|
|
62
|
+
seqSection.innerHTML = '<div class="diagram-section-header">Diagrammes de s\u00e9quence</div>';
|
|
63
|
+
|
|
64
|
+
Object.entries(diagrams.sequences).forEach(function(entry) {
|
|
65
|
+
var flowName = entry[0];
|
|
66
|
+
var def = entry[1];
|
|
67
|
+
var seqDiv = document.createElement('div');
|
|
68
|
+
seqDiv.className = 'diagram-container diagram-sequence';
|
|
69
|
+
seqDiv.innerHTML =
|
|
70
|
+
'<h4>' + escapeHtml(flowName) + '</h4>' +
|
|
71
|
+
'<div class="mermaid">' + escapeHtml(def) + '</div>';
|
|
72
|
+
seqSection.appendChild(seqDiv);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
flowsContainer.appendChild(seqSection);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 4. Render all mermaid elements
|
|
80
|
+
try {
|
|
81
|
+
if (typeof mermaid !== 'undefined' && mermaid.run) {
|
|
82
|
+
mermaid.run({ querySelector: '.mermaid' });
|
|
83
|
+
}
|
|
84
|
+
} catch (e) {
|
|
85
|
+
console.warn('Mermaid rendering failed:', e);
|
|
86
|
+
// Fallback: show raw text
|
|
87
|
+
document.querySelectorAll('.mermaid').forEach(function(el) {
|
|
88
|
+
if (!el.querySelector('svg')) {
|
|
89
|
+
el.style.whiteSpace = 'pre-wrap';
|
|
90
|
+
el.style.fontFamily = 'monospace';
|
|
91
|
+
el.style.fontSize = '0.85rem';
|
|
92
|
+
el.style.color = 'var(--text-muted)';
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Escape HTML for safe injection
|
|
99
|
+
function escapeHtml(text) {
|
|
100
|
+
if (!text) return '';
|
|
101
|
+
// For mermaid content, we need to preserve the syntax
|
|
102
|
+
// Only escape actual HTML tags, not mermaid arrows
|
|
103
|
+
return text.replace(/</g, '<').replace(/>/g, '>');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Auto-run after consolidation rendering
|
|
107
|
+
(function() {
|
|
108
|
+
// Wait for DOM and other render functions to complete
|
|
109
|
+
if (document.readyState === 'loading') {
|
|
110
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
111
|
+
setTimeout(renderMermaidDiagrams, 500);
|
|
112
|
+
});
|
|
113
|
+
} else {
|
|
114
|
+
setTimeout(renderMermaidDiagrams, 500);
|
|
115
|
+
}
|
|
116
|
+
})();
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* ==========================================
|
|
2
|
+
MERMAID DIAGRAMS
|
|
3
|
+
========================================== */
|
|
4
|
+
|
|
5
|
+
.diagram-container {
|
|
6
|
+
margin: 1.5rem 0;
|
|
7
|
+
padding: 1rem;
|
|
8
|
+
background: var(--bg-card);
|
|
9
|
+
border-radius: 8px;
|
|
10
|
+
border: 1px solid var(--border);
|
|
11
|
+
overflow-x: auto;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.diagram-container h3,
|
|
15
|
+
.diagram-container h4 {
|
|
16
|
+
color: var(--text-bright);
|
|
17
|
+
margin-bottom: 1rem;
|
|
18
|
+
font-size: 1.1rem;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.diagram-container .mermaid {
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
min-height: 200px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.diagram-container .mermaid svg {
|
|
28
|
+
max-width: 100%;
|
|
29
|
+
height: auto;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* ERD specific */
|
|
33
|
+
.diagram-erd {
|
|
34
|
+
margin-bottom: 2rem;
|
|
35
|
+
border-left: 3px solid var(--primary);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* State machine specific */
|
|
39
|
+
.diagram-state-machine {
|
|
40
|
+
border-left: 3px solid var(--accent);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Sequence diagram specific */
|
|
44
|
+
.diagram-sequence {
|
|
45
|
+
border-left: 3px solid var(--success);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Diagram section header */
|
|
49
|
+
.diagram-section-header {
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 0.5rem;
|
|
53
|
+
margin-bottom: 1rem;
|
|
54
|
+
color: var(--text-bright);
|
|
55
|
+
font-size: 1.2rem;
|
|
56
|
+
font-weight: 600;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.diagram-section-header::before {
|
|
60
|
+
content: '';
|
|
61
|
+
width: 4px;
|
|
62
|
+
height: 1.2em;
|
|
63
|
+
background: var(--primary);
|
|
64
|
+
border-radius: 2px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* No diagrams fallback */
|
|
68
|
+
.diagram-empty {
|
|
69
|
+
color: var(--text-muted);
|
|
70
|
+
font-style: italic;
|
|
71
|
+
padding: 1rem;
|
|
72
|
+
text-align: center;
|
|
73
|
+
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>{{APPLICATION_NAME}} - Analyse métier</title>
|
|
7
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
|
|
8
|
+
<script>mermaid.initialize({ startOnLoad: false, theme: 'dark', securityLevel: 'loose' });</script>
|
|
7
9
|
<style>
|
|
8
10
|
<!-- CSS_PLACEHOLDER -->
|
|
9
11
|
</style>
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Reference: EMBEDDED_ARTIFACTS Building Details
|
|
2
|
+
|
|
3
|
+
## wireframes{} — per moduleCode
|
|
4
|
+
|
|
5
|
+
### Architecture: Flat File + Nested Structures
|
|
6
|
+
|
|
7
|
+
**FLAT-FILE:** Wireframes come from `screens.json` in each module directory (collected in step-01),
|
|
8
|
+
NOT from `moduleFeature.specification.uiWireframes`.
|
|
9
|
+
|
|
10
|
+
### STEP 1: Collect wireframe sources from BOTH flat and nested structures
|
|
11
|
+
|
|
12
|
+
```javascript
|
|
13
|
+
const mod = collected_data.modules[moduleCode];
|
|
14
|
+
|
|
15
|
+
// Flat: mod.screens.screens[] with mockupFormat/mockup at top level
|
|
16
|
+
// Nested: mod.screens.sections[].resources[].wireframe (design step output)
|
|
17
|
+
let rawWireframes = [];
|
|
18
|
+
|
|
19
|
+
// Source A: flat screens[] array (original BA output or manually enriched)
|
|
20
|
+
const flatScreens = mod.screens?.screens || [];
|
|
21
|
+
rawWireframes.push(...flatScreens.filter(s => s.mockup || s.mockupFormat));
|
|
22
|
+
|
|
23
|
+
// Source B: nested sections[].resources[].wireframe (design step output)
|
|
24
|
+
const sections = mod.screens?.sections || [];
|
|
25
|
+
for (const section of sections) {
|
|
26
|
+
// B1: wireframe directly on section (ba-004 style: sections[].wireframe)
|
|
27
|
+
if (section.wireframe) {
|
|
28
|
+
rawWireframes.push({
|
|
29
|
+
...section.wireframe,
|
|
30
|
+
section: section.wireframe.section || section.id || section.code || section.sectionCode || "",
|
|
31
|
+
screen: section.wireframe.screen || section.id || section.code || section.sectionCode || ""
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
// B2: wireframe on resources (nested: sections[].resources[].wireframe)
|
|
35
|
+
for (const resource of (section.resources || [])) {
|
|
36
|
+
if (resource.wireframe) {
|
|
37
|
+
rawWireframes.push({
|
|
38
|
+
...resource.wireframe,
|
|
39
|
+
section: resource.wireframe.section || section.sectionCode || section.id || "",
|
|
40
|
+
screen: resource.wireframe.screen || `${section.sectionCode || section.id}-${resource.code}` || ""
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Source C: screens/sections without mockup → auto-generate text description as wireframe fallback
|
|
47
|
+
// C1: from flat screens[]
|
|
48
|
+
const screensWithoutMockup = flatScreens.filter(s => !s.mockup && !s.mockupFormat);
|
|
49
|
+
// C2: from sections[] (ba-004 style) — sections without wireframe property
|
|
50
|
+
const sectionsWithoutWireframe = sections.filter(s => !s.wireframe);
|
|
51
|
+
const allNoMockup = [
|
|
52
|
+
...screensWithoutMockup.map(s => ({
|
|
53
|
+
type: s.componentType || "", columns: s.columns || [], tabs: s.tabs || [],
|
|
54
|
+
kpis: s.kpis || [], screen: s.screen || "", section: s.section || "",
|
|
55
|
+
description: s.sectionDescription || ""
|
|
56
|
+
})),
|
|
57
|
+
...sectionsWithoutWireframe.map(s => ({
|
|
58
|
+
type: s.layout || s.componentType || "", columns: s.columns || [], tabs: s.tabs || [],
|
|
59
|
+
kpis: s.kpis || [], screen: s.id || s.code || "", section: s.id || s.code || "",
|
|
60
|
+
description: s.description || ""
|
|
61
|
+
}))
|
|
62
|
+
];
|
|
63
|
+
for (const screen of allNoMockup) {
|
|
64
|
+
const type = screen.type;
|
|
65
|
+
let desc = "";
|
|
66
|
+
if (type.includes("Table") || type.includes("Grid")) {
|
|
67
|
+
const cols = screen.columns;
|
|
68
|
+
desc = "Tableau avec " + cols.length + " colonnes : " + cols.map(c => c.label || c.displayName || c.code || c.name).join(", ");
|
|
69
|
+
} else if (type.includes("Form")) {
|
|
70
|
+
const tabs = screen.tabs;
|
|
71
|
+
desc = "Formulaire " + (tabs.length > 0 ? "avec " + tabs.length + " onglet(s)" : "");
|
|
72
|
+
} else if (type.includes("Dashboard")) {
|
|
73
|
+
desc = "Tableau de bord avec " + (screen.kpis.length || "") + " KPIs";
|
|
74
|
+
} else if (type.includes("Kanban")) {
|
|
75
|
+
desc = "Vue Kanban";
|
|
76
|
+
}
|
|
77
|
+
if (desc) {
|
|
78
|
+
rawWireframes.push({
|
|
79
|
+
screen: screen.screen, section: screen.section,
|
|
80
|
+
mockupFormat: "text", mockup: desc,
|
|
81
|
+
description: screen.description, elements: [], componentMapping: []
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### STEP 2: Map to HTML format (RENAME: mockupFormat → format, mockup → content)
|
|
88
|
+
|
|
89
|
+
**FIELD RENAME WARNING:** Module JSON uses `mockupFormat`/`mockup`. HTML reads `format`/`content`. You MUST rename.
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
wireframes: {
|
|
93
|
+
[moduleCode]: rawWireframes.map(wf => ({
|
|
94
|
+
screen: wf.screen || wf.name || wf.title || wf.id || "",
|
|
95
|
+
section: wf.section || "",
|
|
96
|
+
format: wf.mockupFormat || "ascii", // RENAME: mockupFormat → format
|
|
97
|
+
content: wf.mockup || wf.ascii || wf.content || "", // RENAME: mockup → content
|
|
98
|
+
svgContent: null,
|
|
99
|
+
description: wf.description || "",
|
|
100
|
+
elements: wf.elements || [],
|
|
101
|
+
actions: wf.actions || [],
|
|
102
|
+
componentMapping: Array.isArray(wf.componentMapping)
|
|
103
|
+
? wf.componentMapping.map(function(entry) {
|
|
104
|
+
if (entry.wireframeElement && entry.reactComponent) return entry; // canonical
|
|
105
|
+
// Shorthand: [{key: value}] → {wireframeElement, reactComponent}
|
|
106
|
+
var keys = Object.keys(entry);
|
|
107
|
+
if (keys.length === 1 && !entry.wireframeElement) {
|
|
108
|
+
return { wireframeElement: keys[0], reactComponent: entry[keys[0]] };
|
|
109
|
+
}
|
|
110
|
+
return entry;
|
|
111
|
+
})
|
|
112
|
+
: typeof wf.componentMapping === 'object' && wf.componentMapping !== null
|
|
113
|
+
? Object.entries(wf.componentMapping).map(([k, v]) => ({ wireframeElement: k, reactComponent: v }))
|
|
114
|
+
: [],
|
|
115
|
+
layout: typeof wf.layout === 'object' ? wf.layout : null,
|
|
116
|
+
permissionsRequired: wf.permissionsRequired || []
|
|
117
|
+
}))
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## e2eFlows[]
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
e2eFlows: (master.consolidation?.e2eFlows || []).map(flow => ({
|
|
125
|
+
name: flow.name,
|
|
126
|
+
diagram: flow.steps.map(s => s.action + "(" + s.module + ")").join(" ──→ "),
|
|
127
|
+
steps: flow.steps || [],
|
|
128
|
+
actors: [...new Set(flow.steps.map(s => s.permission?.split(".")[0]).filter(Boolean))].join(", "),
|
|
129
|
+
modules: [...new Set(flow.steps.map(s => s.module))].join(" → ")
|
|
130
|
+
}))
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## dependencyGraph
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
dependencyGraph: {
|
|
137
|
+
nodes: (master.modules || []).map(m => ({
|
|
138
|
+
id: m.code, label: m.code, type: m.featureType || "data-centric"
|
|
139
|
+
})),
|
|
140
|
+
edges: (master.dependencyGraph?.edges || []).map(e => ({
|
|
141
|
+
from: e.from, to: e.to, description: e.description || ""
|
|
142
|
+
}))
|
|
143
|
+
}
|
|
144
|
+
```
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Reference: FEATURE_DATA Building Details
|
|
2
|
+
|
|
3
|
+
## moduleSpecs{} — ONE entry per module (CRITICAL)
|
|
4
|
+
|
|
5
|
+
### Architecture: Flat File Data Collection
|
|
6
|
+
|
|
7
|
+
**FLAT-FILE ARCHITECTURE:** Module data comes from separate JSON files collected in step-01,
|
|
8
|
+
NOT from index.json fields. Use `collected_data.modules[moduleCode].entities`, `.usecases`, etc.
|
|
9
|
+
|
|
10
|
+
For EACH module, use the flat file data from `collected_data.modules[moduleCode]`:
|
|
11
|
+
|
|
12
|
+
```javascript
|
|
13
|
+
const mod = collected_data.modules[moduleCode];
|
|
14
|
+
|
|
15
|
+
// NORMALIZE: usecases.json may use "useCases" (camelCase) or "usecases" (lowercase)
|
|
16
|
+
const rawUCs = mod.usecases?.useCases || mod.usecases?.usecases || [];
|
|
17
|
+
// NORMALIZE: rules.json may use "rules" or "businessRules"
|
|
18
|
+
const rawBRs = mod.rules?.rules || mod.rules?.businessRules || [];
|
|
19
|
+
|
|
20
|
+
moduleSpecs[moduleCode] = {
|
|
21
|
+
useCases: rawUCs.map(uc => ({
|
|
22
|
+
name: uc.name || uc.title || uc.id || "",
|
|
23
|
+
sectionCode: uc.sectionCode || "",
|
|
24
|
+
actor: uc.primaryActor || uc.actor || "",
|
|
25
|
+
// SAFETY NET: steps may be strings[] (mainScenario) or objects[] ({step, action})
|
|
26
|
+
steps: (uc.mainScenario || uc.steps || []).map(s =>
|
|
27
|
+
typeof s === 'string' ? s : (s.action || s.description || "")
|
|
28
|
+
).join("\n"),
|
|
29
|
+
alternative: (uc.alternativeScenarios || uc.alternativeFlows || []).map(a =>
|
|
30
|
+
(a.name || a.trigger || "") + ": " + (a.steps || a.actions || []).map(s =>
|
|
31
|
+
typeof s === 'string' ? s : (s.action || s.description || "")
|
|
32
|
+
).join(", ")
|
|
33
|
+
).join("\n")
|
|
34
|
+
})),
|
|
35
|
+
businessRules: rawBRs.map(br => ({
|
|
36
|
+
name: br.name || br.id || "",
|
|
37
|
+
sectionCode: br.sectionCode || "",
|
|
38
|
+
category: br.category || "",
|
|
39
|
+
statement: br.statement || br.description || "",
|
|
40
|
+
example: (br.examples || []).map(e =>
|
|
41
|
+
typeof e === 'string' ? e : ((e.input || "") + " → " + (e.expected || ""))
|
|
42
|
+
).join("; ")
|
|
43
|
+
})),
|
|
44
|
+
// ENTITY SAFETY NET: map fields[] → attributes[] if agent deviated
|
|
45
|
+
entities: (mod.entities?.entities || []).map(ent => ({
|
|
46
|
+
name: ent.name,
|
|
47
|
+
description: ent.description || "",
|
|
48
|
+
attributes: (ent.attributes || []).length > 0
|
|
49
|
+
? ent.attributes.map(a => ({ name: a.name, type: a.type || "string", required: a.required || false, description: a.description || "" }))
|
|
50
|
+
: (ent.fields || []).map(f => ({ name: f.name, type: f.type || "string", required: f.required || false, description: f.description || "" })),
|
|
51
|
+
relationships: (ent.relationships || []).map(r =>
|
|
52
|
+
typeof r === 'string' ? r : r.target + " (" + r.type + ") - " + (r.description || ""))
|
|
53
|
+
})),
|
|
54
|
+
permissions: buildPermissionKeys(mod.permissions),
|
|
55
|
+
apiEndpoints: mod.usecases?.apiEndpoints || []
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Building screens[] for HTML Interactive Mockups
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
// BUILD screens[] for HTML interactive mockups — use helpers and format detection from references
|
|
63
|
+
const flatScr = mod.screens?.screens || [];
|
|
64
|
+
const sectionScr = mod.screens?.sections || [];
|
|
65
|
+
let screens = [];
|
|
66
|
+
|
|
67
|
+
// Apply normalization helpers from references/02-normalization-helpers.md
|
|
68
|
+
// Apply format detection from references/02-screen-format-detection.md
|
|
69
|
+
|
|
70
|
+
moduleSpecs[moduleCode].screens = screens;
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Enrich anticipatedSections with section-level UC/BR
|
|
74
|
+
|
|
75
|
+
**CRITICAL for HTML viewer to display UC/BR grouped by section.**
|
|
76
|
+
|
|
77
|
+
Execute AFTER moduleSpecs is built:
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
// Post-processing: populate each section's useCases[] and businessRules[]
|
|
81
|
+
// using the sectionCode field from moduleSpecs
|
|
82
|
+
FEATURE_DATA.modules.forEach(m => {
|
|
83
|
+
const spec = FEATURE_DATA.moduleSpecs[m.code];
|
|
84
|
+
if (!spec) return;
|
|
85
|
+
(m.anticipatedSections || []).forEach(section => {
|
|
86
|
+
section.useCases = (spec.useCases || []).filter(uc => uc.sectionCode === section.code);
|
|
87
|
+
section.businessRules = (spec.businessRules || []).filter(br => br.sectionCode === section.code);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Top-Level Fields: dependencies, consolidation, handoff
|
|
93
|
+
|
|
94
|
+
### dependencies[] (TOP-LEVEL — CRITICAL for HTML navigation)
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
dependencies: (master.consolidation?.crossModuleInteractions || master.dependencyGraph?.edges || []).map(i => ({
|
|
98
|
+
from: i.fromModule || i.from || "",
|
|
99
|
+
to: i.toModule || i.to || "",
|
|
100
|
+
description: i.description || ""
|
|
101
|
+
}))
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**WARNING:** `data.dependencies` is used by the sidebar (navigation), module rendering, consolidation views,
|
|
105
|
+
handoff summary, and export. If this array is missing, the entire HTML page crashes with a TypeError.
|
|
106
|
+
ALWAYS include it, even if empty (`dependencies: []`).
|
|
107
|
+
|
|
108
|
+
### consolidation
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
consolidation: {
|
|
112
|
+
interactions: (master.consolidation?.crossModuleInteractions || []).map(i => ({
|
|
113
|
+
from: i.fromModule,
|
|
114
|
+
to: i.toModule,
|
|
115
|
+
description: i.description || ""
|
|
116
|
+
})),
|
|
117
|
+
sharedEntities: master.consolidation?.sharedEntities || [],
|
|
118
|
+
e2eFlows: (master.consolidation?.e2eFlows || []).map(f => ({
|
|
119
|
+
name: f.name,
|
|
120
|
+
steps: (f.steps || []).map(s => ({ module: s.module, action: s.action })),
|
|
121
|
+
actors: (f.steps || []).map(s => s.permission).join(", ")
|
|
122
|
+
}))
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### handoff
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
handoff: {
|
|
130
|
+
complexity: master.handoff?.complexity,
|
|
131
|
+
implementationStrategy: master.handoff?.implementationStrategy,
|
|
132
|
+
moduleOrder: master.handoff?.moduleOrder,
|
|
133
|
+
filesToCreate: master.handoff?.filesToCreate,
|
|
134
|
+
brToCodeMapping: master.handoff?.brToCodeMapping,
|
|
135
|
+
apiEndpointSummary: master.handoff?.apiEndpointSummary
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Helper Function: buildPermissionKeys()
|
|
140
|
+
|
|
141
|
+
See `references/data-mapping.md` for `buildPermissionKeys()` implementation.
|