@atlashub/smartstack-cli 4.18.0 → 4.20.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 (164) hide show
  1. package/package.json +1 -1
  2. package/templates/agents/ba-reader.md +86 -80
  3. package/templates/agents/ba-writer.md +318 -415
  4. package/templates/agents/docs-context-reader.md +3 -3
  5. package/templates/mcp-scaffolding/frontend/nav-routes.ts.hbs +133 -0
  6. package/templates/mcp-scaffolding/frontend/routes.tsx.hbs +126 -0
  7. package/templates/skills/apex/SKILL.md +29 -16
  8. package/templates/skills/apex/_shared.md +62 -9
  9. package/templates/skills/apex/references/analysis-methods.md +8 -6
  10. package/templates/skills/apex/references/challenge-questions.md +5 -5
  11. package/templates/skills/apex/references/core-seed-data.md +68 -45
  12. package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +26 -21
  13. package/templates/skills/apex/references/parallel-execution.md +156 -0
  14. package/templates/skills/apex/references/person-extension-pattern.md +12 -12
  15. package/templates/skills/apex/references/post-checks.md +1748 -1726
  16. package/templates/skills/apex/references/smartstack-api.md +63 -57
  17. package/templates/skills/apex/references/smartstack-frontend-compliance.md +594 -0
  18. package/templates/skills/apex/references/smartstack-frontend.md +1246 -1842
  19. package/templates/skills/apex/references/smartstack-layers.md +98 -145
  20. package/templates/skills/apex/steps/step-00-init.md +30 -6
  21. package/templates/skills/apex/steps/step-01-analyze.md +27 -23
  22. package/templates/skills/apex/steps/step-02-plan.md +12 -12
  23. package/templates/skills/apex/steps/step-03-execute.md +198 -143
  24. package/templates/skills/apex/steps/step-04-examine.md +24 -93
  25. package/templates/skills/apex/steps/step-05-deep-review.md +16 -16
  26. package/templates/skills/apex/steps/step-06-resolve.md +9 -9
  27. package/templates/skills/apex/steps/step-07-tests.md +3 -1
  28. package/templates/skills/apex/steps/step-08-run-tests.md +1 -1
  29. package/templates/skills/business-analyse/SKILL.md +182 -301
  30. package/templates/skills/business-analyse/_shared.md +119 -336
  31. package/templates/skills/business-analyse/html/ba-interactive.html +706 -85
  32. package/templates/skills/business-analyse/html/build-html.js +41 -3
  33. package/templates/skills/business-analyse/html/src/partials/cadrage-context.html +34 -0
  34. package/templates/skills/business-analyse/html/src/partials/cadrage-risks.html +48 -0
  35. package/templates/skills/business-analyse/html/src/partials/cadrage-scope.html +49 -0
  36. package/templates/skills/business-analyse/html/src/partials/cadrage-stakeholders.html +55 -0
  37. package/templates/skills/business-analyse/html/src/partials/cadrage-success.html +34 -0
  38. package/templates/skills/business-analyse/html/src/partials/consol-datamodel.html +8 -0
  39. package/templates/skills/business-analyse/html/src/partials/consol-flows.html +29 -0
  40. package/templates/skills/business-analyse/html/src/partials/consol-interactions.html +8 -0
  41. package/templates/skills/business-analyse/html/src/partials/consol-permissions.html +8 -0
  42. package/templates/skills/business-analyse/html/src/partials/decomp-dependencies.html +38 -0
  43. package/templates/skills/business-analyse/html/src/partials/decomp-modules.html +51 -0
  44. package/templates/skills/business-analyse/html/src/partials/handoff-summary.html +24 -0
  45. package/templates/skills/business-analyse/html/src/partials/module-spec-container.html +4 -0
  46. package/templates/skills/business-analyse/html/src/scripts/01-data-init.js +17 -1
  47. package/templates/skills/business-analyse/html/src/scripts/02-navigation.js +32 -6
  48. package/templates/skills/business-analyse/html/src/scripts/05-render-specs.js +100 -63
  49. package/templates/skills/business-analyse/html/src/scripts/06-render-mockups.js +372 -0
  50. package/templates/skills/business-analyse/html/src/scripts/07-render-handoff.js +1 -1
  51. package/templates/skills/business-analyse/html/src/scripts/10-comments.js +41 -13
  52. package/templates/skills/business-analyse/html/src/styles/09-mockups-html.css +136 -0
  53. package/templates/skills/business-analyse/html/src/template.html +1 -1
  54. package/templates/skills/business-analyse/patterns/suggestion-catalog.md +7 -5
  55. package/templates/skills/business-analyse/questionnaire/01-context.md +11 -157
  56. package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +101 -0
  57. package/templates/skills/business-analyse/questionnaire/03-data-ui.md +92 -0
  58. package/templates/skills/business-analyse/questionnaire/04-risks-metrics.md +6 -0
  59. package/templates/skills/business-analyse/questionnaire/05-cross-module.md +69 -0
  60. package/templates/skills/business-analyse/questionnaire.md +22 -280
  61. package/templates/skills/business-analyse/react/application-viewer.md +2 -2
  62. package/templates/skills/business-analyse/react/components.md +4 -4
  63. package/templates/skills/business-analyse/react/i18n-template.md +1 -1
  64. package/templates/skills/business-analyse/react/schema.md +14 -14
  65. package/templates/skills/business-analyse/references/acceptance-criteria.md +21 -21
  66. package/templates/skills/business-analyse/references/analysis-semantic-checks.md +3 -3
  67. package/templates/skills/business-analyse/references/compilation-structure-cards.md +1 -1
  68. package/templates/skills/business-analyse/references/consolidation-structural-checks.md +5 -5
  69. package/templates/skills/business-analyse/references/deploy-data-build.md +12 -11
  70. package/templates/skills/business-analyse/references/deploy-modes.md +10 -10
  71. package/templates/skills/business-analyse/references/detection-strategies.md +6 -6
  72. package/templates/skills/business-analyse/references/html-data-mapping.md +15 -15
  73. package/templates/skills/business-analyse/references/naming-conventions.md +4 -4
  74. package/templates/skills/business-analyse/references/review-data-mapping.md +29 -29
  75. package/templates/skills/business-analyse/references/robustness-checks.md +36 -36
  76. package/templates/skills/business-analyse/references/spec-auto-inference.md +2 -2
  77. package/templates/skills/business-analyse/references/ui-dashboard-spec.md +1 -1
  78. package/templates/skills/business-analyse/references/ui-resource-cards.md +1 -1
  79. package/templates/skills/business-analyse/references/validation-checklist.md +3 -3
  80. package/templates/skills/business-analyse/references/wireframe-svg-style-guide.md +2 -2
  81. package/templates/skills/business-analyse/schemas/application-schema.json +8 -8
  82. package/templates/skills/business-analyse/schemas/feature-schema.json +3 -3
  83. package/templates/skills/business-analyse/schemas/index-schema.json +47 -0
  84. package/templates/skills/business-analyse/schemas/project-schema.json +6 -6
  85. package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +1 -1
  86. package/templates/skills/business-analyse/schemas/sections/handoff-schema.json +5 -3
  87. package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +4 -4
  88. package/templates/skills/business-analyse/schemas/sections/specification-schema.json +1 -1
  89. package/templates/skills/business-analyse/schemas/shared/common-defs.json +4 -4
  90. package/templates/skills/business-analyse/steps/step-00-init.md +68 -77
  91. package/templates/skills/business-analyse/steps/step-01-cadrage.md +50 -216
  92. package/templates/skills/business-analyse/steps/step-02-structure.md +175 -0
  93. package/templates/skills/business-analyse/steps/step-03-specify.md +198 -0
  94. package/templates/skills/business-analyse/steps/step-04-consolidate.md +478 -0
  95. package/templates/skills/business-analyse/steps/step-05-deploy.md +220 -0
  96. package/templates/skills/business-analyse/steps/step-06-review.md +51 -69
  97. package/templates/skills/business-analyse/templates/tpl-frd.md +1 -1
  98. package/templates/skills/business-analyse/templates/tpl-handoff.md +20 -17
  99. package/templates/skills/business-analyse/templates/tpl-launch-displays.md +2 -2
  100. package/templates/skills/business-analyse/templates-react.md +2 -2
  101. package/templates/skills/derive-prd/SKILL.md +92 -0
  102. package/templates/skills/derive-prd/references/acceptance-criteria.md +169 -0
  103. package/templates/skills/derive-prd/references/entity-domain-mapping.md +115 -0
  104. package/templates/skills/{business-analyse → derive-prd}/references/handoff-file-templates.md +131 -120
  105. package/templates/skills/{business-analyse → derive-prd}/references/handoff-mappings.md +95 -95
  106. package/templates/skills/{business-analyse → derive-prd}/references/handoff-seeddata-generation.md +312 -312
  107. package/templates/skills/{business-analyse → derive-prd}/references/prd-generation.md +262 -263
  108. package/templates/skills/derive-prd/references/readiness-scoring.md +104 -0
  109. package/templates/skills/derive-prd/schemas/handoff-schema.json +95 -0
  110. package/templates/skills/derive-prd/steps/step-00-validate.md +130 -0
  111. package/templates/skills/derive-prd/steps/step-01-transform.md +206 -0
  112. package/templates/skills/derive-prd/steps/step-02-export.md +181 -0
  113. package/templates/skills/{business-analyse → derive-prd}/templates/tpl-progress.md +172 -172
  114. package/templates/skills/documentation/SKILL.md +7 -0
  115. package/templates/skills/ralph-loop/SKILL.md +2 -1
  116. package/templates/skills/ralph-loop/references/init-resume-recovery.md +1 -1
  117. package/templates/skills/ralph-loop/steps/step-01-task.md +2 -2
  118. package/templates/skills/apex/references/agent-teams-protocol.md +0 -203
  119. package/templates/skills/business-analyse/_architecture.md +0 -124
  120. package/templates/skills/business-analyse/_elicitation.md +0 -206
  121. package/templates/skills/business-analyse/_module-loop.md +0 -115
  122. package/templates/skills/business-analyse/_rules.md +0 -142
  123. package/templates/skills/business-analyse/_suggestions.md +0 -34
  124. package/templates/skills/business-analyse/questionnaire/00-application.md +0 -160
  125. package/templates/skills/business-analyse/questionnaire/00b-project.md +0 -85
  126. package/templates/skills/business-analyse/questionnaire/02-stakeholders.md +0 -189
  127. package/templates/skills/business-analyse/questionnaire/03-scope.md +0 -164
  128. package/templates/skills/business-analyse/questionnaire/04-data.md +0 -88
  129. package/templates/skills/business-analyse/questionnaire/05-integrations.md +0 -58
  130. package/templates/skills/business-analyse/questionnaire/06-security.md +0 -68
  131. package/templates/skills/business-analyse/questionnaire/07-ui.md +0 -76
  132. package/templates/skills/business-analyse/questionnaire/08-performance.md +0 -42
  133. package/templates/skills/business-analyse/questionnaire/09-constraints.md +0 -45
  134. package/templates/skills/business-analyse/questionnaire/10-documentation.md +0 -58
  135. package/templates/skills/business-analyse/questionnaire/11-data-lifecycle.md +0 -59
  136. package/templates/skills/business-analyse/questionnaire/12-migration.md +0 -58
  137. package/templates/skills/business-analyse/questionnaire/13-cross-module.md +0 -69
  138. package/templates/skills/business-analyse/questionnaire/14-risk-assumptions.md +0 -135
  139. package/templates/skills/business-analyse/questionnaire/15-success-metrics.md +0 -136
  140. package/templates/skills/business-analyse/references/agent-module-prompt.md +0 -366
  141. package/templates/skills/business-analyse/references/agent-pooling-best-practices.md +0 -557
  142. package/templates/skills/business-analyse/references/cache-warming-strategy.md +0 -566
  143. package/templates/skills/business-analyse/references/cadrage-challenge-patterns.md +0 -41
  144. package/templates/skills/business-analyse/references/cadrage-coverage-matrix.md +0 -74
  145. package/templates/skills/business-analyse/references/cadrage-pre-analysis.md +0 -115
  146. package/templates/skills/business-analyse/references/cadrage-shared-modules.md +0 -68
  147. package/templates/skills/business-analyse/references/cadrage-structure-cards.md +0 -85
  148. package/templates/skills/business-analyse/references/team-orchestration.md +0 -1093
  149. package/templates/skills/business-analyse/references/validate-incremental-html.md +0 -121
  150. package/templates/skills/business-analyse/steps/step-01b-applications.md +0 -419
  151. package/templates/skills/business-analyse/steps/step-02-decomposition.md +0 -387
  152. package/templates/skills/business-analyse/steps/step-03a-data.md +0 -16
  153. package/templates/skills/business-analyse/steps/step-03a1-setup.md +0 -486
  154. package/templates/skills/business-analyse/steps/step-03a2-analysis.md +0 -300
  155. package/templates/skills/business-analyse/steps/step-03b-ui.md +0 -405
  156. package/templates/skills/business-analyse/steps/step-03c-compile.md +0 -516
  157. package/templates/skills/business-analyse/steps/step-03d-validate.md +0 -691
  158. package/templates/skills/business-analyse/steps/step-04-consolidation.md +0 -17
  159. package/templates/skills/business-analyse/steps/step-04a-collect.md +0 -415
  160. package/templates/skills/business-analyse/steps/step-04b-analyze.md +0 -163
  161. package/templates/skills/business-analyse/steps/step-04c-decide.md +0 -186
  162. package/templates/skills/business-analyse/steps/step-05a-handoff.md +0 -937
  163. package/templates/skills/business-analyse/steps/step-05b-deploy.md +0 -522
  164. package/templates/skills/business-analyse/steps/step-05c-ralph-readiness.md +0 -703
