@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.
Files changed (93) hide show
  1. package/dist/index.js +111 -36
  2. package/dist/index.js.map +1 -1
  3. package/dist/mcp-entry.mjs +14 -3
  4. package/dist/mcp-entry.mjs.map +1 -1
  5. package/package.json +1 -1
  6. package/templates/agents/ba-reader.md +17 -15
  7. package/templates/agents/ba-writer.md +49 -51
  8. package/templates/skills/apex/_shared.md +1 -1
  9. package/templates/skills/apex/references/checks/backend-checks.sh +21 -7
  10. package/templates/skills/apex/references/checks/infrastructure-checks.sh +47 -10
  11. package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +3 -0
  12. package/templates/skills/apex/references/post-checks.md +5 -2
  13. package/templates/skills/apex/references/smartstack-frontend.md +53 -7
  14. package/templates/skills/apex/steps/step-00-init.md +74 -0
  15. package/templates/skills/apex/steps/step-03-execute.md +16 -4
  16. package/templates/skills/apex/steps/step-03b-layer1-seed.md +39 -6
  17. package/templates/skills/apex/steps/step-03c-layer2-backend.md +50 -5
  18. package/templates/skills/apex/steps/step-03d-layer3-frontend.md +102 -2
  19. package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +3 -0
  20. package/templates/skills/business-analyse/SKILL.md +14 -0
  21. package/templates/skills/business-analyse/_shared.md +27 -0
  22. package/templates/skills/business-analyse/patterns/suggestion-catalog.md +34 -26
  23. package/templates/skills/business-analyse/questionnaire/01-context.md +13 -9
  24. package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +20 -27
  25. package/templates/skills/business-analyse/questionnaire.md +86 -9
  26. package/templates/skills/business-analyse/references/03-json-schemas.md +213 -0
  27. package/templates/skills/business-analyse/references/03-post-check-validation.md +144 -0
  28. package/templates/skills/business-analyse/references/03-smartstack-entity-guards.md +32 -0
  29. package/templates/skills/business-analyse/references/04-cross-module-validation.md +95 -0
  30. package/templates/skills/business-analyse/references/04-file-allocation.md +162 -0
  31. package/templates/skills/business-analyse/references/04-naming-audit-checks.md +174 -0
  32. package/templates/skills/business-analyse/references/04-semantic-validation-matrix.md +118 -0
  33. package/templates/skills/business-analyse/references/domain-research-playbook.md +234 -0
  34. package/templates/skills/business-analyse/references/entity-sourcing-presentation.md +166 -0
  35. package/templates/skills/business-analyse/references/init-resume-logic.md +70 -0
  36. package/templates/skills/business-analyse/references/module-completeness-challenge.md +174 -0
  37. package/templates/skills/business-analyse/references/multi-app-detection.md +149 -0
  38. package/templates/skills/business-analyse/references/portal-classification.md +52 -0
  39. package/templates/skills/business-analyse/references/validation-checklist.md +30 -1
  40. package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +37 -4
  41. package/templates/skills/business-analyse/steps/step-00-init.md +22 -190
  42. package/templates/skills/business-analyse/steps/step-01-cadrage.md +365 -269
  43. package/templates/skills/business-analyse/steps/step-02-structure.md +98 -20
  44. package/templates/skills/business-analyse/steps/step-03-specify.md +652 -229
  45. package/templates/skills/business-analyse/steps/step-04-consolidate.md +308 -287
  46. package/templates/skills/business-analyse-design/SKILL.md +10 -0
  47. package/templates/skills/business-analyse-design/references/screens-post-check.md +221 -0
  48. package/templates/skills/business-analyse-design/references/screens-type-mapping.md +138 -0
  49. package/templates/skills/business-analyse-design/references/smartcomponents-templates.md +225 -0
  50. package/templates/skills/{business-analyse → business-analyse-design}/references/spec-auto-inference.md +117 -117
  51. package/templates/skills/business-analyse-design/steps/step-01-screens.md +36 -162
  52. package/templates/skills/business-analyse-design/steps/step-02-wireframes.md +8 -7
  53. package/templates/skills/business-analyse-design/steps/step-03-navigation.md +89 -42
  54. package/templates/skills/business-analyse-develop/references/compact-loop.md +9 -0
  55. package/templates/skills/business-analyse-develop/references/handoff-quality-gate.md +132 -0
  56. package/templates/skills/business-analyse-develop/references/prd-v3-transformation.md +326 -0
  57. package/templates/skills/business-analyse-develop/references/report-reconciliation.md +140 -0
  58. package/templates/skills/business-analyse-develop/references/report-template.md +142 -0
  59. package/templates/skills/business-analyse-develop/steps/step-01-task.md +5 -177
  60. package/templates/skills/business-analyse-develop/steps/step-02-execute.md +17 -4
  61. package/templates/skills/business-analyse-develop/steps/step-03-commit.md +6 -2
  62. package/templates/skills/business-analyse-develop/steps/step-04-check.md +6 -0
  63. package/templates/skills/business-analyse-develop/steps/step-05-report.md +3 -269
  64. package/templates/skills/business-analyse-handoff/SKILL.md +10 -0
  65. package/templates/skills/business-analyse-handoff/references/agent-handoff-transform-prompt.md +208 -0
  66. package/templates/skills/business-analyse-handoff/references/context-isolation-pattern.md +47 -0
  67. package/templates/skills/business-analyse-handoff/references/handoff-file-inventory.md +49 -0
  68. package/templates/skills/business-analyse-handoff/references/handoff-global-validation.md +142 -0
  69. package/templates/skills/business-analyse-handoff/references/prd-validation-checks.md +125 -0
  70. package/templates/skills/business-analyse-handoff/references/project-index-update.md +98 -0
  71. package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +9 -160
  72. package/templates/skills/business-analyse-handoff/steps/step-02-export.md +10 -99
  73. package/templates/skills/business-analyse-html/SKILL.md +10 -0
  74. package/templates/skills/business-analyse-html/html/ba-interactive.html +306 -81
  75. package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +15 -2
  76. package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +6 -46
  77. package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +88 -33
  78. package/templates/skills/business-analyse-html/html/src/scripts/12-render-diagrams.js +116 -0
  79. package/templates/skills/business-analyse-html/html/src/styles/10-diagrams.css +73 -0
  80. package/templates/skills/business-analyse-html/html/src/template.html +2 -0
  81. package/templates/skills/business-analyse-html/references/02-embedded-artifacts-building.md +144 -0
  82. package/templates/skills/business-analyse-html/references/02-feature-data-building.md +141 -0
  83. package/templates/skills/business-analyse-html/references/02-mapping-tables.md +442 -0
  84. package/templates/skills/business-analyse-html/references/02-normalization-helpers.md +139 -0
  85. package/templates/skills/business-analyse-html/references/02-screen-format-detection.md +283 -0
  86. package/templates/skills/business-analyse-html/references/02-self-check-validation.md +199 -0
  87. package/templates/skills/business-analyse-html/references/data-build.md +22 -1
  88. package/templates/skills/business-analyse-html/references/data-mapping.md +40 -5
  89. package/templates/skills/business-analyse-html/steps/step-02-build-data.md +12 -555
  90. package/templates/skills/business-analyse-review/SKILL.md +10 -0
  91. package/templates/skills/business-analyse-status/SKILL.md +8 -0
  92. package/templates/skills/dev-start/SKILL.md +143 -307
  93. package/templates/skills/efcore/SKILL.md +13 -0
