@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.
- package/dist/index.js +17 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/skills/apex/references/code-generation.md +1 -1
- package/templates/skills/apex/references/person-extension-pattern.md +23 -2
- package/templates/skills/apex/references/post-checks.md +52 -0
- package/templates/skills/apex/references/smartstack-api.md +111 -0
- package/templates/skills/apex/references/smartstack-frontend.md +25 -2
- package/templates/skills/apex/references/smartstack-layers.md +1 -0
- package/templates/skills/apex/steps/step-03-execute.md +110 -7
- package/templates/skills/application/templates-frontend.md +1 -1
- package/templates/skills/ba-generate-html/SKILL.md +1 -1
- package/templates/skills/ba-generate-html/html/ba-interactive.html +42 -78
- package/templates/skills/ba-generate-html/html/src/partials/cadrage-scope.html +14 -36
- package/templates/skills/ba-generate-html/html/src/partials/decomp-modules.html +0 -8
- package/templates/skills/ba-generate-html/html/src/scripts/01-data-init.js +20 -20
- package/templates/skills/ba-generate-html/html/src/scripts/03-render-cadrage.js +4 -3
- package/templates/skills/ba-generate-html/html/src/scripts/04-render-modules.js +0 -2
- package/templates/skills/ba-generate-html/html/src/scripts/07-render-handoff.js +2 -5
- package/templates/skills/ba-generate-html/html/src/scripts/10-comments.js +1 -1
- package/templates/skills/ba-generate-html/html/src/styles/04-cards.css +2 -4
- package/templates/skills/ba-generate-html/html/src/template.html +14 -44
- package/templates/skills/ba-generate-html/references/data-build.md +4 -9
- package/templates/skills/ba-generate-html/references/data-mapping.md +2 -7
- package/templates/skills/ba-generate-html/references/output-modes.md +1 -1
- package/templates/skills/ba-generate-html/steps/step-02-build-data.md +3 -6
- package/templates/skills/ba-generate-html/steps/step-04-verify.md +2 -2
- package/templates/skills/ba-review/references/review-data-mapping.md +4 -6
- package/templates/skills/ba-review/steps/step-01-apply.md +2 -4
- package/templates/skills/business-analyse/patterns/suggestion-catalog.md +4 -4
- package/templates/skills/business-analyse/questionnaire.md +1 -1
- package/templates/skills/business-analyse/react/schema.md +2 -7
- package/templates/skills/business-analyse/schemas/application-schema.json +2 -9
- package/templates/skills/business-analyse/schemas/project-schema.json +4 -8
- package/templates/skills/business-analyse/schemas/sections/discovery-schema.json +1 -3
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +5 -12
- package/templates/skills/business-analyse/steps/step-02-structure.md +3 -5
- package/templates/skills/dev-start/SKILL.md +242 -0
- package/templates/skills/ui-components/SKILL.md +1 -1
- 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-
|
|
360
|
-
.priority-
|
|
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
|
|
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: #
|
|
1906
|
+
<span style="color: #60a5fa;">■</span> Dans le périmètre
|
|
1909
1907
|
</h3>
|
|
1910
|
-
<div id="
|
|
1911
|
-
<button class="add-btn" onclick="toggleForm('addScopeForm-
|
|
1912
|
-
<div class="inline-form" id="addScopeForm-
|
|
1913
|
-
<div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-
|
|
1914
|
-
<div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-
|
|
1915
|
-
<div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-
|
|
1916
|
-
</div>
|
|
1917
|
-
|
|
1918
|
-
<h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
|
|
1919
|
-
<span style="color: #facc15;">■</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;">■</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;">■</span> Hors périmètre
|
|
1942
1918
|
</h3>
|
|
1943
|
-
<div id="
|
|
1944
|
-
<button class="add-btn" onclick="toggleForm('addScopeForm-
|
|
1945
|
-
<div class="inline-form" id="addScopeForm-
|
|
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-
|
|
1947
|
-
<div class="form-group"><label class="form-label">Raison (optionnel)</label><input type="text" class="form-input" id="scope-desc-
|
|
1948
|
-
<div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-
|
|
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.
|
|
2228
|
+
if (!data.cadrage.scope || (!data.cadrage.scope.inscope?.length && data.cadrage.globalScope)) {
|
|
2261
2229
|
const gs = data.cadrage.globalScope || {};
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
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 || {
|
|
2243
|
+
data.cadrage.scope = data.cadrage.scope || { inscope: [], outofscope: [] };
|
|
2270
2244
|
|
|
2271
|
-
// Backward compat:
|
|
2272
|
-
if (data.cadrage.scope.
|
|
2273
|
-
data.cadrage.scope.
|
|
2274
|
-
data.cadrage.scope.
|
|
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 {
|
|
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
|
-
['
|
|
2738
|
-
const container = document.getElementById('scope' + p
|
|
2739
|
-
|
|
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 = [
|
|
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>
|
|
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
|
-
['
|
|
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
|
|
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: #
|
|
7
|
+
<span style="color: #60a5fa;">■</span> Dans le périmètre
|
|
8
8
|
</h3>
|
|
9
|
-
<div id="
|
|
10
|
-
<button class="add-btn" onclick="toggleForm('addScopeForm-
|
|
11
|
-
<div class="inline-form" id="addScopeForm-
|
|
12
|
-
<div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-
|
|
13
|
-
<div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-
|
|
14
|
-
<div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-
|
|
15
|
-
</div>
|
|
16
|
-
|
|
17
|
-
<h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
|
|
18
|
-
<span style="color: #facc15;">■</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;">■</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;">■</span> Hors périmètre
|
|
41
19
|
</h3>
|
|
42
|
-
<div id="
|
|
43
|
-
<button class="add-btn" onclick="toggleForm('addScopeForm-
|
|
44
|
-
<div class="inline-form" id="addScopeForm-
|
|
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-
|
|
46
|
-
<div class="form-group"><label class="form-label">Raison (optionnel)</label><input type="text" class="form-input" id="scope-desc-
|
|
47
|
-
<div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-
|
|
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.
|
|
39
|
+
if (!data.cadrage.scope || (!data.cadrage.scope.inscope?.length && data.cadrage.globalScope)) {
|
|
40
40
|
const gs = data.cadrage.globalScope || {};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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 || {
|
|
49
|
-
|
|
50
|
-
// Backward compat:
|
|
51
|
-
if (data.cadrage.scope.
|
|
52
|
-
data.cadrage.scope.
|
|
53
|
-
data.cadrage.scope.
|
|
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 {
|
|
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
|
-
['
|
|
86
|
-
const container = document.getElementById('scope' + p
|
|
87
|
-
|
|
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 = [
|
|
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>
|
|
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
|
-
['
|
|
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-
|
|
84
|
-
.priority-
|
|
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
|
|
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: #
|
|
151
|
+
<span style="color: #60a5fa;">■</span> Dans le périmètre
|
|
152
152
|
</h3>
|
|
153
|
-
<div id="
|
|
154
|
-
<button class="add-btn" onclick="toggleForm('addScopeForm-
|
|
155
|
-
<div class="inline-form" id="addScopeForm-
|
|
156
|
-
<div class="form-group"><label class="form-label">Nom de la fonctionnalité</label><input type="text" class="form-input" id="scope-name-
|
|
157
|
-
<div class="form-group"><label class="form-label">Description (optionnel)</label><input type="text" class="form-input" id="scope-desc-
|
|
158
|
-
<div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-
|
|
159
|
-
</div>
|
|
160
|
-
|
|
161
|
-
<h3 style="color: var(--text-bright); font-size: 1rem; margin: 1.5rem 0 0.75rem;">
|
|
162
|
-
<span style="color: #facc15;">■</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;">■</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;">■</span> Hors périmètre
|
|
185
163
|
</h3>
|
|
186
|
-
<div id="
|
|
187
|
-
<button class="add-btn" onclick="toggleForm('addScopeForm-
|
|
188
|
-
<div class="inline-form" id="addScopeForm-
|
|
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-
|
|
190
|
-
<div class="form-group"><label class="form-label">Raison (optionnel)</label><input type="text" class="form-input" id="scope-desc-
|
|
191
|
-
<div class="form-actions"><button class="btn" onclick="toggleForm('addScopeForm-
|
|
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
|
-
//
|
|
29
|
+
// inScope → inscope, outOfScope → outofscope
|
|
30
30
|
// CRITICAL: Preserve per-item `module` assignment from coverageMatrix (NOT modules[0])
|
|
31
|
-
|
|
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
|
-
|
|
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]`:
|