@@ -313,7 +313,10 @@ function renderEntity(code, ent, index) {
313
313
  <tbody>
314
314
  ${ent.attributes.map(a => `<tr><td style="font-weight:500;color:var(--text-bright);">${a.name}</td><td>${a.description || ''}</td></tr>`).join('')}
315
315
  </tbody>
316
- </table>` : ''}
316
+ </table>
317
+ <div style="padding:0.3rem 0.75rem;">
318
+ <button class="add-btn" style="font-size:0.75rem;padding:0.4rem;" onclick="addEntityAttribute('${code}',${index})">+ Ajouter un attribut</button>
319
+ </div>` : ''}
317
320
  ${(ent.relationships || []).length > 0 ? `
318
321
  <div style="padding:0.5rem 0.75rem;font-size:0.8rem;color:var(--text-muted);border-top:1px solid var(--border);">
319
322
  Relations : ${ent.relationships.map(r => `<span style="color:var(--accent);">${r}</span>`).join(', ')}
@@ -355,6 +358,19 @@ function removeEntity(code, index) {
355
358
  autoSave();
356
359
  }
357
360
 
361
+ function addEntityAttribute(code, entityIndex) {
362
+ var attrName = prompt('Nom de l\'attribut :');
363
+ if (!attrName) return;
364
+ var attrDesc = prompt('Description (optionnel) :') || '';
365
+ if (!data.moduleSpecs[code]?.entities?.[entityIndex]) return;
366
+ if (!data.moduleSpecs[code].entities[entityIndex].attributes) {
367
+ data.moduleSpecs[code].entities[entityIndex].attributes = [];
368
+ }
369
+ data.moduleSpecs[code].entities[entityIndex].attributes.push({ name: attrName, description: attrDesc });
370
+ renderAllModuleSpecs();
371
+ autoSave();
372
+ }
373
+
358
374
  function getSpecComment(code, type, index) {
359
375
  const key = code + '.' + type + '.' + index;
360
376
  return data.specComments[key] || '';
@@ -377,8 +393,25 @@ function updateWireframeComment(code, screen, value) {
377
393
  }
378
394
 
379
395
  function renderModuleMockups(code) {
380
- const wireframes = EMBEDDED_ARTIFACTS?.wireframes?.[code] || [];
396
+ var spec = data.moduleSpecs[code] || {};
397
+ var screens = spec.screens || [];
398
+ var wireframes = EMBEDDED_ARTIFACTS?.wireframes?.[code] || [];
399
+
400
+ // Priority 1: HTML mockups from screens[] specs
401
+ if (screens.length > 0) {
402
+ var html = '';
403
+ if (typeof renderScreenMockups === 'function') {
404
+ html = renderScreenMockups(code);
405
+ }
406
+ // Also show wireframes below if available
407
+ if (wireframes.length > 0) {
408
+ html += '<h3 style="color:var(--text-bright);font-size:1rem;margin:2rem 0 1rem;">Wireframes</h3>';
409
+ html += wireframes.map(function(wf, i) { return renderWireframeMockup(code, wf, i); }).join('');
410
+ }
411
+ return html;
412
+ }
381
413
 
414
+ // Priority 2: Wireframes from EMBEDDED_ARTIFACTS
382
415
  if (wireframes.length === 0) {
383
416
  return `
384
417
  <div class="card" style="text-align:center;padding:2rem;color:var(--text-muted);">
@@ -387,69 +420,73 @@ function renderModuleMockups(code) {
387
420
  </div>`;
388
421
  }
389
422
 
390
- return wireframes.map((wf, i) => {
391
- const hasSvg = !!wf.svgContent;
392
- const wireframeId = `wf-${code}-${i}`;
423
+ return wireframes.map(function(wf, i) { return renderWireframeMockup(code, wf, i); }).join('');
424
+ }
393
425
 
394
- return `
395
- <div class="mockup-frame" style="${i > 0 ? 'margin-top:1.5rem;' : ''}">
396
- <div class="mockup-toolbar">
397
- <div class="mockup-dot mockup-dot-red"></div>
398
- <div class="mockup-dot mockup-dot-yellow"></div>
399
- <div class="mockup-dot mockup-dot-green"></div>
400
- <span class="mockup-title">${wf.screen || wf.section}</span>
401
- ${hasSvg ? `
402
- <div class="wireframe-toggle">
403
- <button class="wireframe-toggle-btn active" data-target="${wireframeId}" data-view="svg" onclick="toggleWireframeView('${wireframeId}', 'svg')">SVG</button>
404
- <button class="wireframe-toggle-btn" data-target="${wireframeId}" data-view="ascii" onclick="toggleWireframeView('${wireframeId}', 'ascii')">ASCII</button>
405
- </div>` : ''}
406
- </div>
407
- <div class="mockup-content" id="${wireframeId}">
408
- ${hasSvg
409
- ? `<div class="svg-wireframe wireframe-view active" data-view="svg">${wf.svgContent}</div>
410
- <pre class="ascii-wireframe wireframe-view" data-view="ascii" style="display:none;">${wf.content || ''}</pre>`
411
- : (wf.format === 'ascii'
412
- ? `<pre class="ascii-wireframe">${wf.content || ''}</pre>`
413
- : `<div class="svg-wireframe">${wf.content || ''}</div>`)}
414
- </div>
415
- ${wf.description ? `
416
- <div class="wireframe-description">
417
- <strong>Description:</strong> ${wf.description}
418
- </div>` : ''}
419
- ${(wf.elements || []).length > 0 ? `
420
- <div class="wireframe-metadata">
421
- <div><strong>Elements:</strong> ${wf.elements.map(e => typeof e === 'string' ? e : (e.type || e.label || e.id || '')).filter(Boolean).join(', ')}</div>
426
+ function renderWireframeMockup(code, wf, i) {
427
+ const hasSvg = !!wf.svgContent;
428
+ const wireframeId = `wf-${code}-${i}`;
429
+
430
+ return `
431
+ <div class="mockup-frame" style="${i > 0 ? 'margin-top:1.5rem;' : ''}">
432
+ <div class="mockup-toolbar">
433
+ <div class="mockup-dot mockup-dot-red"></div>
434
+ <div class="mockup-dot mockup-dot-yellow"></div>
435
+ <div class="mockup-dot mockup-dot-green"></div>
436
+ <span class="mockup-title">${wf.screen || wf.section}</span>
437
+ ${hasSvg ? `
438
+ <div class="wireframe-toggle">
439
+ <button class="wireframe-toggle-btn active" data-target="${wireframeId}" data-view="svg" onclick="toggleWireframeView('${wireframeId}', 'svg')">SVG</button>
440
+ <button class="wireframe-toggle-btn" data-target="${wireframeId}" data-view="ascii" onclick="toggleWireframeView('${wireframeId}', 'ascii')">ASCII</button>
422
441
  </div>` : ''}
423
- ${(() => {
424
- const cm = wf.componentMapping;
425
- const mappings = Array.isArray(cm) ? cm
426
- : (typeof cm === 'object' && cm !== null) ? Object.entries(cm).map(([k,v]) => ({wireframeElement: k, reactComponent: v}))
427
- : [];
428
- return mappings.length > 0 ? `
429
- <details class="wireframe-details">
430
- <summary>Mapping composants SmartStack</summary>
431
- <table class="mapping-table">
432
- <thead><tr><th>Element maquette</th><th>Composant React</th></tr></thead>
433
- <tbody>
434
- ${mappings.map(m =>
435
- '<tr><td>' + (m.wireframeElement || '') + '</td><td><code>' + (m.reactComponent || '') + '</code></td></tr>'
436
- ).join('')}
437
- </tbody>
438
- </table>
439
- </details>` : '';
440
- })()}
441
- <div class="wireframe-comment">
442
- <label style="font-size:0.8rem;color:var(--text-muted);display:block;margin-bottom:0.3rem;">Commentaire / Feedback :</label>
443
- <textarea class="form-textarea"
444
- data-module="${code}"
445
- data-screen="${wf.screen}"
446
- placeholder="Ajouter un commentaire sur cette maquette (ex: deplacer ce bouton, ajouter une colonne...)"
447
- onblur="updateWireframeComment('${code}', '${wf.screen}', this.value)"
448
- style="min-height:60px;font-size:0.85rem;resize:vertical;"
449
- >${getWireframeComment(code, wf.screen)}</textarea>
450
- </div>
451
442
  </div>
452
- `}).join('');
443
+ <div class="mockup-content" id="${wireframeId}">
444
+ ${hasSvg
445
+ ? `<div class="svg-wireframe wireframe-view active" data-view="svg">${wf.svgContent}</div>
446
+ <pre class="ascii-wireframe wireframe-view" data-view="ascii" style="display:none;">${wf.content || ''}</pre>`
447
+ : (wf.format === 'ascii'
448
+ ? `<pre class="ascii-wireframe">${wf.content || ''}</pre>`
449
+ : `<div class="svg-wireframe">${wf.content || ''}</div>`)}
450
+ </div>
451
+ ${wf.description ? `
452
+ <div class="wireframe-description">
453
+ <strong>Description:</strong> ${wf.description}
454
+ </div>` : ''}
455
+ ${(wf.elements || []).length > 0 ? `
456
+ <div class="wireframe-metadata">
457
+ <div><strong>Elements:</strong> ${wf.elements.map(e => typeof e === 'string' ? e : (e.type || e.label || e.id || '')).filter(Boolean).join(', ')}</div>
458
+ </div>` : ''}
459
+ ${(() => {
460
+ const cm = wf.componentMapping;
461
+ const mappings = Array.isArray(cm) ? cm
462
+ : (typeof cm === 'object' && cm !== null) ? Object.entries(cm).map(([k,v]) => ({wireframeElement: k, reactComponent: v}))
463
+ : [];
464
+ return mappings.length > 0 ? `
465
+ <details class="wireframe-details">
466
+ <summary>Mapping composants SmartStack</summary>
467
+ <table class="mapping-table">
468
+ <thead><tr><th>Element maquette</th><th>Composant React</th></tr></thead>
469
+ <tbody>
470
+ ${mappings.map(m =>
471
+ '<tr><td>' + (m.wireframeElement || '') + '</td><td><code>' + (m.reactComponent || '') + '</code></td></tr>'
472
+ ).join('')}
473
+ </tbody>
474
+ </table>
475
+ </details>` : '';
476
+ })()}
477
+ <div class="wireframe-comment">
478
+ <label style="font-size:0.8rem;color:var(--text-muted);display:block;margin-bottom:0.3rem;">Commentaire / Feedback :</label>
479
+ <textarea class="form-textarea"
480
+ data-module="${code}"
481
+ data-screen="${wf.screen}"
482
+ placeholder="Ajouter un commentaire sur cette maquette (ex: deplacer ce bouton, ajouter une colonne...)"
483
+ onblur="updateWireframeComment('${code}', '${wf.screen}', this.value)"
484
+ style="min-height:60px;font-size:0.85rem;resize:vertical;"
485
+ >${getWireframeComment(code, wf.screen)}</textarea>
486
+ </div>
487
+ </div>
488
+ `;
489
+ }
453
490
  }
454
491
 
455
492
  function toggleWireframeView(wireframeId, view) {
@@ -473,7 +510,7 @@ function toggleWireframeView(wireframeId, view) {
473
510
  }
474
511
 
475
512
  function getPermRoles() {
476
- // Extract roles from actual permission data (handles English role names from feature.json)
513
+ // Extract roles from actual permission data (handles English role names from JSON data)
477
514
  const rolesFromPerms = [];
478
515
  const seen = new Set();
479
516
  data.modules.forEach(m => {
@@ -0,0 +1,372 @@
1
+ /* ============================================
2
+ HTML MOCKUP RENDERER
3
+ Generates realistic HTML mockups from screens[] specs
4
+ ============================================ */
5
+
6
+ function renderScreenMockups(code) {
7
+ var spec = data.moduleSpecs[code] || {};
8
+ var screens = spec.screens || [];
9
+
10
+ if (screens.length === 0) return '';
11
+
12
+ return screens.map(function(screen, si) {
13
+ var resources = screen.resources || [];
14
+ return '<div class="screen-section" style="margin-bottom:2rem;">' +
15
+ '<h3 style="color:var(--text-bright);font-size:1rem;margin-bottom:1rem;">' +
16
+ '<span style="color:var(--accent);">&#9656;</span> ' + (screen.sectionLabel || screen.sectionCode) +
17
+ '</h3>' +
18
+ resources.map(function(res, ri) {
19
+ return renderResourceMockup(code, screen.sectionCode, res, ri);
20
+ }).join('') +
21
+ '</div>';
22
+ }).join('');
23
+ }
24
+
25
+ function renderResourceMockup(code, sectionCode, res, index) {
26
+ var mockupId = 'mockup-' + code + '-' + sectionCode + '-' + index;
27
+ var html = '<div class="mockup-frame" style="margin-bottom:1.5rem;">';
28
+
29
+ // Browser chrome
30
+ html += '<div class="mockup-toolbar">';
31
+ html += '<div class="mockup-dot mockup-dot-red"></div>';
32
+ html += '<div class="mockup-dot mockup-dot-yellow"></div>';
33
+ html += '<div class="mockup-dot mockup-dot-green"></div>';
34
+ html += '<span class="mockup-title">' + (res.label || res.code) + ' (' + res.type + ')</span>';
35
+ if (res.permission) {
36
+ html += '<span style="margin-left:auto;font-size:0.65rem;color:var(--text-muted);background:var(--bg-dark);padding:0.15rem 0.5rem;border-radius:4px;">' + res.permission + '</span>';
37
+ }
38
+ html += '</div>';
39
+
40
+ // Mockup content
41
+ html += '<div class="mockup-content" id="' + mockupId + '">';
42
+ switch (res.type) {
43
+ case 'SmartTable':
44
+ html += renderSmartTableMockup(res);
45
+ break;
46
+ case 'SmartForm':
47
+ html += renderSmartFormMockup(res);
48
+ break;
49
+ case 'SmartCard':
50
+ html += renderSmartCardMockup(res);
51
+ break;
52
+ case 'SmartKanban':
53
+ html += renderSmartKanbanMockup(res);
54
+ break;
55
+ case 'SmartDashboard':
56
+ html += renderSmartDashboardMockup(res);
57
+ break;
58
+ case 'SmartFilter':
59
+ html += renderSmartFilterMockup(res);
60
+ break;
61
+ default:
62
+ html += '<div style="padding:2rem;text-align:center;color:var(--text-muted);">Composant ' + res.type + ' - maquette non disponible</div>';
63
+ }
64
+ html += '</div>';
65
+
66
+ // Notes
67
+ if (res.notes) {
68
+ html += '<div style="padding:0.5rem 1rem;font-size:0.8rem;color:var(--text-muted);border-top:1px solid var(--border);background:var(--bg-input);">';
69
+ html += '<strong>Notes:</strong> ' + res.notes;
70
+ html += '</div>';
71
+ }
72
+
73
+ // Comment area
74
+ html += '<div class="wireframe-comment">';
75
+ html += '<label style="font-size:0.8rem;color:var(--text-muted);display:block;margin-bottom:0.3rem;">Commentaire :</label>';
76
+ html += '<textarea class="form-textarea" placeholder="Commentaire sur cette maquette..."';
77
+ html += ' onblur="updateWireframeComment(\'' + code + '\', \'' + (res.code || sectionCode + '-' + index) + '\', this.value)"';
78
+ html += ' style="min-height:50px;font-size:0.85rem;resize:vertical;">';
79
+ html += getWireframeComment(code, res.code || sectionCode + '-' + index);
80
+ html += '</textarea>';
81
+ html += '</div>';
82
+
83
+ html += '</div>';
84
+ return html;
85
+ }
86
+
87
+ /* ---------- SmartTable ---------- */
88
+ function renderSmartTableMockup(res) {
89
+ var columns = res.columns || [];
90
+ if (columns.length === 0) return '<div style="padding:2rem;text-align:center;color:var(--text-muted);">Table sans colonnes definies</div>';
91
+
92
+ var html = '';
93
+
94
+ // Header with actions
95
+ html += '<div class="mock-header">';
96
+ html += '<span class="mock-title">' + (res.label || 'Liste') + '</span>';
97
+ html += '<div style="display:flex;gap:0.4rem;">';
98
+ (res.actions || []).forEach(function(action) {
99
+ var isPrimary = action === 'create' || action === 'export';
100
+ html += '<span class="mock-btn' + (isPrimary ? '' : '" style="background:var(--bg-hover);color:var(--text)') + '">' + formatActionLabel(action) + '</span>';
101
+ });
102
+ html += '</div></div>';
103
+
104
+ // Filters
105
+ if (res.filters && res.filters.length > 0) {
106
+ html += '<div style="display:flex;gap:0.5rem;margin-bottom:1rem;">';
107
+ res.filters.forEach(function(f) {
108
+ html += '<span class="mock-input" style="width:auto;min-width:120px;font-size:0.8rem;color:var(--text-muted);">' + f + ' &#9662;</span>';
109
+ });
110
+ html += '<span class="mock-input" style="width:auto;min-width:200px;font-size:0.8rem;color:var(--text-muted);">Rechercher...</span>';
111
+ html += '</div>';
112
+ }
113
+
114
+ // Table
115
+ html += '<table class="mock-table">';
116
+ html += '<thead><tr>';
117
+ columns.forEach(function(col) {
118
+ html += '<th>' + (col.label || col.field);
119
+ if (col.sortable) html += ' <span style="font-size:0.6rem;color:var(--text-muted);">&#9650;&#9660;</span>';
120
+ html += '</th>';
121
+ });
122
+ html += '<th style="width:80px;">Actions</th>';
123
+ html += '</tr></thead>';
124
+
125
+ // Sample rows
126
+ html += '<tbody>';
127
+ var sampleData = generateSampleRows(columns, 4);
128
+ sampleData.forEach(function(row) {
129
+ html += '<tr>';
130
+ columns.forEach(function(col) {
131
+ var val = row[col.field] || '';
132
+ if (col.type === 'badge') {
133
+ html += '<td><span class="mock-status mock-status-active">' + val + '</span></td>';
134
+ } else if (col.type === 'lookup') {
135
+ html += '<td style="color:var(--accent);">' + val + '</td>';
136
+ } else {
137
+ html += '<td>' + val + '</td>';
138
+ }
139
+ });
140
+ html += '<td style="text-align:center;"><span style="cursor:pointer;color:var(--text-muted);">&#9998; &#128465;</span></td>';
141
+ html += '</tr>';
142
+ });
143
+ html += '</tbody></table>';
144
+
145
+ // Pagination
146
+ html += '<div style="display:flex;justify-content:space-between;align-items:center;padding:0.75rem 0;font-size:0.8rem;color:var(--text-muted);">';
147
+ html += '<span>1-4 sur 24 resultats</span>';
148
+ html += '<div style="display:flex;gap:0.3rem;">';
149
+ html += '<span class="mock-btn" style="background:var(--primary);font-size:0.75rem;padding:0.2rem 0.5rem;">1</span>';
150
+ html += '<span class="mock-btn" style="background:var(--bg-hover);font-size:0.75rem;padding:0.2rem 0.5rem;">2</span>';
151
+ html += '<span class="mock-btn" style="background:var(--bg-hover);font-size:0.75rem;padding:0.2rem 0.5rem;">3</span>';
152
+ html += '</div></div>';
153
+
154
+ return html;
155
+ }
156
+
157
+ /* ---------- SmartForm ---------- */
158
+ function renderSmartFormMockup(res) {
159
+ var tabs = res.tabs || [];
160
+ if (tabs.length === 0 && res.fields) {
161
+ tabs = [{ label: 'Informations', fields: res.fields }];
162
+ }
163
+ if (tabs.length === 0) return '<div style="padding:2rem;text-align:center;color:var(--text-muted);">Formulaire sans champs definis</div>';
164
+
165
+ var html = '';
166
+
167
+ // Header
168
+ html += '<div class="mock-header">';
169
+ html += '<span class="mock-title">' + (res.label || 'Formulaire') + '</span>';
170
+ html += '<div style="display:flex;gap:0.4rem;">';
171
+ (res.actions || ['save', 'cancel']).forEach(function(action) {
172
+ var isPrimary = action === 'save';
173
+ html += '<span class="mock-btn' + (isPrimary ? '' : '" style="background:var(--bg-hover);color:var(--text)') + '">' + formatActionLabel(action) + '</span>';
174
+ });
175
+ html += '</div></div>';
176
+
177
+ // Tabs
178
+ if (tabs.length > 1) {
179
+ html += '<div style="display:flex;gap:0;border-bottom:1px solid var(--border);margin-bottom:1.5rem;">';
180
+ tabs.forEach(function(tab, i) {
181
+ html += '<span style="padding:0.5rem 1rem;font-size:0.85rem;cursor:pointer;border-bottom:2px solid ' + (i === 0 ? 'var(--primary)' : 'transparent') + ';color:' + (i === 0 ? 'var(--primary-light)' : 'var(--text-muted)') + ';">' + tab.label + '</span>';
182
+ });
183
+ html += '</div>';
184
+ }
185
+
186
+ // Fields (first tab only)
187
+ var fields = tabs[0].fields || [];
188
+ var rows = [];
189
+ for (var i = 0; i < fields.length; i += 2) {
190
+ rows.push(fields.slice(i, i + 2));
191
+ }
192
+
193
+ rows.forEach(function(row) {
194
+ if (row.length === 1 && row[0].type === 'subtable') {
195
+ html += renderSubtableMockup(row[0]);
196
+ } else {
197
+ html += '<div class="mock-form-row">';
198
+ row.forEach(function(field) {
199
+ html += '<div class="mock-form-group">';
200
+ html += '<label class="mock-label">' + (field.label || field.field);
201
+ if (field.required) html += ' <span style="color:var(--error);">*</span>';
202
+ html += '</label>';
203
+ html += renderFormFieldMockup(field);
204
+ html += '</div>';
205
+ });
206
+ html += '</div>';
207
+ }
208
+ });
209
+
210
+ return html;
211
+ }
212
+
213
+ function renderFormFieldMockup(field) {
214
+ var val = generateSampleValue(field);
215
+ switch (field.type) {
216
+ case 'select':
217
+ return '<span class="mock-input" style="display:block;">' + val + ' &#9662;</span>';
218
+ case 'lookup':
219
+ return '<span class="mock-input" style="display:block;color:var(--accent);">' + val + ' &#128269;</span>';
220
+ case 'date':
221
+ return '<span class="mock-input" style="display:block;">' + val + ' &#128197;</span>';
222
+ case 'textarea':
223
+ return '<span class="mock-input" style="display:block;min-height:60px;">' + val + '</span>';
224
+ case 'checkbox':
225
+ return '<div style="display:flex;align-items:center;gap:0.5rem;"><input type="checkbox" checked disabled style="width:16px;height:16px;"><span style="font-size:0.85rem;color:var(--text);">' + val + '</span></div>';
226
+ default:
227
+ return '<span class="mock-input" style="display:block;' + (field.readonly ? 'opacity:0.6;' : '') + '">' + val + '</span>';
228
+ }
229
+ }
230
+
231
+ function renderSubtableMockup(field) {
232
+ var cols = field.columns || [];
233
+ var entity = field.entity || 'Element';
234
+ var html = '<div style="margin:1rem 0;border:1px solid var(--border);border-radius:8px;overflow:hidden;">';
235
+ html += '<div style="display:flex;justify-content:space-between;align-items:center;padding:0.5rem 0.75rem;background:var(--bg-hover);">';
236
+ html += '<span style="font-weight:500;color:var(--text-bright);font-size:0.85rem;">' + entity + '</span>';
237
+ html += '<span class="mock-btn" style="font-size:0.75rem;padding:0.2rem 0.5rem;">+ Ajouter</span>';
238
+ html += '</div>';
239
+ html += '<table class="mock-table"><thead><tr>';
240
+ cols.forEach(function(c) { html += '<th>' + c + '</th>'; });
241
+ html += '</tr></thead><tbody>';
242
+ html += '<tr>' + cols.map(function() { return '<td style="color:var(--text-muted);font-style:italic;">...</td>'; }).join('') + '</tr>';
243
+ html += '</tbody></table></div>';
244
+ return html;
245
+ }
246
+
247
+ /* ---------- SmartCard ---------- */
248
+ function renderSmartCardMockup(res) {
249
+ var columns = res.columns || res.fields || [];
250
+ var html = '<div class="mock-header"><span class="mock-title">' + (res.label || 'Cartes') + '</span></div>';
251
+ html += '<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:1rem;">';
252
+
253
+ for (var i = 0; i < 4; i++) {
254
+ html += '<div style="background:var(--bg-hover);border:1px solid var(--border);border-radius:8px;padding:1rem;">';
255
+ columns.forEach(function(col, ci) {
256
+ var label = col.label || col.field || col;
257
+ if (ci === 0) {
258
+ html += '<div style="font-weight:600;color:var(--text-bright);margin-bottom:0.5rem;">' + label + ' #' + (i + 1) + '</div>';
259
+ } else {
260
+ html += '<div style="font-size:0.8rem;color:var(--text-muted);margin-bottom:0.25rem;">' + label + ': <span style="color:var(--text);">valeur</span></div>';
261
+ }
262
+ });
263
+ html += '</div>';
264
+ }
265
+ html += '</div>';
266
+ return html;
267
+ }
268
+
269
+ /* ---------- SmartKanban ---------- */
270
+ function renderSmartKanbanMockup(res) {
271
+ var options = res.options || res.columns || ['A faire', 'En cours', 'Termine'];
272
+ var html = '<div class="mock-header"><span class="mock-title">' + (res.label || 'Kanban') + '</span></div>';
273
+ html += '<div style="display:flex;gap:1rem;overflow-x:auto;padding-bottom:0.5rem;">';
274
+
275
+ options.forEach(function(col, ci) {
276
+ var colLabel = typeof col === 'string' ? col : (col.label || col.field || 'Colonne');
277
+ html += '<div style="min-width:200px;flex:1;background:var(--bg-hover);border-radius:8px;padding:0.75rem;">';
278
+ html += '<div style="font-weight:600;font-size:0.85rem;color:var(--text-bright);margin-bottom:0.75rem;display:flex;justify-content:space-between;">';
279
+ html += colLabel + ' <span style="font-size:0.7rem;background:var(--bg-card);padding:0.1rem 0.4rem;border-radius:4px;color:var(--text-muted);">' + (3 - ci) + '</span>';
280
+ html += '</div>';
281
+ for (var j = 0; j < Math.max(1, 3 - ci); j++) {
282
+ html += '<div style="background:var(--bg-card);border:1px solid var(--border);border-radius:6px;padding:0.5rem;margin-bottom:0.5rem;font-size:0.8rem;">';
283
+ html += '<div style="color:var(--text-bright);font-weight:500;">Element ' + (j + 1) + '</div>';
284
+ html += '<div style="color:var(--text-muted);font-size:0.7rem;margin-top:0.25rem;">Description...</div>';
285
+ html += '</div>';
286
+ }
287
+ html += '</div>';
288
+ });
289
+ html += '</div>';
290
+ return html;
291
+ }
292
+
293
+ /* ---------- SmartDashboard ---------- */
294
+ function renderSmartDashboardMockup(res) {
295
+ var html = '<div class="mock-header"><span class="mock-title">' + (res.label || 'Tableau de bord') + '</span></div>';
296
+
297
+ // KPI cards
298
+ html += '<div class="mock-kpi-grid">';
299
+ var kpis = res.kpis || [
300
+ { label: 'Total', value: '1,234' },
301
+ { label: 'Actifs', value: '987' },
302
+ { label: 'En attente', value: '156' },
303
+ { label: 'Taux', value: '80%' }
304
+ ];
305
+ kpis.forEach(function(kpi) {
306
+ html += '<div class="mock-kpi"><div class="mock-kpi-value">' + (kpi.value || '0') + '</div><div class="mock-kpi-label">' + (kpi.label || '') + '</div></div>';
307
+ });
308
+ html += '</div>';
309
+
310
+ // Chart placeholder
311
+ html += '<div class="mock-chart-placeholder">Graphique</div>';
312
+
313
+ return html;
314
+ }
315
+
316
+ /* ---------- SmartFilter ---------- */
317
+ function renderSmartFilterMockup(res) {
318
+ var options = res.options || [];
319
+ var html = '<div style="display:flex;gap:0.4rem;flex-wrap:wrap;padding:0.5rem 0;">';
320
+ html += '<span style="padding:0.3rem 0.7rem;border-radius:16px;font-size:0.8rem;background:var(--primary);color:#fff;cursor:pointer;">Tous</span>';
321
+ options.forEach(function(opt) {
322
+ 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;">' + opt + '</span>';
323
+ });
324
+ html += '</div>';
325
+ return html;
326
+ }
327
+
328
+ /* ---------- Helpers ---------- */
329
+ function formatActionLabel(action) {
330
+ var labels = {
331
+ create: 'Nouveau', edit: 'Modifier', delete: 'Supprimer',
332
+ export: 'Exporter', save: 'Enregistrer', cancel: 'Annuler',
333
+ validate: 'Valider', archive: 'Archiver', print: 'Imprimer'
334
+ };
335
+ return labels[action] || action;
336
+ }
337
+
338
+ function generateSampleRows(columns, count) {
339
+ var rows = [];
340
+ for (var i = 0; i < count; i++) {
341
+ var row = {};
342
+ columns.forEach(function(col) {
343
+ row[col.field] = generateSampleValue(col, i);
344
+ });
345
+ rows.push(row);
346
+ }
347
+ return rows;
348
+ }
349
+
350
+ function generateSampleValue(field, index) {
351
+ var idx = (index || 0) + 1;
352
+ var t = field.type || 'text';
353
+ var f = field.field || '';
354
+
355
+ if (field.options && field.options.length > 0) {
356
+ return field.options[idx % field.options.length];
357
+ }
358
+
359
+ if (t === 'date') return '0' + idx + '/03/2026';
360
+ if (t === 'badge' || t === 'select') return 'Actif';
361
+ if (t === 'lookup') return f.replace(/Id$/, '') + ' #' + idx;
362
+ if (t === 'number') return String(idx * 100);
363
+ if (t === 'checkbox') return idx % 2 === 0 ? 'Oui' : 'Non';
364
+
365
+ if (f.toLowerCase().includes('code')) return 'CODE-' + String(idx).padStart(3, '0');
366
+ if (f.toLowerCase().includes('name') || f.toLowerCase().includes('nom')) return 'Nom ' + idx;
367
+ if (f.toLowerCase().includes('email')) return 'user' + idx + '@example.com';
368
+ if (f.toLowerCase().includes('date')) return '0' + idx + '/03/2026';
369
+ if (f.toLowerCase().includes('status') || f.toLowerCase().includes('statut')) return 'Actif';
370
+
371
+ return f + ' ' + idx;
372
+ }
@@ -24,7 +24,7 @@ function renderHandoffStats() {
24
24
  <div class="stat-card"><div class="stat-value">${totalStakeholders}</div><div class="stat-label">Profils utilisateurs</div></div>
25
25
  <div class="stat-card"><div class="stat-value">${data.dependencies.length}</div><div class="stat-label">Dependances</div></div>
26
26
  <div class="stat-card"><div class="stat-value">${data.consolidation.e2eFlows.length}</div><div class="stat-label">Parcours bout en bout</div></div>
27
- <div class="stat-card"><div class="stat-value">${data.cadrage.risks.length}</div><div class="stat-label">Risques identifies</div></div>
27
+ ${isVibeCoding ? '' : `<div class="stat-card"><div class="stat-value">${data.cadrage.risks.length}</div><div class="stat-label">Risques identifies</div></div>`}
28
28
  `;
29
29
  }
30
30
 
@@ -13,20 +13,48 @@
13
13
  */
14
14
 
15
15
  function initInlineComments() {
16
- // Add comment buttons under each card and uc-item (direct children of sections)
17
- document.querySelectorAll('.section').forEach(section => {
18
- const sectionId = section.id;
19
- section.querySelectorAll(':scope > .card, :scope > .uc-item').forEach((card, index) => {
20
- if (card.querySelector('.comment-btn-container')) return;
21
- card.appendChild(createCommentUI(sectionId, index));
22
- });
16
+ // Cadrage sections: direct card children
17
+ document.querySelectorAll('.section > .card, .section > .stakeholder-card, .section > .uc-item, .section > .risk-item').forEach(function(card) {
18
+ if (card.dataset.commentInitialized) return;
19
+ card.dataset.commentInitialized = 'true';
20
+ var section = card.closest('.section');
21
+ var sectionId = section ? section.id : 'unknown';
22
+ var siblings = Array.from(section.querySelectorAll(':scope > .card, :scope > .stakeholder-card, :scope > .uc-item, :scope > .risk-item'));
23
+ var index = siblings.indexOf(card);
24
+ card.appendChild(createCommentUI(sectionId, index));
25
+ });
26
+
27
+ // Module spec lists: nested items in ucList, brList, entList containers
28
+ document.querySelectorAll('[id^="ucList-"] > .uc-item, [id^="brList-"] > div, [id^="entList-"] > .entity-block').forEach(function(item) {
29
+ if (item.dataset.commentInitialized) return;
30
+ item.dataset.commentInitialized = 'true';
31
+ var list = item.parentElement;
32
+ var listId = list.id;
33
+ var siblings = Array.from(list.children);
34
+ var index = siblings.indexOf(item);
35
+ item.appendChild(createCommentUI(listId, index));
23
36
  });
24
- // Second pass: nested list containers in module specs (ucList-*, brList-*, entList-*)
25
- document.querySelectorAll('[id^="ucList-"], [id^="brList-"], [id^="entList-"]').forEach(list => {
26
- const listId = list.id;
27
- list.querySelectorAll(':scope > .uc-item, :scope > .entity-block, :scope > div').forEach((item, index) => {
28
- if (item.querySelector('.comment-btn-container')) return;
29
- item.appendChild(createCommentUI(listId, index));
37
+
38
+ // Stakeholder cards in grid
39
+ document.querySelectorAll('.stakeholder-grid > .stakeholder-card').forEach(function(card) {
40
+ if (card.dataset.commentInitialized) return;
41
+ card.dataset.commentInitialized = 'true';
42
+ var grid = card.parentElement;
43
+ var section = card.closest('.section');
44
+ var sectionId = section ? section.id : 'stakeholders';
45
+ var siblings = Array.from(grid.children);
46
+ var index = siblings.indexOf(card);
47
+ card.appendChild(createCommentUI(sectionId, index));
48
+ });
49
+
50
+ // Scope items
51
+ ['scopeVital', 'scopeImportant', 'scopeOptional', 'scopeExcluded'].forEach(function(containerId) {
52
+ var container = document.getElementById(containerId);
53
+ if (!container) return;
54
+ container.querySelectorAll('.uc-item').forEach(function(item, index) {
55
+ if (item.dataset.commentInitialized) return;
56
+ item.dataset.commentInitialized = 'true';
57
+ item.appendChild(createCommentUI(containerId, index));
30
58
  });
31
59
  });
32
60
  }