@@ -77,3 +77,13 @@ When launched, detect and select the target project:
77
77
  ## Entry Point
78
78
 
79
79
  **FIRST ACTION:** Load `steps/step-01-collect.md`
80
+
81
+ <success_criteria>
82
+ - Sources JSON collectees (index, cadrage, modules, consolidation)
83
+ - FEATURE_DATA construit avec mapping correct des champs
84
+ - EMBEDDED_ARTIFACTS cree pour ERD, matrice permissions, wireframes
85
+ - ba-interactive.html template injecte et rendu
86
+ - Fichier HTML final > 100KB sans chaine [object Object]
87
+ - moduleSpecs a UNE entree par module avec resources peuplees
88
+ - Cles scope normalisees : inScope -> inscope, outOfScope -> outofscope
89
+ </success_criteria>
@@ -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
  /* --- 01-variables.css --- */
9
11
  /* ============================================
@@ -2024,6 +2026,82 @@ body {
2024
2026
  .mock-form-tab-content.active {
2025
2027
  display: block;
2026
2028
  }
2029
+
2030
+
2031
+ /* --- 10-diagrams.css --- */
2032
+ /* ==========================================
2033
+ MERMAID DIAGRAMS
2034
+ ========================================== */
2035
+
2036
+ .diagram-container {
2037
+ margin: 1.5rem 0;
2038
+ padding: 1rem;
2039
+ background: var(--bg-card);
2040
+ border-radius: 8px;
2041
+ border: 1px solid var(--border);
2042
+ overflow-x: auto;
2043
+ }
2044
+
2045
+ .diagram-container h3,
2046
+ .diagram-container h4 {
2047
+ color: var(--text-bright);
2048
+ margin-bottom: 1rem;
2049
+ font-size: 1.1rem;
2050
+ }
2051
+
2052
+ .diagram-container .mermaid {
2053
+ display: flex;
2054
+ justify-content: center;
2055
+ min-height: 200px;
2056
+ }
2057
+
2058
+ .diagram-container .mermaid svg {
2059
+ max-width: 100%;
2060
+ height: auto;
2061
+ }
2062
+
2063
+ /* ERD specific */
2064
+ .diagram-erd {
2065
+ margin-bottom: 2rem;
2066
+ border-left: 3px solid var(--primary);
2067
+ }
2068
+
2069
+ /* State machine specific */
2070
+ .diagram-state-machine {
2071
+ border-left: 3px solid var(--accent);
2072
+ }
2073
+
2074
+ /* Sequence diagram specific */
2075
+ .diagram-sequence {
2076
+ border-left: 3px solid var(--success);
2077
+ }
2078
+
2079
+ /* Diagram section header */
2080
+ .diagram-section-header {
2081
+ display: flex;
2082
+ align-items: center;
2083
+ gap: 0.5rem;
2084
+ margin-bottom: 1rem;
2085
+ color: var(--text-bright);
2086
+ font-size: 1.2rem;
2087
+ font-weight: 600;
2088
+ }
2089
+
2090
+ .diagram-section-header::before {
2091
+ content: '';
2092
+ width: 4px;
2093
+ height: 1.2em;
2094
+ background: var(--primary);
2095
+ border-radius: 2px;
2096
+ }
2097
+
2098
+ /* No diagrams fallback */
2099
+ .diagram-empty {
2100
+ color: var(--text-muted);
2101
+ font-style: italic;
2102
+ padding: 1rem;
2103
+ text-align: center;
2104
+ }
2027
2105
 
2028
2106
  </style>
2029
2107
  </head>
@@ -2515,9 +2593,22 @@ if (!data.cadrage.scope || (!data.cadrage.scope.inscope?.length && data.cadrage.
2515
2593
  outofscope: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
2516
2594
  };
2517
2595
  } else {
2596
+ function normScopeItem(s) {
2597
+ if (typeof s === 'string') return { name: s, description: '' };
2598
+ if (s.name) return s;
2599
+ var nm = s.feature || s.label || s.title || JSON.stringify(s);
2600
+ var parts = [];
2601
+ if (s.priority) parts.push(s.priority.toUpperCase());
2602
+ if (s.module) parts.push('Module: ' + s.module);
2603
+ return { name: nm, description: parts.join(' — ') };
2604
+ }
2518
2605
  data.cadrage.scope = {
2519
- inscope: (gs.inScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s),
2520
- outofscope: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
2606
+ inscope: (gs.inScope || []).map(normScopeItem),
2607
+ outofscope: (gs.outOfScope || []).map(function(s) {
2608
+ if (typeof s === 'string') return { name: s, description: '' };
2609
+ if (s.name) return s;
2610
+ return { name: s.feature || s.reason || JSON.stringify(s), description: s.reason || '' };
2611
+ })
2521
2612
  };
2522
2613
  }
2523
2614
  }
