@atlashub/smartstack-cli 4.18.0 → 4.19.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 (160) 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 +703 -82
  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 +31 -5
  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/10-comments.js +41 -13
  51. package/templates/skills/business-analyse/html/src/styles/09-mockups-html.css +136 -0
  52. package/templates/skills/business-analyse/patterns/suggestion-catalog.md +7 -5
  53. package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +142 -0
  54. package/templates/skills/business-analyse/questionnaire/03-data-ui.md +94 -0
  55. package/templates/skills/business-analyse/questionnaire/04-risks-metrics.md +150 -0
  56. package/templates/skills/business-analyse/questionnaire/05-cross-module.md +69 -0
  57. package/templates/skills/business-analyse/questionnaire.md +23 -280
  58. package/templates/skills/business-analyse/react/application-viewer.md +2 -2
  59. package/templates/skills/business-analyse/react/components.md +4 -4
  60. package/templates/skills/business-analyse/react/i18n-template.md +1 -1
  61. package/templates/skills/business-analyse/react/schema.md +14 -14
  62. package/templates/skills/business-analyse/references/acceptance-criteria.md +21 -21
  63. package/templates/skills/business-analyse/references/analysis-semantic-checks.md +3 -3
  64. package/templates/skills/business-analyse/references/compilation-structure-cards.md +1 -1
  65. package/templates/skills/business-analyse/references/consolidation-structural-checks.md +5 -5
  66. package/templates/skills/business-analyse/references/deploy-data-build.md +12 -11
  67. package/templates/skills/business-analyse/references/deploy-modes.md +10 -10
  68. package/templates/skills/business-analyse/references/detection-strategies.md +6 -6
  69. package/templates/skills/business-analyse/references/html-data-mapping.md +15 -15
  70. package/templates/skills/business-analyse/references/naming-conventions.md +4 -4
  71. package/templates/skills/business-analyse/references/review-data-mapping.md +29 -29
  72. package/templates/skills/business-analyse/references/robustness-checks.md +36 -36
  73. package/templates/skills/business-analyse/references/spec-auto-inference.md +2 -2
  74. package/templates/skills/business-analyse/references/ui-dashboard-spec.md +1 -1
  75. package/templates/skills/business-analyse/references/ui-resource-cards.md +1 -1
  76. package/templates/skills/business-analyse/references/validation-checklist.md +3 -3
  77. package/templates/skills/business-analyse/references/wireframe-svg-style-guide.md +2 -2
  78. package/templates/skills/business-analyse/schemas/application-schema.json +8 -8
  79. package/templates/skills/business-analyse/schemas/feature-schema.json +3 -3
  80. package/templates/skills/business-analyse/schemas/index-schema.json +47 -0
  81. package/templates/skills/business-analyse/schemas/project-schema.json +6 -6
  82. package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +1 -1
  83. package/templates/skills/business-analyse/schemas/sections/handoff-schema.json +5 -3
  84. package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +4 -4
  85. package/templates/skills/business-analyse/schemas/sections/specification-schema.json +1 -1
  86. package/templates/skills/business-analyse/schemas/shared/common-defs.json +4 -4
  87. package/templates/skills/business-analyse/steps/step-00-init.md +68 -77
  88. package/templates/skills/business-analyse/steps/step-01-cadrage.md +54 -180
  89. package/templates/skills/business-analyse/steps/step-02-structure.md +175 -0
  90. package/templates/skills/business-analyse/steps/step-03-specify.md +198 -0
  91. package/templates/skills/business-analyse/steps/step-04-consolidate.md +478 -0
  92. package/templates/skills/business-analyse/steps/step-05-deploy.md +220 -0
  93. package/templates/skills/business-analyse/steps/step-06-review.md +51 -69
  94. package/templates/skills/business-analyse/templates/tpl-frd.md +1 -1
  95. package/templates/skills/business-analyse/templates/tpl-handoff.md +20 -17
  96. package/templates/skills/business-analyse/templates/tpl-launch-displays.md +2 -2
  97. package/templates/skills/business-analyse/templates-react.md +2 -2
  98. package/templates/skills/derive-prd/SKILL.md +92 -0
  99. package/templates/skills/derive-prd/references/acceptance-criteria.md +169 -0
  100. package/templates/skills/derive-prd/references/entity-domain-mapping.md +115 -0
  101. package/templates/skills/{business-analyse → derive-prd}/references/handoff-file-templates.md +131 -120
  102. package/templates/skills/{business-analyse → derive-prd}/references/handoff-mappings.md +95 -95
  103. package/templates/skills/{business-analyse → derive-prd}/references/handoff-seeddata-generation.md +312 -312
  104. package/templates/skills/{business-analyse → derive-prd}/references/prd-generation.md +262 -263
  105. package/templates/skills/derive-prd/references/readiness-scoring.md +104 -0
  106. package/templates/skills/derive-prd/schemas/handoff-schema.json +95 -0
  107. package/templates/skills/derive-prd/steps/step-00-validate.md +130 -0
  108. package/templates/skills/derive-prd/steps/step-01-transform.md +206 -0
  109. package/templates/skills/derive-prd/steps/step-02-export.md +181 -0
  110. package/templates/skills/{business-analyse → derive-prd}/templates/tpl-progress.md +172 -172
  111. package/templates/skills/ralph-loop/SKILL.md +2 -1
  112. package/templates/skills/ralph-loop/references/init-resume-recovery.md +1 -1
  113. package/templates/skills/ralph-loop/steps/step-01-task.md +2 -2
  114. package/templates/skills/apex/references/agent-teams-protocol.md +0 -203
  115. package/templates/skills/business-analyse/_architecture.md +0 -124
  116. package/templates/skills/business-analyse/_elicitation.md +0 -206
  117. package/templates/skills/business-analyse/_module-loop.md +0 -115
  118. package/templates/skills/business-analyse/_rules.md +0 -142
  119. package/templates/skills/business-analyse/_suggestions.md +0 -34
  120. package/templates/skills/business-analyse/questionnaire/00-application.md +0 -160
  121. package/templates/skills/business-analyse/questionnaire/00b-project.md +0 -85
  122. package/templates/skills/business-analyse/questionnaire/02-stakeholders.md +0 -189
  123. package/templates/skills/business-analyse/questionnaire/03-scope.md +0 -164
  124. package/templates/skills/business-analyse/questionnaire/04-data.md +0 -88
  125. package/templates/skills/business-analyse/questionnaire/05-integrations.md +0 -58
  126. package/templates/skills/business-analyse/questionnaire/06-security.md +0 -68
  127. package/templates/skills/business-analyse/questionnaire/07-ui.md +0 -76
  128. package/templates/skills/business-analyse/questionnaire/08-performance.md +0 -42
  129. package/templates/skills/business-analyse/questionnaire/09-constraints.md +0 -45
  130. package/templates/skills/business-analyse/questionnaire/10-documentation.md +0 -58
  131. package/templates/skills/business-analyse/questionnaire/11-data-lifecycle.md +0 -59
  132. package/templates/skills/business-analyse/questionnaire/12-migration.md +0 -58
  133. package/templates/skills/business-analyse/questionnaire/13-cross-module.md +0 -69
  134. package/templates/skills/business-analyse/questionnaire/14-risk-assumptions.md +0 -135
  135. package/templates/skills/business-analyse/questionnaire/15-success-metrics.md +0 -136
  136. package/templates/skills/business-analyse/references/agent-module-prompt.md +0 -366
  137. package/templates/skills/business-analyse/references/agent-pooling-best-practices.md +0 -557
  138. package/templates/skills/business-analyse/references/cache-warming-strategy.md +0 -566
  139. package/templates/skills/business-analyse/references/cadrage-challenge-patterns.md +0 -41
  140. package/templates/skills/business-analyse/references/cadrage-coverage-matrix.md +0 -74
  141. package/templates/skills/business-analyse/references/cadrage-pre-analysis.md +0 -115
  142. package/templates/skills/business-analyse/references/cadrage-shared-modules.md +0 -68
  143. package/templates/skills/business-analyse/references/cadrage-structure-cards.md +0 -85
  144. package/templates/skills/business-analyse/references/team-orchestration.md +0 -1093
  145. package/templates/skills/business-analyse/references/validate-incremental-html.md +0 -121
  146. package/templates/skills/business-analyse/steps/step-01b-applications.md +0 -419
  147. package/templates/skills/business-analyse/steps/step-02-decomposition.md +0 -387
  148. package/templates/skills/business-analyse/steps/step-03a-data.md +0 -16
  149. package/templates/skills/business-analyse/steps/step-03a1-setup.md +0 -486
  150. package/templates/skills/business-analyse/steps/step-03a2-analysis.md +0 -300
  151. package/templates/skills/business-analyse/steps/step-03b-ui.md +0 -405
  152. package/templates/skills/business-analyse/steps/step-03c-compile.md +0 -516
  153. package/templates/skills/business-analyse/steps/step-03d-validate.md +0 -691
  154. package/templates/skills/business-analyse/steps/step-04-consolidation.md +0 -17
  155. package/templates/skills/business-analyse/steps/step-04a-collect.md +0 -415
  156. package/templates/skills/business-analyse/steps/step-04b-analyze.md +0 -163
  157. package/templates/skills/business-analyse/steps/step-04c-decide.md +0 -186
  158. package/templates/skills/business-analyse/steps/step-05a-handoff.md +0 -937
  159. package/templates/skills/business-analyse/steps/step-05b-deploy.md +0 -522
  160. 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
+ }
@@ -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
  }