@atlashub/smartstack-cli 4.30.0 → 4.31.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 (40) hide show
  1. package/dist/index.js +17 -4
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/templates/skills/apex/references/code-generation.md +1 -1
  5. package/templates/skills/apex/references/person-extension-pattern.md +23 -2
  6. package/templates/skills/apex/references/post-checks.md +52 -0
  7. package/templates/skills/apex/references/smartstack-api.md +111 -0
  8. package/templates/skills/apex/references/smartstack-frontend.md +25 -2
  9. package/templates/skills/apex/references/smartstack-layers.md +1 -0
  10. package/templates/skills/apex/steps/step-03-execute.md +110 -7
  11. package/templates/skills/application/templates-frontend.md +1 -1
  12. package/templates/skills/ba-generate-html/SKILL.md +1 -1
  13. package/templates/skills/ba-generate-html/html/ba-interactive.html +42 -78
  14. package/templates/skills/ba-generate-html/html/src/partials/cadrage-scope.html +14 -36
  15. package/templates/skills/ba-generate-html/html/src/partials/decomp-modules.html +0 -8
  16. package/templates/skills/ba-generate-html/html/src/scripts/01-data-init.js +20 -20
  17. package/templates/skills/ba-generate-html/html/src/scripts/03-render-cadrage.js +4 -3
  18. package/templates/skills/ba-generate-html/html/src/scripts/04-render-modules.js +0 -2
  19. package/templates/skills/ba-generate-html/html/src/scripts/07-render-handoff.js +2 -5
  20. package/templates/skills/ba-generate-html/html/src/scripts/10-comments.js +1 -1
  21. package/templates/skills/ba-generate-html/html/src/styles/04-cards.css +2 -4
  22. package/templates/skills/ba-generate-html/html/src/template.html +14 -44
  23. package/templates/skills/ba-generate-html/references/data-build.md +4 -9
  24. package/templates/skills/ba-generate-html/references/data-mapping.md +2 -7
  25. package/templates/skills/ba-generate-html/references/output-modes.md +1 -1
  26. package/templates/skills/ba-generate-html/steps/step-02-build-data.md +3 -6
  27. package/templates/skills/ba-generate-html/steps/step-04-verify.md +2 -2
  28. package/templates/skills/ba-review/references/review-data-mapping.md +4 -6
  29. package/templates/skills/ba-review/steps/step-01-apply.md +2 -4
  30. package/templates/skills/business-analyse/patterns/suggestion-catalog.md +4 -4
  31. package/templates/skills/business-analyse/questionnaire.md +1 -1
  32. package/templates/skills/business-analyse/react/schema.md +2 -7
  33. package/templates/skills/business-analyse/schemas/application-schema.json +2 -9
  34. package/templates/skills/business-analyse/schemas/project-schema.json +4 -8
  35. package/templates/skills/business-analyse/schemas/sections/discovery-schema.json +1 -3
  36. package/templates/skills/business-analyse/steps/step-01-cadrage.md +5 -12
  37. package/templates/skills/business-analyse/steps/step-02-structure.md +3 -5
  38. package/templates/skills/dev-start/SKILL.md +242 -0
  39. package/templates/skills/ui-components/SKILL.md +1 -1
  40. package/templates/skills/ui-components/patterns/data-table.md +1 -1
@@ -356,10 +356,8 @@ body {
356
356
  text-transform: uppercase;
357
357
  letter-spacing: 0.05em;
358
358
  }