@@ -2851,54 +2942,14 @@ function renderModuleNavItem(mod) {
2851
2942
  var ucCount = (spec.useCases || []).length;
2852
2943
  var brCount = (spec.businessRules || []).length;
2853
2944
  var entCount = (spec.entities || []).length;
2854
- var sections = (mod.anticipatedSections || []).map(function(s) {
2855
- return typeof s === 'string' ? { code: s, name: s, resources: [] } : s;
2856
- });
2857
- var groupId = 'mod-' + code;
2858
- var collapsed = navCollapseState[groupId] === true;
2859
-
2860
- var html = '<div class="nav-module" data-group-id="' + groupId + '">';
2861
-
2862
- // Module header (clickable to expand + navigate to module spec)
2863
2945
  var totalItems = ucCount + brCount + entCount;
2864
- html += '<a class="nav-item nav-module-header" onclick="toggleNavGroup(\'' + groupId + '\');showSection(\'module-spec-' + code + '\')" data-section="module-spec-' + code + '">';
2865
- html += '<span class="nav-chevron ' + (collapsed ? '' : 'expanded') + '">&#9656;</span> ';
2866
- html += (mod.name || mod.code);
2867
- if (totalItems > 0) html += ' <span class="nav-badge">' + totalItems + '</span>';
2868
- html += '</a>';
2869
-
2870
- // Children: sections/resources (navigable sub-tree)
2871
- // Tab-level items (UC, BR, Données, etc.) are NOT shown here — they are accessed
2872
- // via the tab bar in the module content area to avoid redundancy.
2873
- html += '<div class="nav-children"' + (collapsed ? ' style="display:none;"' : '') + '>';
2874
- if (sections.length > 0) {
2875
- sections.forEach(function(section) {
2876
- var resources = section.resources || [];
2877
- var sectionUCs = (section.useCases || []).length;
2878
- var sectionBRs = (section.businessRules || []).length;
2879
- var contentCount = sectionUCs + sectionBRs + resources.length;
2880
- html += '<div class="nav-section-item">';
2881
- html += '<a class="nav-item nav-section-link" onclick="showSection(\'module-spec-' + code + '\');switchTab(\'' + code + '\',\'struct\')" data-section="module-struct-' + code + '-' + section.code + '">';
2882
- html += '<span class="nav-icon nav-icon-section">&#9655;</span> ' + escapeHtml(section.code || section.name || '');
2883
- if (contentCount > 0) html += ' <span class="nav-badge">' + contentCount + '</span>';
2884
- html += '</a>';
2885
- if (resources.length > 0) {
2886
- html += '<div class="nav-children nav-resources">';
2887
- resources.forEach(function(res) {
2888
- var resName = typeof res === 'string' ? res : (res.code || res.name || '');
2889
- html += '<a class="nav-item nav-resource-link" onclick="showSection(\'module-spec-' + code + '\');switchTab(\'' + code + '\',\'mock\');scrollToMockup(\'' + code + '\',\'' + section.code + '\')">';
2890
- html += '<span class="nav-icon nav-icon-resource">&#8226;</span> ' + escapeHtml(resName);
2891
- html += '</a>';
2892
- });
2893
- html += '</div>';
2894
- }
2895
- html += '</div>';
2896
- });
2897
- }
2898
2946
 
2899
- html += '</div>'; // nav-children
2900
- html += '</div>'; // nav-module
2901
- return html;
2947
+ // Flat module link — sections/resources are accessible via tabs (Structure, Maquettes)
2948
+ return '<a class="nav-item nav-module-header" onclick="showSection(\'module-spec-' + code + '\')" data-section="module-spec-' + code + '">' +
2949
+ '<span class="nav-icon">&#9679;</span> ' +
2950
+ (mod.name || mod.code) +
2951
+ (totalItems > 0 ? ' <span class="nav-badge">' + totalItems + '</span>' : '') +
2952
+ '</a>';
2902
2953
  }
2903
2954
 
2904
2955
  function renderModuleTabNavItem(code, tabId, label, badge) {
@@ -4625,31 +4676,36 @@ function renderSmartFormMockup(res) {
4625
4676
  html += '<div class="mock-form-tab-content' + (ti === 0 || isOnly ? ' active' : '') + '"';
4626
4677
  html += ' data-mockup="' + mockupId + '" data-tab="' + ti + '">';
4627
4678
 
4628
- var fields = tab.fields || [];
4629
- var rows = [];
4630
- for (var i = 0; i < fields.length; i += 2) {
4631
- rows.push(fields.slice(i, i + 2));
4632
- }
4679
+ // Tab-level subtable: the entire tab is a subtable (type: "subtable", entity, columns)
4680
+ if (tab.type === 'subtable') {
4681
+ html += renderSubtableMockup(tab);
4682
+ } else {
4683
+ var fields = tab.fields || [];
4684
+ var rows = [];
4685
+ for (var i = 0; i < fields.length; i += 2) {
4686
+ rows.push(fields.slice(i, i + 2));
4687
+ }
4633
4688
 
4634
- rows.forEach(function(row) {
4635
- if (row.length === 1 && row[0].type === 'subtable') {
4636
- html += renderSubtableMockup(row[0]);
4637
- } else {
4638
- html += '<div class="mock-form-row">';
4639
- row.forEach(function(field) {
4640
- html += '<div class="mock-form-group">';
4641
- html += '<label class="mock-label">' + escapeHtml(field.label || field.field);
4642
- if (field.required) html += ' <span style="color:var(--error);">*</span>';
4643
- html += '</label>';
4644
- html += renderFormFieldMockup(field);
4689
+ rows.forEach(function(row) {
4690
+ if (row.length === 1 && row[0].type === 'subtable') {
4691
+ html += renderSubtableMockup(row[0]);
4692
+ } else {
4693
+ html += '<div class="mock-form-row">';
4694
+ row.forEach(function(field) {
4695
+ html += '<div class="mock-form-group">';
4696
+ html += '<label class="mock-label">' + escapeHtml(field.label || field.field);
4697
+ if (field.required) html += ' <span style="color:var(--error);">*</span>';
4698
+ html += '</label>';
4699
+ html += renderFormFieldMockup(field);
4700
+ html += '</div>';
4701
+ });
4645
4702
  html += '</div>';
4646
- });
4647
- html += '</div>';
4648
- }
4649
- });
4703
+ }
4704
+ });
4650
4705
 
4651
- if (fields.length === 0) {
4652
- html += '<div style="padding:2rem;text-align:center;color:var(--text-muted);font-style:italic;">Contenu de l\'onglet &laquo; ' + escapeHtml(tab.label) + ' &raquo;</div>';
4706
+ if (fields.length === 0) {
4707
+ html += '<div style="padding:2rem;text-align:center;color:var(--text-muted);font-style:italic;">Contenu de l\'onglet &laquo; ' + escapeHtml(tab.label) + ' &raquo;</div>';
4708
+ }
4653
4709
  }
4654
4710
 
4655
4711
  html += '</div>';
@@ -4694,20 +4750,39 @@ function renderSubtableMockup(field) {
4694
4750
 
4695
4751
  /* ---------- SmartCard ---------- */
4696
4752
  function renderSmartCardMockup(res) {
4697
- var columns = res.columns || res.fields || [];
4753
+ var fields = res.fields || res.columns || [];
4698
4754
  var html = '<div class="mock-header"><span class="mock-title">' + escapeHtml(res.label || 'Cartes') + '</span></div>';
4699
4755
  html += '<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:1rem;">';
4700
4756
 
4701
4757
  for (var i = 0; i < 4; i++) {
4702
4758
  html += '<div style="background:var(--bg-hover);border:1px solid var(--border);border-radius:8px;padding:1rem;">';
4703
- columns.forEach(function(col, ci) {
4704
- var label = col.label || col.field || col;
4705
- if (ci === 0) {
4759
+ // Title/Subtitle pattern (SmartCard with title + subtitle + fields + actions)
4760
+ if (res.title) {
4761
+ html += '<div style="font-weight:600;color:var(--text-bright);margin-bottom:0.25rem;">' + escapeHtml(res.title) + ' #' + (i + 1) + '</div>';
4762
+ }
4763
+ if (res.subtitle) {
4764
+ html += '<div style="font-size:0.8rem;color:var(--accent);margin-bottom:0.5rem;">' + escapeHtml(res.subtitle) + '</div>';
4765
+ }
4766
+ // Fields
4767
+ fields.forEach(function(col, ci) {
4768
+ var label = col.label || col.field || (typeof col === 'string' ? col : '');
4769
+ var iconMap = { calendar: '&#128197; ', 'dollar-sign': '&#128176; ', 'alert-circle': '&#9888; ', mail: '&#9993; ', building: '&#127970; ', user: '&#128100; ' };
4770
+ var icon = col.icon ? (iconMap[col.icon] || '&#9679; ') : '';
4771
+ if (!res.title && ci === 0) {
4706
4772
  html += '<div style="font-weight:600;color:var(--text-bright);margin-bottom:0.5rem;">' + escapeHtml(label) + ' #' + (i + 1) + '</div>';
4707
4773
  } else {
4708
- 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>';
4774
+ 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>';
4709
4775
  }
4710
4776
  });
4777
+ // Actions
4778
+ if (res.actions && res.actions.length > 0) {
4779
+ html += '<div style="margin-top:0.75rem;display:flex;gap:0.4rem;">';
4780
+ res.actions.forEach(function(a) {
4781
+ var actionLabel = typeof a === 'string' ? a.replace(/-/g, ' ') : (a.label || a.action || '');
4782
+ html += '<span class="mock-btn" style="font-size:0.75rem;">' + escapeHtml(actionLabel) + '</span>';
4783
+ });
4784
+ html += '</div>';
4785
+ }
4711
4786
  html += '</div>';
4712
4787
  }
4713
4788
  html += '</div>';
@@ -4716,7 +4791,7 @@ function renderSmartCardMockup(res) {
4716
4791
 
4717
4792
  /* ---------- SmartKanban ---------- */
4718
4793
  function renderSmartKanbanMockup(res) {
4719
- var options = res.options || res.columns || ['À faire', 'En cours', 'Terminé'];
4794
+ var options = (res.options && res.options.length > 0) ? res.options : (res.columns && res.columns.length > 0) ? res.columns : ['À faire', 'En cours', 'Terminé'];
4720
4795
  var html = '<div class="mock-header"><span class="mock-title">' + escapeHtml(res.label || 'Kanban') + '</span></div>';
4721
4796
  html += '<div style="display:flex;gap:1rem;overflow-x:auto;padding-bottom:0.5rem;">';
4722
4797
 
@@ -4790,11 +4865,42 @@ function kpiDisplayValue(kpi) {
4790
4865
 
4791
4866
  /* ---------- SmartFilter ---------- */
4792
4867
  function renderSmartFilterMockup(res) {
4793
- var options = res.options || [];
4794
- var html = '<div style="display:flex;gap:0.4rem;flex-wrap:wrap;padding:0.5rem 0;">';
4795
- html += '<span style="padding:0.3rem 0.7rem;border-radius:16px;font-size:0.8rem;background:var(--primary);color:#fff;cursor:pointer;">Tous</span>';
4796
- options.forEach(function(opt) {
4797
- 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(opt) + '</span>';
4868
+ var filters = res.filters || [];
4869
+ if (filters.length === 0) {
4870
+ // Fallback: legacy options[] format (tag pills)
4871
+ var options = res.options || [];
4872
+ if (options.length === 0) return '<div style="padding:1rem;text-align:center;color:var(--text-muted);">Aucun filtre défini</div>';
4873
+ var html = '<div style="display:flex;gap:0.4rem;flex-wrap:wrap;padding:0.5rem 0;">';
4874
+ html += '<span style="padding:0.3rem 0.7rem;border-radius:16px;font-size:0.8rem;background:var(--primary);color:#fff;cursor:pointer;">Tous</span>';
4875
+ options.forEach(function(opt) {
4876
+ 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>';
4877
+ });
4878
+ html += '</div>';
4879
+ return html;
4880
+ }
4881
+
4882
+ // Rich filter bar: render each filter based on its type
4883
+ var html = '<div style="display:flex;gap:0.5rem;flex-wrap:wrap;align-items:flex-end;padding:0.5rem 0;">';
4884
+ filters.forEach(function(f) {
4885
+ var label = typeof f === 'string' ? f : (f.label || f.field || '');
4886
+ var type = typeof f === 'string' ? 'text' : (f.type || 'text');
4887
+ html += '<div style="display:flex;flex-direction:column;gap:0.2rem;">';
4888
+ html += '<span style="font-size:0.7rem;color:var(--text-muted);">' + escapeHtml(label) + '</span>';
4889
+ switch (type) {
4890
+ case 'select':
4891
+ var opts = f.options || ['Option 1', 'Option 2'];
4892
+ html += '<span class="mock-input" style="width:auto;min-width:130px;font-size:0.8rem;color:var(--text-muted);">' + escapeHtml(opts[0]) + ' &#9662;</span>';
4893
+ break;
4894
+ case 'lookup':
4895
+ html += '<span class="mock-input" style="width:auto;min-width:130px;font-size:0.8rem;color:var(--accent);">' + escapeHtml(f.entity || label) + ' &#128269;</span>';
4896
+ break;
4897
+ case 'daterange':
4898
+ 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 &#128197;</span>';
4899
+ break;
4900
+ default:
4901
+ html += '<span class="mock-input" style="width:auto;min-width:160px;font-size:0.8rem;color:var(--text-muted);">Rechercher... &#128269;</span>';
4902
+ }
4903
+ html += '</div>';
4798
4904
  });
4799
4905
  html += '</div>';
4800
4906
  return html;
@@ -5721,6 +5827,125 @@ function scrollToCommentThread(sectionId, safeElId) {
5721
5827
  }
5722
5828
  }, 100);
5723
5829
  }
5830
+
5831
+
5832
+ /* --- 12-render-diagrams.js --- */
5833
+ /* ==========================================
5834
+ MERMAID DIAGRAM RENDERING
5835
+ Renders ERD, state machines, and sequence diagrams
5836
+ from consolidation.mermaidDiagrams data.
5837
+ ========================================== */
5838
+
5839
+ function renderMermaidDiagrams() {
5840
+ const data = window.FEATURE_DATA;
5841
+ if (!data) return;
5842
+
5843
+ const diagrams = data.consolidation?.mermaidDiagrams;
5844
+ if (!diagrams) return;
5845
+
5846
+ // 1. ERD in consol-datamodel (prepend before entity cards)
5847
+ if (diagrams.erd) {
5848
+ const erdContainer = document.getElementById('dataModelContainer');
5849
+ if (erdContainer) {
5850
+ const erdDiv = document.createElement('div');
5851
+ erdDiv.className = 'diagram-container diagram-erd';
5852
+ erdDiv.innerHTML =
5853
+ '<div class="diagram-section-header">Diagramme Entit\u00e9-Relation (ERD)</div>' +
5854
+ '<div class="mermaid">' + escapeHtml(diagrams.erd) + '</div>';
5855
+ erdContainer.insertBefore(erdDiv, erdContainer.firstChild);
5856
+ }
5857
+ }
5858
+
5859
+ // 2. State machine diagrams — inject in module spec sections or consol-datamodel
5860
+ if (diagrams.stateMachines && Object.keys(diagrams.stateMachines).length > 0) {
5861
+ const smContainer = document.getElementById('dataModelContainer');
5862
+ if (smContainer) {
5863
+ const smSection = document.createElement('div');
5864
+ smSection.innerHTML = '<div class="diagram-section-header">Cycles de vie (State Machines)</div>';
5865
+
5866
+ Object.entries(diagrams.stateMachines).forEach(function(entry) {
5867
+ var entity = entry[0];
5868
+ var def = entry[1];
5869
+ var smDiv = document.createElement('div');
5870
+ smDiv.className = 'diagram-container diagram-state-machine';
5871
+ smDiv.innerHTML =
5872
+ '<h4>' + escapeHtml(entity) + '</h4>' +
5873
+ '<div class="mermaid">' + escapeHtml(def) + '</div>';
5874
+ smSection.appendChild(smDiv);
5875
+ });
5876
+
5877
+ smContainer.appendChild(smSection);
5878
+ }
5879
+ }
5880
+
5881
+ // 3. Sequence diagrams in consol-flows
5882
+ if (diagrams.sequences && Object.keys(diagrams.sequences).length > 0) {
5883
+ var flowsContainer = document.getElementById('consolFlowsContainer');
5884
+ // Fallback: try the consol-flows section
5885
+ if (!flowsContainer) {
5886
+ var consolFlows = document.getElementById('consol-flows');
5887
+ if (consolFlows) {
5888
+ flowsContainer = consolFlows.querySelector('.section-body') || consolFlows;
5889
+ }
5890
+ }
5891
+
5892
+ if (flowsContainer) {
5893
+ var seqSection = document.createElement('div');
5894
+ seqSection.innerHTML = '<div class="diagram-section-header">Diagrammes de s\u00e9quence</div>';
5895
+
5896
+ Object.entries(diagrams.sequences).forEach(function(entry) {
5897
+ var flowName = entry[0];
5898
+ var def = entry[1];
5899
+ var seqDiv = document.createElement('div');
5900
+ seqDiv.className = 'diagram-container diagram-sequence';
5901
+ seqDiv.innerHTML =
5902
+ '<h4>' + escapeHtml(flowName) + '</h4>' +
5903
+ '<div class="mermaid">' + escapeHtml(def) + '</div>';
5904
+ seqSection.appendChild(seqDiv);
5905
+ });
5906
+
5907
+ flowsContainer.appendChild(seqSection);
5908
+ }
5909
+ }
5910
+
5911
+ // 4. Render all mermaid elements
5912
+ try {
5913
+ if (typeof mermaid !== 'undefined' && mermaid.run) {
5914
+ mermaid.run({ querySelector: '.mermaid' });
5915
+ }
5916
+ } catch (e) {
5917
+ console.warn('Mermaid rendering failed:', e);
5918
+ // Fallback: show raw text
5919
+ document.querySelectorAll('.mermaid').forEach(function(el) {
5920
+ if (!el.querySelector('svg')) {
5921
+ el.style.whiteSpace = 'pre-wrap';
5922
+ el.style.fontFamily = 'monospace';
5923
+ el.style.fontSize = '0.85rem';
5924
+ el.style.color = 'var(--text-muted)';
5925
+ }
5926
+ });
5927
+ }
5928
+ }
5929
+
5930
+ // Escape HTML for safe injection
5931
+ function escapeHtml(text) {
5932
+ if (!text) return '';
5933
+ // For mermaid content, we need to preserve the syntax
5934
+ // Only escape actual HTML tags, not mermaid arrows
5935
+ return text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
5936
+ }
5937
+
5938
+ // Auto-run after consolidation rendering
5939
+ (function() {
5940
+ // Wait for DOM and other render functions to complete
5941
+ if (document.readyState === 'loading') {
5942
+ document.addEventListener('DOMContentLoaded', function() {
5943
+ setTimeout(renderMermaidDiagrams, 500);
5944
+ });
5945
+ } else {
5946
+ setTimeout(renderMermaidDiagrams, 500);
5947
+ }
5948
+ })();
5724
5949
 
5725
5950
  </script>
5726
5951
  </body>
@@ -52,9 +52,22 @@ if (!data.cadrage.scope || (!data.cadrage.scope.inscope?.length && data.cadrage.
52
52
  outofscope: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
53
53
  };
54
54
  } else {
55
+ function normScopeItem(s) {
56
+ if (typeof s === 'string') return { name: s, description: '' };
57
+ if (s.name) return s;
58
+ var nm = s.feature || s.label || s.title || JSON.stringify(s);
59
+ var parts = [];
60
+ if (s.priority) parts.push(s.priority.toUpperCase());
61
+ if (s.module) parts.push('Module: ' + s.module);
62
+ return { name: nm, description: parts.join(' — ') };
63
+ }
55
64
  data.cadrage.scope = {
56
- inscope: (gs.inScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s),
57
- outofscope: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
65
+ inscope: (gs.inScope || []).map(normScopeItem),
66
+ outofscope: (gs.outOfScope || []).map(function(s) {
67
+ if (typeof s === 'string') return { name: s, description: '' };
68
+ if (s.name) return s;
69
+ return { name: s.feature || s.reason || JSON.stringify(s), description: s.reason || '' };
70
+ })
58
71
  };
59
72
  }
60
73
  }
@@ -149,54 +149,14 @@ function renderModuleNavItem(mod) {
149
149
  var ucCount = (spec.useCases || []).length;
150
150
  var brCount = (spec.businessRules || []).length;
151
151
  var entCount = (spec.entities || []).length;
152
- var sections = (mod.anticipatedSections || []).map(function(s) {
153
- return typeof s === 'string' ? { code: s, name: s, resources: [] } : s;
154
- });
155
- var groupId = 'mod-' + code;
156
- var collapsed = navCollapseState[groupId] === true;
157
-
158
- var html = '<div class="nav-module" data-group-id="' + groupId + '">';
159
-
160
- // Module header (clickable to expand + navigate to module spec)
161
152
  var totalItems = ucCount + brCount + entCount;
162
- html += '<a class="nav-item nav-module-header" onclick="toggleNavGroup(\'' + groupId + '\');showSection(\'module-spec-' + code + '\')" data-section="module-spec-' + code + '">';
163
- html += '<span class="nav-chevron ' + (collapsed ? '' : 'expanded') + '">&#9656;</span> ';
164
- html += (mod.name || mod.code);
165
- if (totalItems > 0) html += ' <span class="nav-badge">' + totalItems + '</span>';
166
- html += '</a>';
167
-
168
- // Children: sections/resources (navigable sub-tree)
169
- // Tab-level items (UC, BR, Données, etc.) are NOT shown here — they are accessed
170
- // via the tab bar in the module content area to avoid redundancy.
171
- html += '<div class="nav-children"' + (collapsed ? ' style="display:none;"' : '') + '>';
172
- if (sections.length > 0) {
173
- sections.forEach(function(section) {
174
- var resources = section.resources || [];
175
- var sectionUCs = (section.useCases || []).length;
176
- var sectionBRs = (section.businessRules || []).length;
177
- var contentCount = sectionUCs + sectionBRs + resources.length;
178
- html += '<div class="nav-section-item">';
179
- html += '<a class="nav-item nav-section-link" onclick="showSection(\'module-spec-' + code + '\');switchTab(\'' + code + '\',\'struct\')" data-section="module-struct-' + code + '-' + section.code + '">';
180
- html += '<span class="nav-icon nav-icon-section">&#9655;</span> ' + escapeHtml(section.code || section.name || '');
181
- if (contentCount > 0) html += ' <span class="nav-badge">' + contentCount + '</span>';
182
- html += '</a>';
183
- if (resources.length > 0) {
184
- html += '<div class="nav-children nav-resources">';
185
- resources.forEach(function(res) {
186
- var resName = typeof res === 'string' ? res : (res.code || res.name || '');
187
- html += '<a class="nav-item nav-resource-link" onclick="showSection(\'module-spec-' + code + '\');switchTab(\'' + code + '\',\'mock\');scrollToMockup(\'' + code + '\',\'' + section.code + '\')">';
188
- html += '<span class="nav-icon nav-icon-resource">&#8226;</span> ' + escapeHtml(resName);
189
- html += '</a>';
190
- });
191
- html += '</div>';
192
- }
193
- html += '</div>';
194
- });
195
- }
196
153
 
197
- html += '</div>'; // nav-children
198
- html += '</div>'; // nav-module
199
- return html;
154
+ // Flat module link — sections/resources are accessible via tabs (Structure, Maquettes)
155
+ return '<a class="nav-item nav-module-header" onclick="showSection(\'module-spec-' + code + '\')" data-section="module-spec-' + code + '">' +
156
+ '<span class="nav-icon">&#9679;</span> ' +
157
+ (mod.name || mod.code) +
158
+ (totalItems > 0 ? ' <span class="nav-badge">' + totalItems + '</span>' : '') +
159
+ '</a>';
200
160
  }
201
161
 
202
162
  function renderModuleTabNavItem(code, tabId, label, badge) {