359
- .priority-vital { background: rgba(239,68,68,0.15); color: #f87171; border: 1px solid rgba(239,68,68,0.3); }
360
- .priority-important { background: rgba(234,179,8,0.15); color: #facc15; border: 1px solid rgba(234,179,8,0.3); }
361
- .priority-optional { background: rgba(34,197,94,0.15); color: #4ade80; border: 1px solid rgba(34,197,94,0.3); }
362
- .priority-excluded { background: rgba(100,116,139,0.15); color: #94a3b8; border: 1px solid rgba(100,116,139,0.3); }
359
+ .priority-inscope { background: rgba(59,130,246,0.15); color: #60a5fa; border: 1px solid rgba(59,130,246,0.3); }
360
+ .priority-outofscope { background: rgba(100,116,139,0.15); color: #94a3b8; border: 1px solid rgba(100,116,139,0.3); }
363
361
 
364
362
  /* ============================================
365
363
  STATUS BADGES
@@ -1902,50 +1900,28 @@ body {
1902
1900
  <!-- SECTION: Périmètre fonctionnel -->
1903
1901
  <div class="section" id="cadrage-scope" style="display:none;">
1904
1902
  <h2 class="section-title">Périmètre fonctionnel</h2>
1905
- <p class="section-subtitle">Ce que le système doit faire et ne pas faire, par ordre de priorité.</p>
1903
+ <p class="section-subtitle">Ce que le système doit faire et ne pas faire.</p>
1906
1904
 
1907
1905
  <h3 style="color: var(--text-bright); font-size: 1rem; margin-bottom: 0.75rem;">
1908
- <span style="color: #f87171;">&#9632;</span> Fonctionnalités indispensables
1906
+ <span style="color: #60a5fa;">&#9632;</span> Dans le périmètre
1909
1907
  </h3>
1910
- <div id="scopeVital" class="uc-list"></div>
1911
- <button class="add-btn" onclick="toggleForm('addScopeForm-vital')">+ Ajouter une fonctionnalité indispensable</button>
1912
- <div class="inline-form" id="addScopeForm-vital">
1913
- <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-vital" placeholder="Ex: Gestion des commandes"></div>
1914
- <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-vital" placeholder="Courte description"></div>
1915
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-vital')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('vital')">Ajouter</button></div>
1916
- </div>
1917
-
1918
- <h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
1919
- <span style="color: #facc15;">&#9632;</span> Fonctionnalités importantes
1920
- </h3>
1921
- <div id="scopeImportant" class="uc-list"></div>
1922
- <button class="add-btn" onclick="toggleForm('addScopeForm-important')">+ Ajouter une fonctionnalité importante</button>
1923
- <div class="inline-form" id="addScopeForm-important">
1924
- <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-important" placeholder="Ex: Export PDF"></div>
1925
- <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-important" placeholder="Courte description"></div>
1926
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-important')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('important')">Ajouter</button></div>
1927
- </div>
1928
-
1929
- <h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
1930
- <span style="color: #4ade80;">&#9632;</span> Fonctionnalités optionnelles
1931
- </h3>
1932
- <div id="scopeOptional" class="uc-list"></div>
1933
- <button class="add-btn" onclick="toggleForm('addScopeForm-optional')">+ Ajouter une fonctionnalité optionnelle</button>
1934
- <div class="inline-form" id="addScopeForm-optional">
1935
- <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-optional" placeholder="Ex: Calendrier partagé"></div>
1936
- <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-optional" placeholder="Courte description"></div>
1937
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-optional')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('optional')">Ajouter</button></div>
1908
+ <div id="scopeInScope" class="uc-list"></div>
1909
+ <button class="add-btn" onclick="toggleForm('addScopeForm-inscope')">+ Ajouter une fonctionnalité</button>
1910
+ <div class="inline-form" id="addScopeForm-inscope">
1911
+ <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-inscope" placeholder="Ex: Gestion des commandes"></div>
1912
+ <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-inscope" placeholder="Courte description"></div>
1913
+ <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-inscope')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('inscope')">Ajouter</button></div>
1938
1914
  </div>
1939
1915
 
1940
1916
  <h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
1941
1917
  <span style="color: #94a3b8;">&#9632;</span> Hors périmètre
1942
1918
  </h3>
1943
- <div id="scopeExcluded" class="uc-list"></div>
1944
- <button class="add-btn" onclick="toggleForm('addScopeForm-excluded')">+ Ajouter une exclusion</button>
1945
- <div class="inline-form" id="addScopeForm-excluded">
1946
- <div class="form-group"><label class="form-label">Élément hors périmètre</label><input type="text" class="form-input" id="scope-name-excluded" placeholder="Ex: Gestion de la paie"></div>
1947
- <div class="form-group"><label class="form-label">Raison (optionnel)</label><input type="text" class="form-input" id="scope-desc-excluded" placeholder="Pourquoi hors périmètre"></div>
1948
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-excluded')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('excluded')">Ajouter</button></div>
1919
+ <div id="scopeOutOfScope" class="uc-list"></div>
1920
+ <button class="add-btn" onclick="toggleForm('addScopeForm-outofscope')">+ Ajouter une exclusion</button>
1921
+ <div class="inline-form" id="addScopeForm-outofscope">
1922
+ <div class="form-group"><label class="form-label">Élément hors périmètre</label><input type="text" class="form-input" id="scope-name-outofscope" placeholder="Ex: Gestion de la paie"></div>
1923
+ <div class="form-group"><label class="form-label">Raison (optionnel)</label><input type="text" class="form-input" id="scope-desc-outofscope" placeholder="Pourquoi hors périmètre"></div>
1924
+ <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-outofscope')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('outofscope')">Ajouter</button></div>
1949
1925
  </div>
1950
1926
  </div>
1951
1927
 
@@ -2020,14 +1996,6 @@ body {
2020
1996
  <option value="full-module">Domaine complet (données + processus + rapports)</option>
2021
1997
  </select>
2022
1998
  </div>
2023
- <div class="form-group">
2024
- <label class="form-label">Priorité</label>
2025
- <select class="form-select" id="mod-priority">
2026
- <option value="must">Indispensable</option>
2027
- <option value="should">Important</option>
2028
- <option value="could">Optionnel</option>
2029
- </select>
2030
- </div>
2031
1999
  </div>
2032
2000
  <div class="form-group">
2033
2001
  <label class="form-label">Principales données gérées (une par ligne)</label>
@@ -2257,23 +2225,27 @@ data.comments = data.comments || [];
2257
2225
 
2258
2226
  // Defensive mapping: globalScope (JSON format) -> scope (HTML format)
2259
2227
  // Handles cases where FEATURE_DATA contains raw globalScope instead of pre-mapped scope
2260
- if (!data.cadrage.scope || (!data.cadrage.scope.vital?.length && data.cadrage.globalScope)) {
2228
+ if (!data.cadrage.scope || (!data.cadrage.scope.inscope?.length && data.cadrage.globalScope)) {
2261
2229
  const gs = data.cadrage.globalScope || {};
2262
- data.cadrage.scope = {
2263
- vital: (gs.mustHave || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s),
2264
- important: (gs.shouldHave || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s),
2265
- optional: (gs.couldHave || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s),
2266
- excluded: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
2267
- };
2230
+ // Backward compat: merge old MoSCoW into binary scope
2231
+ if (gs.mustHave || gs.shouldHave || gs.couldHave) {
2232
+ data.cadrage.scope = {
2233
+ inscope: [...(gs.mustHave || []), ...(gs.shouldHave || []), ...(gs.couldHave || [])].map(s => typeof s === 'string' ? { name: s, description: '' } : s),
2234
+ outofscope: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
2235
+ };
2236
+ } else {
2237
+ data.cadrage.scope = {
2238
+ inscope: (gs.inScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s),
2239
+ outofscope: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
2240
+ };
2241
+ }
2268
2242
  }
2269
- data.cadrage.scope = data.cadrage.scope || { vital: [], important: [], optional: [], excluded: [] };
2243
+ data.cadrage.scope = data.cadrage.scope || { inscope: [], outofscope: [] };
2270
2244
 
2271
- // Backward compat: mustHave/shouldHave/couldHave/wontHave vital/important/optional/excluded
2272
- if (data.cadrage.scope.mustHave && !data.cadrage.scope.vital?.length) {
2273
- data.cadrage.scope.vital = data.cadrage.scope.mustHave;
2274
- data.cadrage.scope.important = data.cadrage.scope.shouldHave || data.cadrage.scope.important || [];
2275
- data.cadrage.scope.optional = data.cadrage.scope.couldHave || data.cadrage.scope.optional || [];
2276
- data.cadrage.scope.excluded = data.cadrage.scope.wontHave || data.cadrage.scope.excluded || [];
2245
+ // Backward compat: old vital/important/optional/excluded → inscope/outofscope
2246
+ if (data.cadrage.scope.vital && !data.cadrage.scope.inscope?.length) {
2247
+ data.cadrage.scope.inscope = [...(data.cadrage.scope.vital || []), ...(data.cadrage.scope.important || []), ...(data.cadrage.scope.optional || [])];
2248
+ data.cadrage.scope.outofscope = data.cadrage.scope.excluded || data.cadrage.scope.outofscope || [];
2277
2249
  }
2278
2250
 
2279
2251
  // Defensive init: moduleSpecs (may be missing if LLM didn't follow mapping)
@@ -2352,7 +2324,7 @@ function formatAccess(a) {
2352
2324
  }
2353
2325
 
2354
2326
  function formatPriority(p) {
2355
- return { vital: 'Indispensable', important: 'Important', optional: 'Optionnel', excluded: 'Hors périmètre' }[p] || p;
2327
+ return { inscope: 'Dans le périmètre', outofscope: 'Hors périmètre' }[p] || p;
2356
2328
  }
2357
2329
 
2358
2330
  function formatLevel(l) {
@@ -2363,10 +2335,6 @@ function formatModuleType(t) {
2363
2335
  return { 'data-centric': 'Données', 'workflow': 'Processus', 'reporting': 'Rapports', 'integration': 'Intégration', 'full-module': 'Complet' }[t] || t;
2364
2336
  }
2365
2337
 
2366
- function formatModulePriority(p) {
2367
- return { must: 'Indispensable', should: 'Important', could: 'Optionnel' }[p] || p;
2368
- }
2369
-
2370
2338
  /* ============================================
2371
2339
  INITIALIZATION
2372
2340
  ============================================ */
@@ -2734,9 +2702,10 @@ function addScopeItem(priority) {
2734
2702
  }
2735
2703
 
2736
2704
  function renderScope() {
2737
- ['vital', 'important', 'optional', 'excluded'].forEach(p => {
2738
- const container = document.getElementById('scope' + p.charAt(0).toUpperCase() + p.slice(1));
2739
- container.innerHTML = data.cadrage.scope[p].map((item, i) => `
2705
+ ['inscope', 'outofscope'].forEach(p => {
2706
+ const container = document.getElementById('scope' + (p === 'inscope' ? 'InScope' : 'OutOfScope'));
2707
+ if (!container) return;
2708
+ container.innerHTML = (data.cadrage.scope[p] || []).map((item, i) => `
2740
2709
  <div class="uc-item">
2741
2710
  <div class="uc-header">
2742
2711
  <span class="priority priority-${p}">${formatPriority(p)}</span>
@@ -2826,7 +2795,6 @@ function addModule() {
2826
2795
  name: name,
2827
2796
  description: document.getElementById('mod-desc').value.trim(),
2828
2797
  featureType: document.getElementById('mod-type').value,
2829
- priority: document.getElementById('mod-priority').value,
2830
2798
  entities: document.getElementById('mod-entities').value.split('\n').filter(e => e.trim()),
2831
2799
  anticipatedSections: [],
2832
2800
  status: 'pending'
@@ -2876,7 +2844,6 @@ function renderModules() {
2876
2844
  </div>
2877
2845
  <div class="module-card-desc">${m.description || ''}</div>
2878
2846
  <div class="module-card-meta">
2879
- <span class="priority priority-${m.priority === 'must' ? 'vital' : m.priority === 'should' ? 'important' : 'optional'}">${formatModulePriority(m.priority)}</span>
2880
2847
  <span>${(m.entities || []).length} données</span>
2881
2848
  <span>${(data.moduleSpecs[m.code]?.useCases || []).length} cas d'utilisation</span>
2882
2849
  </div>
@@ -4333,7 +4300,6 @@ function renderHandoffModules() {
4333
4300
  <span>${(spec.businessRules || []).length} règles</span>
4334
4301
  <span>${(spec.entities || []).length} données</span>
4335
4302
  </div>
4336
- <span class="priority priority-${m.priority === 'must' ? 'vital' : m.priority === 'should' ? 'important' : 'optional'}">${formatModulePriority(m.priority)}</span>
4337
4303
  </div>
4338
4304
  </div>`;
4339
4305
  }).join('');
@@ -4343,9 +4309,7 @@ function renderCoverageMatrix() {
4343
4309
  const container = document.getElementById('coverageMatrix');
4344
4310
  if (!container) return;
4345
4311
 
4346
- const allScope = ['vital', 'important', 'optional'].flatMap(p =>
4347
- (data.cadrage.scope[p] || []).map(item => ({ ...item, priority: p }))
4348
- );
4312
+ const allScope = (data.cadrage.scope.inscope || []).map(item => ({ ...item, priority: 'inscope' }));
4349
4313
 
4350
4314
  if (allScope.length === 0) {
4351
4315
  container.innerHTML = '<p style="color:var(--text-muted);font-style:italic;">Aucun élément de périmètre défini dans le cadrage.</p>';
@@ -4354,7 +4318,7 @@ function renderCoverageMatrix() {
4354
4318
 
4355
4319
  container.innerHTML = `
4356
4320
  <table class="mock-table" style="background:var(--bg-card);border-radius:8px;overflow:hidden;">
4357
- <thead><tr><th>Besoin</th><th>Priorité</th><th>Domaine</th><th>Couvert</th></tr></thead>
4321
+ <thead><tr><th>Besoin</th><th>Périmètre</th><th>Domaine</th><th>Couvert</th></tr></thead>
4358
4322
  <tbody>
4359
4323
  ${allScope.map(item => {
4360
4324
  const moduleName = item.module
@@ -4731,7 +4695,7 @@ function initInlineComments() {
4731
4695
  });
4732
4696
 
4733
4697
  // Scope items
4734
- ['scopeVital', 'scopeImportant', 'scopeOptional', 'scopeExcluded'].forEach(function(containerId) {
4698
+ ['scopeInScope', 'scopeOutOfScope'].forEach(function(containerId) {
4735
4699
  var container = document.getElementById(containerId);
4736
4700
  if (!container) return;
4737
4701
  container.querySelectorAll('.uc-item').forEach(function(item, index) {
@@ -1,49 +1,27 @@
1
1
  <!-- SECTION: Périmètre fonctionnel -->
2
2
  <div class="section" id="cadrage-scope" style="display:none;">
3
3
  <h2 class="section-title">Périmètre fonctionnel</h2>
4
- <p class="section-subtitle">Ce que le système doit faire et ne pas faire, par ordre de priorité.</p>
4
+ <p class="section-subtitle">Ce que le système doit faire et ne pas faire.</p>
5
5
 
6
6
  <h3 style="color: var(--text-bright); font-size: 1rem; margin-bottom: 0.75rem;">
7
- <span style="color: #f87171;">&#9632;</span> Fonctionnalités indispensables
7
+ <span style="color: #60a5fa;">&#9632;</span> Dans le périmètre
8
8
  </h3>
9
- <div id="scopeVital" class="uc-list"></div>
10
- <button class="add-btn" onclick="toggleForm('addScopeForm-vital')">+ Ajouter une fonctionnalité indispensable</button>
11
- <div class="inline-form" id="addScopeForm-vital">
12
- <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-vital" placeholder="Ex: Gestion des commandes"></div>
13
- <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-vital" placeholder="Courte description"></div>
14
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-vital')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('vital')">Ajouter</button></div>
15
- </div>
16
-
17
- <h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
18
- <span style="color: #facc15;">&#9632;</span> Fonctionnalités importantes
19
- </h3>
20
- <div id="scopeImportant" class="uc-list"></div>
21
- <button class="add-btn" onclick="toggleForm('addScopeForm-important')">+ Ajouter une fonctionnalité importante</button>
22
- <div class="inline-form" id="addScopeForm-important">
23
- <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-important" placeholder="Ex: Export PDF"></div>
24
- <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-important" placeholder="Courte description"></div>
25
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-important')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('important')">Ajouter</button></div>
26
- </div>
27
-
28
- <h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
29
- <span style="color: #4ade80;">&#9632;</span> Fonctionnalités optionnelles
30
- </h3>
31
- <div id="scopeOptional" class="uc-list"></div>
32
- <button class="add-btn" onclick="toggleForm('addScopeForm-optional')">+ Ajouter une fonctionnalité optionnelle</button>
33
- <div class="inline-form" id="addScopeForm-optional">
34
- <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-optional" placeholder="Ex: Calendrier partagé"></div>
35
- <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-optional" placeholder="Courte description"></div>
36
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-optional')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('optional')">Ajouter</button></div>
9
+ <div id="scopeInScope" class="uc-list"></div>
10
+ <button class="add-btn" onclick="toggleForm('addScopeForm-inscope')">+ Ajouter une fonctionnalité</button>
11
+ <div class="inline-form" id="addScopeForm-inscope">
12
+ <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-inscope" placeholder="Ex: Gestion des commandes"></div>
13
+ <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-inscope" placeholder="Courte description"></div>
14
+ <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-inscope')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('inscope')">Ajouter</button></div>
37
15
  </div>
38
16
 
39
17
  <h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
40
18
  <span style="color: #94a3b8;">&#9632;</span> Hors périmètre
41
19
  </h3>
42
- <div id="scopeExcluded" class="uc-list"></div>
43
- <button class="add-btn" onclick="toggleForm('addScopeForm-excluded')">+ Ajouter une exclusion</button>
44
- <div class="inline-form" id="addScopeForm-excluded">
45
- <div class="form-group"><label class="form-label">Élément hors périmètre</label><input type="text" class="form-input" id="scope-name-excluded" placeholder="Ex: Gestion de la paie"></div>
46
- <div class="form-group"><label class="form-label">Raison (optionnel)</label><input type="text" class="form-input" id="scope-desc-excluded" placeholder="Pourquoi hors périmètre"></div>
47
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-excluded')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('excluded')">Ajouter</button></div>
20
+ <div id="scopeOutOfScope" class="uc-list"></div>
21
+ <button class="add-btn" onclick="toggleForm('addScopeForm-outofscope')">+ Ajouter une exclusion</button>
22
+ <div class="inline-form" id="addScopeForm-outofscope">
23
+ <div class="form-group"><label class="form-label">Élément hors périmètre</label><input type="text" class="form-input" id="scope-name-outofscope" placeholder="Ex: Gestion de la paie"></div>
24
+ <div class="form-group"><label class="form-label">Raison (optionnel)</label><input type="text" class="form-input" id="scope-desc-outofscope" placeholder="Pourquoi hors périmètre"></div>
25
+ <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-outofscope')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('outofscope')">Ajouter</button></div>
48
26
  </div>
49
27
  </div>
@@ -30,14 +30,6 @@
30
30
  <option value="full-module">Domaine complet (données + processus + rapports)</option>
31
31
  </select>
32
32
  </div>
33
- <div class="form-group">
34
- <label class="form-label">Priorité</label>
35
- <select class="form-select" id="mod-priority">
36
- <option value="must">Indispensable</option>
37
- <option value="should">Important</option>
38
- <option value="could">Optionnel</option>
39
- </select>
40
- </div>
41
33
  </div>
42
34
  <div class="form-group">
43
35
  <label class="form-label">Principales données gérées (une par ligne)</label>
@@ -36,23 +36,27 @@ data.comments = data.comments || [];
36
36
 
37
37
  // Defensive mapping: globalScope (JSON format) -> scope (HTML format)
38
38
  // Handles cases where FEATURE_DATA contains raw globalScope instead of pre-mapped scope
39
- if (!data.cadrage.scope || (!data.cadrage.scope.vital?.length && data.cadrage.globalScope)) {
39
+ if (!data.cadrage.scope || (!data.cadrage.scope.inscope?.length && data.cadrage.globalScope)) {
40
40
  const gs = data.cadrage.globalScope || {};
41
- data.cadrage.scope = {
42
- vital: (gs.mustHave || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s),
43
- important: (gs.shouldHave || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s),
44
- optional: (gs.couldHave || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s),
45
- excluded: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
46
- };
41
+ // Backward compat: merge old MoSCoW into binary scope
42
+ if (gs.mustHave || gs.shouldHave || gs.couldHave) {
43
+ data.cadrage.scope = {
44
+ inscope: [...(gs.mustHave || []), ...(gs.shouldHave || []), ...(gs.couldHave || [])].map(s => typeof s === 'string' ? { name: s, description: '' } : s),
45
+ outofscope: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
46
+ };
47
+ } else {
48
+ data.cadrage.scope = {
49
+ inscope: (gs.inScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s),
50
+ outofscope: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
51
+ };
52
+ }
47
53
  }
48
- data.cadrage.scope = data.cadrage.scope || { vital: [], important: [], optional: [], excluded: [] };
49
-
50
- // Backward compat: mustHave/shouldHave/couldHave/wontHave vital/important/optional/excluded
51
- if (data.cadrage.scope.mustHave && !data.cadrage.scope.vital?.length) {
52
- data.cadrage.scope.vital = data.cadrage.scope.mustHave;
53
- data.cadrage.scope.important = data.cadrage.scope.shouldHave || data.cadrage.scope.important || [];
54
- data.cadrage.scope.optional = data.cadrage.scope.couldHave || data.cadrage.scope.optional || [];
55
- data.cadrage.scope.excluded = data.cadrage.scope.wontHave || data.cadrage.scope.excluded || [];
54
+ data.cadrage.scope = data.cadrage.scope || { inscope: [], outofscope: [] };
55
+
56
+ // Backward compat: old vital/important/optional/excluded → inscope/outofscope
57
+ if (data.cadrage.scope.vital && !data.cadrage.scope.inscope?.length) {
58
+ data.cadrage.scope.inscope = [...(data.cadrage.scope.vital || []), ...(data.cadrage.scope.important || []), ...(data.cadrage.scope.optional || [])];
59
+ data.cadrage.scope.outofscope = data.cadrage.scope.excluded || data.cadrage.scope.outofscope || [];
56
60
  }
57
61
 
58
62
  // Defensive init: moduleSpecs (may be missing if LLM didn't follow mapping)
@@ -131,7 +135,7 @@ function formatAccess(a) {
131
135
  }
132
136
 
133
137
  function formatPriority(p) {
134
- return { vital: 'Indispensable', important: 'Important', optional: 'Optionnel', excluded: 'Hors périmètre' }[p] || p;
138
+ return { inscope: 'Dans le périmètre', outofscope: 'Hors périmètre' }[p] || p;
135
139
  }
136
140
 
137
141
  function formatLevel(l) {
@@ -142,10 +146,6 @@ function formatModuleType(t) {
142
146
  return { 'data-centric': 'Données', 'workflow': 'Processus', 'reporting': 'Rapports', 'integration': 'Intégration', 'full-module': 'Complet' }[t] || t;
143
147
  }
144
148
 
145
- function formatModulePriority(p) {
146
- return { must: 'Indispensable', should: 'Important', could: 'Optionnel' }[p] || p;
147
- }
148
-
149
149
  /* ============================================
150
150
  INITIALIZATION
151
151
  ============================================ */
@@ -82,9 +82,10 @@ function addScopeItem(priority) {
82
82
  }
83
83
 
84
84
  function renderScope() {
85
- ['vital', 'important', 'optional', 'excluded'].forEach(p => {
86
- const container = document.getElementById('scope' + p.charAt(0).toUpperCase() + p.slice(1));
87
- container.innerHTML = data.cadrage.scope[p].map((item, i) => `
85
+ ['inscope', 'outofscope'].forEach(p => {
86
+ const container = document.getElementById('scope' + (p === 'inscope' ? 'InScope' : 'OutOfScope'));
87
+ if (!container) return;
88
+ container.innerHTML = (data.cadrage.scope[p] || []).map((item, i) => `
88
89
  <div class="uc-item">
89
90
  <div class="uc-header">
90
91
  <span class="priority priority-${p}">${formatPriority(p)}</span>
@@ -11,7 +11,6 @@ function addModule() {
11
11
  name: name,
12
12
  description: document.getElementById('mod-desc').value.trim(),
13
13
  featureType: document.getElementById('mod-type').value,
14
- priority: document.getElementById('mod-priority').value,
15
14
  entities: document.getElementById('mod-entities').value.split('\n').filter(e => e.trim()),
16
15
  anticipatedSections: [],
17
16
  status: 'pending'
@@ -61,7 +60,6 @@ function renderModules() {
61
60
  </div>
62
61
  <div class="module-card-desc">${m.description || ''}</div>
63
62
  <div class="module-card-meta">
64
- <span class="priority priority-${m.priority === 'must' ? 'vital' : m.priority === 'should' ? 'important' : 'optional'}">${formatModulePriority(m.priority)}</span>
65
63
  <span>${(m.entities || []).length} données</span>
66
64
  <span>${(data.moduleSpecs[m.code]?.useCases || []).length} cas d'utilisation</span>
67
65
  </div>
@@ -51,7 +51,6 @@ function renderHandoffModules() {
51
51
  <span>${(spec.businessRules || []).length} règles</span>
52
52
  <span>${(spec.entities || []).length} données</span>
53
53
  </div>
54
- <span class="priority priority-${m.priority === 'must' ? 'vital' : m.priority === 'should' ? 'important' : 'optional'}">${formatModulePriority(m.priority)}</span>
55
54
  </div>
56
55
  </div>`;
57
56
  }).join('');
@@ -61,9 +60,7 @@ function renderCoverageMatrix() {
61
60
  const container = document.getElementById('coverageMatrix');
62
61
  if (!container) return;
63
62
 
64
- const allScope = ['vital', 'important', 'optional'].flatMap(p =>
65
- (data.cadrage.scope[p] || []).map(item => ({ ...item, priority: p }))
66
- );
63
+ const allScope = (data.cadrage.scope.inscope || []).map(item => ({ ...item, priority: 'inscope' }));
67
64
 
68
65
  if (allScope.length === 0) {
69
66
  container.innerHTML = '<p style="color:var(--text-muted);font-style:italic;">Aucun élément de périmètre défini dans le cadrage.</p>';
@@ -72,7 +69,7 @@ function renderCoverageMatrix() {
72
69
 
73
70
  container.innerHTML = `
74
71
  <table class="mock-table" style="background:var(--bg-card);border-radius:8px;overflow:hidden;">
75
- <thead><tr><th>Besoin</th><th>Priorité</th><th>Domaine</th><th>Couvert</th></tr></thead>
72
+ <thead><tr><th>Besoin</th><th>Périmètre</th><th>Domaine</th><th>Couvert</th></tr></thead>
76
73
  <tbody>
77
74
  ${allScope.map(item => {
78
75
  const moduleName = item.module
@@ -48,7 +48,7 @@ function initInlineComments() {
48
48
  });
49
49
 
50
50
  // Scope items
51
- ['scopeVital', 'scopeImportant', 'scopeOptional', 'scopeExcluded'].forEach(function(containerId) {
51
+ ['scopeInScope', 'scopeOutOfScope'].forEach(function(containerId) {
52
52
  var container = document.getElementById(containerId);
53
53
  if (!container) return;
54
54
  container.querySelectorAll('.uc-item').forEach(function(item, index) {
@@ -80,10 +80,8 @@
80
80
  text-transform: uppercase;
81
81
  letter-spacing: 0.05em;
82
82
  }
83
- .priority-vital { background: rgba(239,68,68,0.15); color: #f87171; border: 1px solid rgba(239,68,68,0.3); }
84
- .priority-important { background: rgba(234,179,8,0.15); color: #facc15; border: 1px solid rgba(234,179,8,0.3); }
85
- .priority-optional { background: rgba(34,197,94,0.15); color: #4ade80; border: 1px solid rgba(34,197,94,0.3); }
86
- .priority-excluded { background: rgba(100,116,139,0.15); color: #94a3b8; border: 1px solid rgba(100,116,139,0.3); }
83
+ .priority-inscope { background: rgba(59,130,246,0.15); color: #60a5fa; border: 1px solid rgba(59,130,246,0.3); }
84
+ .priority-outofscope { background: rgba(100,116,139,0.15); color: #94a3b8; border: 1px solid rgba(100,116,139,0.3); }
87
85
 
88
86
  /* ============================================
89
87
  STATUS BADGES
@@ -145,50 +145,28 @@
145
145
  <!-- SECTION: Périmètre fonctionnel -->
146
146
  <div class="section" id="cadrage-scope" style="display:none;">
147
147
  <h2 class="section-title">Périmètre fonctionnel</h2>
148
- <p class="section-subtitle">Ce que le système doit faire et ne pas faire, par ordre de priorité.</p>
148
+ <p class="section-subtitle">Ce que le système doit faire et ne pas faire.</p>
149
149
 
150
150
  <h3 style="color: var(--text-bright); font-size: 1rem; margin-bottom: 0.75rem;">
151
- <span style="color: #f87171;">&#9632;</span> Fonctionnalités indispensables
151
+ <span style="color: #60a5fa;">&#9632;</span> Dans le périmètre
152
152
  </h3>
153
- <div id="scopeVital" class="uc-list"></div>
154
- <button class="add-btn" onclick="toggleForm('addScopeForm-vital')">+ Ajouter une fonctionnalité indispensable</button>
155
- <div class="inline-form" id="addScopeForm-vital">
156
- <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-vital" placeholder="Ex: Gestion des commandes"></div>
157
- <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-vital" placeholder="Courte description"></div>
158
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-vital')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('vital')">Ajouter</button></div>
159
- </div>
160
-
161
- <h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
162
- <span style="color: #facc15;">&#9632;</span> Fonctionnalités importantes
163
- </h3>
164
- <div id="scopeImportant" class="uc-list"></div>
165
- <button class="add-btn" onclick="toggleForm('addScopeForm-important')">+ Ajouter une fonctionnalité importante</button>
166
- <div class="inline-form" id="addScopeForm-important">
167
- <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-important" placeholder="Ex: Export PDF"></div>
168
- <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-important" placeholder="Courte description"></div>
169
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-important')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('important')">Ajouter</button></div>
170
- </div>
171
-
172
- <h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
173
- <span style="color: #4ade80;">&#9632;</span> Fonctionnalités optionnelles
174
- </h3>
175
- <div id="scopeOptional" class="uc-list"></div>
176
- <button class="add-btn" onclick="toggleForm('addScopeForm-optional')">+ Ajouter une fonctionnalité optionnelle</button>
177
- <div class="inline-form" id="addScopeForm-optional">
178
- <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-optional" placeholder="Ex: Calendrier partagé"></div>
179
- <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-optional" placeholder="Courte description"></div>
180
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-optional')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('optional')">Ajouter</button></div>
153
+ <div id="scopeInScope" class="uc-list"></div>
154
+ <button class="add-btn" onclick="toggleForm('addScopeForm-inscope')">+ Ajouter une fonctionnalité</button>
155
+ <div class="inline-form" id="addScopeForm-inscope">
156
+ <div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-inscope" placeholder="Ex: Gestion des commandes"></div>
157
+ <div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-inscope" placeholder="Courte description"></div>
158
+ <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-inscope')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('inscope')">Ajouter</button></div>
181
159
  </div>
182
160
 
183
161
  <h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
184
162
  <span style="color: #94a3b8;">&#9632;</span> Hors périmètre
185
163
  </h3>
186
- <div id="scopeExcluded" class="uc-list"></div>
187
- <button class="add-btn" onclick="toggleForm('addScopeForm-excluded')">+ Ajouter une exclusion</button>
188
- <div class="inline-form" id="addScopeForm-excluded">
189
- <div class="form-group"><label class="form-label">Élément hors périmètre</label><input type="text" class="form-input" id="scope-name-excluded" placeholder="Ex: Gestion de la paie"></div>
190
- <div class="form-group"><label class="form-label">Raison (optionnel)</label><input type="text" class="form-input" id="scope-desc-excluded" placeholder="Pourquoi hors périmètre"></div>
191
- <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-excluded')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('excluded')">Ajouter</button></div>
164
+ <div id="scopeOutOfScope" class="uc-list"></div>
165
+ <button class="add-btn" onclick="toggleForm('addScopeForm-outofscope')">+ Ajouter une exclusion</button>
166
+ <div class="inline-form" id="addScopeForm-outofscope">
167
+ <div class="form-group"><label class="form-label">Élément hors périmètre</label><input type="text" class="form-input" id="scope-name-outofscope" placeholder="Ex: Gestion de la paie"></div>
168
+ <div class="form-group"><label class="form-label">Raison (optionnel)</label><input type="text" class="form-input" id="scope-desc-outofscope" placeholder="Pourquoi hors périmètre"></div>
169
+ <div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-outofscope')">Annuler</button><button class="btn btn-primary" onclick="addScopeItem('outofscope')">Ajouter</button></div>
192
170
  </div>
193
171
  </div>
194
172
 
@@ -263,14 +241,6 @@
263
241
  <option value="full-module">Domaine complet (données + processus + rapports)</option>
264
242
  </select>
265
243
  </div>
266
- <div class="form-group">
267
- <label class="form-label">Priorité</label>
268
- <select class="form-select" id="mod-priority">
269
- <option value="must">Indispensable</option>
270
- <option value="should">Important</option>
271
- <option value="could">Optionnel</option>
272
- </select>
273
- </div>
274
244
  </div>
275
245
  <div class="form-group">
276
246
  <label class="form-label">Principales données gérées (une par ligne)</label>
@@ -26,15 +26,11 @@ const FEATURE_DATA = {
26
26
  },
27
27
  scope: {
28
28
  // CONVERT index.json keys to HTML keys:
29
- // mustHavevital, shouldHave → important, couldHave → optional, outOfScope → excluded
29
+ // inScopeinscope, outOfScope → outofscope
30
30
  // CRITICAL: Preserve per-item `module` assignment from coverageMatrix (NOT modules[0])
31
- vital: (master.cadrage.globalScope?.mustHave || master.cadrage.coverageMatrix?.filter(i => i.category === "mustHave") || [])
31
+ inscope: (master.cadrage.globalScope?.inScope || master.cadrage.coverageMatrix?.filter(i => i.category === "inScope") || [])
32
32
  .map(item => typeof item === 'string' ? { name: item, description: "", module: null } : { name: item.item || item, description: item.notes || "", module: item.module || null }),
33
- important: (master.cadrage.globalScope?.shouldHave || master.cadrage.coverageMatrix?.filter(i => i.category === "shouldHave") || [])
34
- .map(item => typeof item === 'string' ? { name: item, description: "", module: null } : { name: item.item || item, description: item.notes || "", module: item.module || null }),
35
- optional: (master.cadrage.globalScope?.couldHave || master.cadrage.coverageMatrix?.filter(i => i.category === "couldHave") || [])
36
- .map(item => typeof item === 'string' ? { name: item, description: "", module: null } : { name: item.item || item, description: item.notes || "", module: item.module || null }),
37
- excluded: (master.cadrage.globalScope?.outOfScope || master.cadrage.coverageMatrix?.filter(i => i.category === "outOfScope") || [])
33
+ outofscope: (master.cadrage.globalScope?.outOfScope || master.cadrage.coverageMatrix?.filter(i => i.category === "outOfScope") || [])
38
34
  .map(item => typeof item === 'string' ? { name: item, description: "", module: null } : { name: item.item || item, description: item.notes || "", module: item.module || null })
39
35
  },
40
36
  stakeholders: (master.cadrage.stakeholders || []).map(s => ({
@@ -53,7 +49,6 @@ const FEATURE_DATA = {
53
49
  name: module.name || module.code, // Display name (e.g., "Gestion du temps") — MANDATORY
54
50
  description: module.description || "",
55
51
  featureType: module.featureType || "data-centric",
56
- priority: module.priority || "must",
57
52
  estimatedComplexity: module.estimatedComplexity || "medium",
58
53
  entities: module.entities || [],
59
54
  anticipatedSections: module.anticipatedSections || [],
@@ -104,7 +99,7 @@ const FEATURE_DATA = {
104
99
  ### Build Process
105
100
 
106
101
  1. Extract metadata from master index.json
107
- 2. Extract cadrage from master cadrage.json (CONVERT scope keys)
102
+ 2. Extract cadrage from master cadrage.json (CONVERT scope keys: inScope→inscope, outOfScope→outofscope)
108
103
  3. Extract stakeholders from master cadrage.stakeholders
109
104
  4. Iterate ALL modules and populate moduleSpecs (THIS IS CRITICAL — empty moduleSpecs = BUG)
110
105
  5. For EACH module, read FLAT FILES from `collected_data.modules[moduleCode]`: