@atlashub/smartstack-cli 3.19.0 → 3.21.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 (35) hide show
  1. package/dist/index.js +53 -1
  2. package/dist/index.js.map +1 -1
  3. package/dist/mcp-entry.mjs +1 -0
  4. package/dist/mcp-entry.mjs.map +1 -1
  5. package/package.json +1 -1
  6. package/templates/agents/gitflow/cleanup.md +5 -1
  7. package/templates/agents/gitflow/finish.md +2 -0
  8. package/templates/agents/gitflow/init-clone.md +13 -0
  9. package/templates/agents/gitflow/init-validate.md +14 -0
  10. package/templates/agents/gitflow/status.md +6 -0
  11. package/templates/project/api.ts.template +8 -29
  12. package/templates/project/appsettings.json.template +1 -0
  13. package/templates/skills/business-analyse/html/ba-interactive.html +562 -150
  14. package/templates/skills/business-analyse/html/src/scripts/01-data-init.js +11 -6
  15. package/templates/skills/business-analyse/html/src/scripts/02-navigation.js +209 -4
  16. package/templates/skills/business-analyse/html/src/scripts/04-render-modules.js +2 -8
  17. package/templates/skills/business-analyse/html/src/scripts/05-render-specs.js +57 -2
  18. package/templates/skills/business-analyse/html/src/scripts/07-render-handoff.js +3 -1
  19. package/templates/skills/business-analyse/html/src/scripts/08-editing.js +112 -22
  20. package/templates/skills/business-analyse/html/src/scripts/11-review-panel.js +7 -0
  21. package/templates/skills/business-analyse/html/src/styles/02-layout.css +1 -1
  22. package/templates/skills/business-analyse/html/src/styles/03-navigation.css +89 -31
  23. package/templates/skills/business-analyse/html/src/styles/05-modules.css +64 -0
  24. package/templates/skills/business-analyse/html/src/template.html +8 -76
  25. package/templates/skills/business-analyse/references/deploy-data-build.md +9 -7
  26. package/templates/skills/business-analyse/references/html-data-mapping.md +20 -28
  27. package/templates/skills/business-analyse/references/validate-incremental-html.md +2 -1
  28. package/templates/skills/business-analyse/steps/step-02-decomposition.md +16 -3
  29. package/templates/skills/business-analyse/steps/step-03c-compile.md +55 -2
  30. package/templates/skills/business-analyse/steps/step-03d-validate.md +82 -15
  31. package/templates/skills/business-analyse/steps/step-05a-handoff.md +77 -3
  32. package/templates/skills/business-analyse/steps/step-05b-deploy.md +27 -0
  33. package/templates/skills/gitflow/_shared.md +65 -17
  34. package/templates/skills/gitflow/phases/status.md +8 -3
  35. package/templates/skills/gitflow/steps/step-start.md +3 -0
@@ -1,62 +1,120 @@
1
1
  /* ============================================
2
- SIDEBAR - Navigation 5 niveaux
2
+ SIDEBAR - Hierarchical Tree Navigation
3
3
  ============================================ */
4
- .nav-group { padding: 1rem 0; }
4
+
5
+ /* Sidebar header */
6
+ .sidebar-header {
7
+ padding: 0.75rem 1rem;
8
+ border-bottom: 1px solid var(--border);
9
+ background: var(--bg-hover);
10
+ }
11
+ .sidebar-app-name {
12
+ font-size: 0.95rem;
13
+ font-weight: 600;
14
+ color: var(--primary-light);
15
+ display: block;
16
+ white-space: nowrap;
17
+ overflow: hidden;
18
+ text-overflow: ellipsis;
19
+ }
20
+
21
+ /* Nav groups (top-level: Cadrage, Modules, Consolidation, Synthese) */
22
+ .nav-group { padding: 0.4rem 0; }
5
23
  .nav-group + .nav-group { border-top: 1px solid var(--border); }
6
24
 
7
25
  .nav-group-title {
8
- font-size: 0.65rem;
26
+ font-size: 0.7rem;
9
27
  text-transform: uppercase;
10
28
  letter-spacing: 0.1em;
11
29
  color: var(--text-muted);
12
- padding: 0 1rem;
13
- margin-bottom: 0.5rem;
30
+ padding: 0.4rem 1rem;
31
+ margin-bottom: 0.15rem;
14
32
  font-weight: 600;
33
+ cursor: pointer;
34
+ display: flex;
35
+ align-items: center;
36
+ gap: 0.3rem;
37
+ user-select: none;
38
+ transition: color var(--transition-fast);
39
+ }
40
+ .nav-group-title:hover { color: var(--text-bright); }
41
+
42
+ /* Chevron icon for expand/collapse */
43
+ .nav-chevron {
44
+ font-size: 0.6rem;
45
+ display: inline-block;
46
+ transition: transform var(--transition-fast);
47
+ color: var(--text-muted);
48
+ width: 12px;
49
+ text-align: center;
50
+ flex-shrink: 0;
15
51
  }
52
+ .nav-chevron.expanded { transform: rotate(90deg); }
16
53
 
54
+ /* Nav items (leaf nodes) */
17
55
  .nav-item {
18
56
  display: flex;
19
57
  align-items: center;
20
- gap: 0.5rem;
21
- padding: 0.45rem 1rem;
58
+ gap: 0.4rem;
59
+ padding: 0.35rem 1rem;
22
60
  color: var(--text);
23
61
  text-decoration: none;
24
- font-size: 0.85rem;
62
+ font-size: 0.82rem;
25
63
  cursor: pointer;
26
64
  transition: all var(--transition-fast);
27
65
  border-left: 3px solid transparent;
28
66
  }
29
67
  .nav-item:hover { background: var(--bg-hover); color: var(--text-bright); }
30
- .nav-item.active { background: rgba(99,102,241,0.1); border-left-color: var(--primary); color: var(--primary-light); font-weight: 500; }
68
+ .nav-item.active {
69
+ background: rgba(99,102,241,0.1);
70
+ border-left-color: var(--primary);
71
+ color: var(--primary-light);
72
+ font-weight: 500;
73
+ }
31
74
 
32
- .nav-item .nav-icon { font-size: 1rem; width: 20px; text-align: center; }
75
+ .nav-item .nav-icon {
76
+ font-size: 0.45rem;
77
+ width: 12px;
78
+ text-align: center;
79
+ color: var(--border-light);
80
+ flex-shrink: 0;
81
+ }
33
82
  .nav-item .nav-badge {
34
83
  margin-left: auto;
35
- font-size: 0.65rem;
84
+ font-size: 0.6rem;
36
85
  background: var(--bg-hover);
37
- padding: 0.1rem 0.4rem;
86
+ padding: 0.1rem 0.35rem;
38
87
  border-radius: 10px;
39
88
  color: var(--text-muted);
89
+ min-width: 16px;
90
+ text-align: center;
40
91
  }
41
92
 
42
- .nav-children { margin-left: 1.2rem; }
43
- .nav-children .nav-item { font-size: 0.8rem; padding: 0.3rem 1rem; }
93
+ /* Nested children (indented) */
94
+ .nav-children { margin-left: 0; }
95
+ .nav-children .nav-item { padding-left: 1.6rem; font-size: 0.8rem; }
96
+ .nav-children .nav-children .nav-item { padding-left: 2.4rem; font-size: 0.78rem; }
97
+ .nav-children .nav-children .nav-children .nav-item { padding-left: 3rem; font-size: 0.75rem; }
44
98
 
45
- /* ============================================
46
- PHASE PROGRESS
47
- ============================================ */
48
- .phase-progress {
49
- display: flex; align-items: center; gap: 0.3rem;
50
- padding: 0.75rem 1rem; border-bottom: 1px solid var(--border);
51
- }
52
- .phase-dot {
53
- width: 24px; height: 24px; border-radius: 50%;
54
- display: flex; align-items: center; justify-content: center;
55
- font-size: 0.6rem; font-weight: 700; color: var(--text-muted);
56
- background: var(--bg-hover); border: 2px solid var(--border);
57
- transition: all var(--transition-fast);
99
+ /* Module header in nav (collapsible) */
100
+ .nav-module-header {
101
+ font-weight: 500;
102
+ color: var(--text-bright);
103
+ font-size: 0.85rem;
104
+ }
105
+ .nav-module-header:hover { color: var(--primary-light); }
106
+
107
+ /* Section/Resource items in nav */
108
+ .nav-section-item { margin-top: 0.1rem; }
109
+ .nav-section-link { font-style: italic; }
110
+ .nav-icon-section { font-size: 0.5rem; color: var(--accent); }
111
+ .nav-icon-resource { font-size: 0.7rem; color: var(--border-light); }
112
+ .nav-resource-link {
113
+ cursor: default;
114
+ font-size: 0.72rem;
115
+ color: var(--text-muted);
116
+ padding-top: 0.2rem;
117
+ padding-bottom: 0.2rem;
58
118
  }
59
- .phase-dot.completed { background: var(--success); border-color: var(--success); color: #fff; }
60
- .phase-dot.current { background: var(--primary); border-color: var(--primary); color: #fff; }
61
- .phase-line { flex: 1; height: 2px; background: var(--border); }
62
- .phase-line.completed { background: var(--success); }
119
+ .nav-resource-link:hover { background: transparent; color: var(--text-muted); }
120
+ .nav-resources { margin-left: 0.5rem; }
@@ -388,3 +388,67 @@
388
388
  padding-left: 0.75rem; border-left: 2px solid var(--accent);
389
389
  margin-bottom: 0.2rem;
390
390
  }
391
+
392
+ /* ============================================
393
+ STRUCTURE TAB (Sections/Resources)
394
+ ============================================ */
395
+ .struct-section {
396
+ background: var(--bg-card);
397
+ border: 1px solid var(--border);
398
+ border-radius: 10px;
399
+ margin-bottom: 1rem;
400
+ overflow: hidden;
401
+ }
402
+ .struct-section-header {
403
+ display: flex;
404
+ align-items: center;
405
+ gap: 0.75rem;
406
+ padding: 0.75rem 1rem;
407
+ background: var(--bg-hover);
408
+ border-bottom: 1px solid var(--border);
409
+ }
410
+ .struct-section-code {
411
+ font-weight: 600;
412
+ color: var(--text-bright);
413
+ font-size: 0.95rem;
414
+ }
415
+ .struct-section-desc {
416
+ flex: 1;
417
+ font-size: 0.8rem;
418
+ color: var(--text-muted);
419
+ }
420
+ .struct-section-badge {
421
+ font-size: 0.65rem;
422
+ color: var(--text-muted);
423
+ background: rgba(99,102,241,0.1);
424
+ padding: 0.1rem 0.5rem;
425
+ border-radius: 4px;
426
+ white-space: nowrap;
427
+ }
428
+ .struct-resources {
429
+ padding: 0.5rem 0;
430
+ }
431
+ .struct-resource {
432
+ display: flex;
433
+ align-items: baseline;
434
+ gap: 0.5rem;
435
+ padding: 0.35rem 1rem 0.35rem 1.5rem;
436
+ font-size: 0.85rem;
437
+ transition: background var(--transition-fast);
438
+ }
439
+ .struct-resource:hover {
440
+ background: var(--bg-hover);
441
+ }
442
+ .struct-resource-icon {
443
+ color: var(--primary-light);
444
+ font-size: 0.7rem;
445
+ flex-shrink: 0;
446
+ }
447
+ .struct-resource-name {
448
+ font-weight: 500;
449
+ color: var(--text-bright);
450
+ }
451
+ .struct-resource-desc {
452
+ font-size: 0.8rem;
453
+ color: var(--text-muted);
454
+ }
@@ -20,6 +20,7 @@
20
20
  <span class="header-app-name" id="appName">{{APPLICATION_NAME}}</span>
21
21
  <div class="header-spacer"></div>
22
22
  <div class="header-actions">
23
+ <button class="btn btn-sm" onclick="resetToEmbedded()" title="Reinitialiser depuis les donnees d'origine (supprime les modifications locales)">Reset</button>
23
24
  <button class="btn btn-sm" onclick="saveToLocalStorage()" title="Sauvegarder les modifications dans le navigateur">Sauvegarder</button>
24
25
  <button class="btn btn-sm btn-review" onclick="saveReviewJSON()" title="Sauvegarder les corrections pour creer une nouvelle version">Sauvegarder corrections</button>
25
26
  <button class="btn btn-sm btn-primary" onclick="exportJSON()" title="Exporter les donnees au format JSON pour l'extraction">Exporter JSON</button>
@@ -32,85 +33,16 @@
32
33
 
33
34
  <div class="body" id="appBody">
34
35
  <!-- ============================================
35
- SIDEBAR - Navigation 5 niveaux
36
+ SIDEBAR - Navigation hierarchique
36
37
  ============================================ -->
37
38
  <aside class="sidebar">
38
- <!-- Phase Progress -->
39
- <div class="phase-progress">
40
- <div class="phase-dot current" id="phase-1" title="Cadrage">1</div>
41
- <div class="phase-line" id="pline-1"></div>
42
- <div class="phase-dot" id="phase-2" title="Decomposition">2</div>
43
- <div class="phase-line" id="pline-2"></div>
44
- <div class="phase-dot" id="phase-3" title="Specification">3</div>
45
- <div class="phase-line" id="pline-3"></div>
46
- <div class="phase-dot" id="phase-4" title="Consolidation">4</div>
47
- <div class="phase-line" id="pline-4"></div>
48
- <div class="phase-dot" id="phase-5" title="Synthese">5</div>
39
+ <!-- Application Name -->
40
+ <div class="sidebar-header">
41
+ <span class="sidebar-app-name" id="sidebarAppName">{{APPLICATION_NAME}}</span>
49
42
  </div>
50
-
51
- <!-- Phase 1 : Cadrage -->
52
- <div class="nav-group">
53
- <div class="nav-group-title">1. Cadrage</div>
54
- <a class="nav-item active" onclick="showSection('cadrage-context')" data-section="cadrage-context">
55
- <span class="nav-icon">&#9679;</span> Contexte
56
- </a>
57
- <a class="nav-item" onclick="showSection('cadrage-stakeholders')" data-section="cadrage-stakeholders">
58
- <span class="nav-icon">&#9679;</span> Parties prenantes
59
- <span class="nav-badge" id="stakeholderCount">0</span>
60
- </a>
61
- <a class="nav-item" onclick="showSection('cadrage-scope')" data-section="cadrage-scope">
62
- <span class="nav-icon">&#9679;</span> Perimetre fonctionnel
63
- </a>
64
- <a class="nav-item" onclick="showSection('cadrage-risks')" data-section="cadrage-risks">
65
- <span class="nav-icon">&#9679;</span> Risques et hypotheses
66
- </a>
67
- <a class="nav-item" onclick="showSection('cadrage-success')" data-section="cadrage-success">
68
- <span class="nav-icon">&#9679;</span> Criteres de reussite
69
- </a>
70
- </div>
71
-
72
- <!-- Phase 2 : Decomposition -->
73
- <div class="nav-group">
74
- <div class="nav-group-title">2. Decomposition</div>
75
- <a class="nav-item" onclick="showSection('decomp-modules')" data-section="decomp-modules">
76
- <span class="nav-icon">&#9679;</span> Domaines fonctionnels
77
- <span class="nav-badge" id="moduleCount">0</span>
78
- </a>
79
- <a class="nav-item" onclick="showSection('decomp-dependencies')" data-section="decomp-dependencies">
80
- <span class="nav-icon">&#9679;</span> Dependances
81
- </a>
82
- </div>
83
-
84
- <!-- Phase 3 : Specification par module -->
85
- <div class="nav-group" id="modulesNav">
86
- <div class="nav-group-title">3. Specification</div>
87
- <!-- Populated dynamically per module -->
88
- </div>
89
-
90
- <!-- Phase 4 : Consolidation -->
91
- <div class="nav-group">
92
- <div class="nav-group-title">4. Consolidation</div>
93
- <a class="nav-item" onclick="showSection('consol-datamodel')" data-section="consol-datamodel">
94
- <span class="nav-icon">&#9679;</span> Modele de donnees
95
- <span class="nav-badge" id="entityCount">0</span>
96
- </a>
97
- <a class="nav-item" onclick="showSection('consol-interactions')" data-section="consol-interactions">
98
- <span class="nav-icon">&#9679;</span> Interactions
99
- </a>
100
- <a class="nav-item" onclick="showSection('consol-permissions')" data-section="consol-permissions">
101
- <span class="nav-icon">&#9679;</span> Coherence des acces
102
- </a>
103
- <a class="nav-item" onclick="showSection('consol-flows')" data-section="consol-flows">
104
- <span class="nav-icon">&#9679;</span> Parcours bout en bout
105
- </a>
106
- </div>
107
-
108
- <!-- Phase 5 : Synthese -->
109
- <div class="nav-group">
110
- <div class="nav-group-title">5. Synthese</div>
111
- <a class="nav-item" onclick="showSection('handoff-summary')" data-section="handoff-summary">
112
- <span class="nav-icon">&#9679;</span> Vue d'ensemble
113
- </a>
43
+ <!-- Dynamic Tree Navigation -->
44
+ <div id="sidebarNav">
45
+ <!-- Populated by buildNavTree() -->
114
46
  </div>
115
47
  </aside>
116
48
 
@@ -26,14 +26,15 @@ const FEATURE_DATA = {
26
26
  scope: {
27
27
  // CONVERT feature.json keys to HTML keys:
28
28
  // mustHave → vital, shouldHave → important, couldHave → optional, outOfScope → excluded
29
+ // CRITICAL: Preserve per-item `module` assignment from coverageMatrix (NOT modules[0])
29
30
  vital: (master.cadrage.globalScope?.mustHave || master.cadrage.coverageMatrix?.filter(i => i.category === "mustHave") || [])
30
- .map(item => typeof item === 'string' ? { name: item, description: "" } : { name: item.item || item, description: item.notes || "" }),
31
+ .map(item => typeof item === 'string' ? { name: item, description: "", module: null } : { name: item.item || item, description: item.notes || "", module: item.module || null }),
31
32
  important: (master.cadrage.globalScope?.shouldHave || master.cadrage.coverageMatrix?.filter(i => i.category === "shouldHave") || [])
32
- .map(item => typeof item === 'string' ? { name: item, description: "" } : { name: item.item || item, description: item.notes || "" }),
33
+ .map(item => typeof item === 'string' ? { name: item, description: "", module: null } : { name: item.item || item, description: item.notes || "", module: item.module || null }),
33
34
  optional: (master.cadrage.globalScope?.couldHave || master.cadrage.coverageMatrix?.filter(i => i.category === "couldHave") || [])
34
- .map(item => typeof item === 'string' ? { name: item, description: "" } : { name: item.item || item, description: item.notes || "" }),
35
+ .map(item => typeof item === 'string' ? { name: item, description: "", module: null } : { name: item.item || item, description: item.notes || "", module: item.module || null }),
35
36
  excluded: (master.cadrage.globalScope?.outOfScope || master.cadrage.coverageMatrix?.filter(i => i.category === "outOfScope") || [])
36
- .map(item => typeof item === 'string' ? { name: item, description: "" } : { name: item.item || item, description: item.notes || "" })
37
+ .map(item => typeof item === 'string' ? { name: item, description: "", module: null } : { name: item.item || item, description: item.notes || "", module: item.module || null })
37
38
  },
38
39
  risks: (master.cadrage.risks || []).map(r => ({
39
40
  description: r.description,
@@ -123,8 +124,9 @@ const FEATURE_DATA = {
123
124
  const EMBEDDED_ARTIFACTS = {
124
125
  wireframes: {
125
126
  // PER-MODULE keyed object (NOT a flat array)
126
- // FOR EACH module: extract from specification.uiWireframes[]
127
- [moduleCode]: moduleFeature.specification.uiWireframes.map(wf => ({
127
+ // FOR EACH module: extract from specification.uiWireframes[] OR specification.wireframes[] (SAFETY NET)
128
+ // IMPORTANT: The agent may write wireframes under either key name — always check BOTH
129
+ [moduleCode]: (moduleFeature.specification.uiWireframes || moduleFeature.specification.wireframes || []).map(wf => ({
128
130
  screen: wf.screen || wf.name || wf.id || "", // SAFETY NET: fallback name/id → screen
129
131
  section: wf.section || "", // e.g. "list"
130
132
  format: wf.mockupFormat || "ascii", // RENAME: mockupFormat → format
@@ -161,7 +163,7 @@ const EMBEDDED_ARTIFACTS = {
161
163
 
162
164
  ### Artifact Gathering
163
165
 
164
- 1. For EACH module: read `specification.uiWireframes[]`, **rename fields** (`mockupFormat`→`format`, `mockup`→`content`), store under `wireframes[moduleCode]`
166
+ 1. For EACH module: read `specification.uiWireframes[]` OR `specification.wireframes[]` (check BOTH keys — agent may use either), **rename fields** (`mockupFormat`→`format`, `mockup`→`content`), store under `wireframes[moduleCode]`
165
167
  2. Read master's `consolidation.e2eFlows[]` and build e2eFlows array with diagram generation
166
168
  3. Read master's `dependencyGraph` and build nodes/edges
167
169
  4. Serialize as JSON with 2-space indentation
@@ -20,25 +20,17 @@ Build a JSON object following this **exact mapping** from feature.json to the HT
20
20
  analysisMode: master.metadata.analysisMode || "interactive" // always "interactive"
21
21
  },
22
22
  cadrage: {
23
- problem: {
24
- description: master.cadrage.problem, // string problem.description
25
- trigger: master.cadrage.trigger, // string → problem.trigger
26
- impactedPeople: "", // not in feature.json, client fills
27
- history: "",
28
- consequences: ""
29
- },
30
- current: {
31
- tools: master.cadrage.asIs, // string current.tools
32
- steps: [], // client can add process steps
33
- painPoints: master.cadrage.stakeholders
34
- .flatMap(s => s.painPoints || []).join("\n"), // aggregate all painPoints
35
- errors: ""
36
- },
37
- vision: {
38
- changes: master.cadrage.toBe, // string → vision.changes
39
- results: master.cadrage.acceptanceCriteria
40
- .map(ac => ac.criterion).join("\n"), // AC → results (one per line)
41
- successSign: ""
23
+ // CONTEXT SECTION — lean format (merged from problem/asIs/toBe)
24
+ // NOTE: 01-data-init.js has backward compat for old problem/current/vision format
25
+ context: {
26
+ problem: master.cadrage.problem || "", // flat string from feature.json
27
+ trigger: master.cadrage.trigger || "", // flat string from feature.json
28
+ currentSituation: master.cadrage.asIs || "", // flat string from feature.json
29
+ desiredSituation: master.cadrage.toBe || "", // flat string from feature.json
30
+ painPoints: (master.cadrage.stakeholders || [])
31
+ .flatMap(s => s.painPoints || []).join("\n"), // aggregate all painPoints
32
+ acceptanceCriteria: (master.cadrage.acceptanceCriteria || [])
33
+ .map(ac => ac.criterion).join("\n") // AC → newline-separated string
42
34
  },
43
35
  stakeholders: master.cadrage.stakeholders.map(s => ({
44
36
  role: s.role,
@@ -64,22 +56,22 @@ Build a JSON object following this **exact mapping** from feature.json to the HT
64
56
  impact: r.impact,
65
57
  mitigation: r.mitigation || ""
66
58
  })),
67
- assumptions: "",
68
- success: {
69
- definition: (master.cadrage.acceptanceCriteria || [])
70
- .map(ac => ac.criterion).join("\n"),
71
- metrics: "",
72
- timeline: "",
73
- minimumConditions: ""
74
- }
59
+ criteria: (master.cadrage.acceptanceCriteria || []).map(ac => ({
60
+ text: ac.criterion,
61
+ validated: ac.validated || false
62
+ }))
75
63
  },
76
64
  modules: master.modules.map(m => ({
77
65
  code: m.code,
78
- name: m.code, // module code as name
66
+ name: m.name || m.code, // display name (MANDATORY, separate from code)
79
67
  description: m.description || "",
80
68
  featureType: m.featureType || "data-centric",
81
69
  priority: m.priority || "must",
82
70
  entities: m.entities || [],
71
+ anticipatedSections: m.anticipatedSections || [], // [{code, description, resources[]}]
72
+ dependencies: m.dependencies || [],
73
+ dependents: m.dependents || [],
74
+ estimatedComplexity: m.estimatedComplexity || "medium",
83
75
  status: m.status || "handed-off"
84
76
  })),
85
77
  dependencies: (master.dependencyGraph?.edges || []).map(e => ({
@@ -44,7 +44,8 @@ Build EMBEDDED_ARTIFACTS with wireframes for completed modules only:
44
44
  const EMBEDDED_ARTIFACTS = {
45
45
  wireframes: {
46
46
  // FOR EACH completed module: extract wireframes with RENAMED fields
47
- [moduleCode]: moduleFeature.specification.uiWireframes.map(wf => ({
47
+ // SAFETY NET: check BOTH key names (agent may use either)
48
+ [moduleCode]: (moduleFeature.specification.uiWireframes || moduleFeature.specification.wireframes || []).map(wf => ({
48
49
  screen: wf.screen,
49
50
  section: wf.section,
50
51
  format: wf.mockupFormat || "ascii", // RENAME: mockupFormat → format
@@ -293,10 +293,12 @@ Create: docs/business/{app}/{module_code}/business-analyse/v1.0/
293
293
 
294
294
  > Module feature.json files will be created by step-03 when each module is processed.
295
295
 
296
- ### 9. Display Summary
296
+ ### 9. Display Summary & AUTOCHAIN
297
297
 
298
298
  ```
299
- ## Decomposition Complete - {feature_id}
299
+ ═══════════════════════════════════════════════════════════
300
+ DECOMPOSITION COMPLETE - {feature_id}
301
+ ═══════════════════════════════════════════════════════════
300
302
 
301
303
  | Aspect | Value |
302
304
  |--------|-------|
@@ -309,8 +311,16 @@ Create: docs/business/{app}/{module_code}/business-analyse/v1.0/
309
311
  {numbered list of modules}
310
312
 
311
313
  → Starting iterative specification with {first_module}...
314
+ ═══════════════════════════════════════════════════════════
312
315
  ```
313
316
 
317
+ **AUTOCHAIN — DO NOT STOP HERE:**
318
+ - Do NOT ask "shall I continue?" or "voulez-vous que je continue?"
319
+ - Do NOT summarize what's coming next
320
+ - Do NOT wait for user input
321
+ - The user ALREADY validated at step 6 — that was the checkpoint
322
+ - IMMEDIATELY load step-03a1-setup.md
323
+
314
324
  ---
315
325
 
316
326
  ## SINGLE-MODULE MODE
@@ -325,6 +335,9 @@ When `workflow.mode = "module"` or only 1 scope item identified:
325
335
 
326
336
  ---
327
337
 
328
- ## NEXT STEP
338
+ ## NEXT STEP (MANDATORY — NO PAUSE)
329
339
 
330
340
  Load: `./step-03a1-setup.md`
341
+
342
+ > **FORBIDDEN:** Asking any question between decomposition summary and step-03 load.
343
+ > The client checkpoint was at step 6. Do NOT add another one.
@@ -48,6 +48,45 @@ Compile all data collected in step-03a (data) and step-03b (UI) into the module
48
48
 
49
49
  Generate the complete specification for this module. **Each subsection below includes a STRUCTURE CARD showing the EXACT JSON format. Follow them precisely.**
50
50
 
51
+ #### ENTITY ATTRIBUTE SCHEMA (MANDATORY — applies to ALL entities in section 6b of step-03a)
52
+
53
+ > **CRITICAL:** Entity attributes MUST use STRUCTURED properties, not free-text validation strings.
54
+ > The ralph-loop needs parseable types to generate correct C# code.
55
+
56
+ > **STRUCTURE CARD: analysis.entities[].attributes[]**
57
+ > ```json
58
+ > {
59
+ > "name": "occupancyRate",
60
+ > "description": "Employee occupancy percentage",
61
+ > "type": "decimal",
62
+ > "maxLength": null,
63
+ > "nullable": true,
64
+ > "required": false,
65
+ > "unique": false,
66
+ > "indexed": false,
67
+ > "defaultValue": "100",
68
+ > "validation": "min:0, max:100, step:0.01",
69
+ > "foreignKey": null
70
+ > }
71
+ > ```
72
+ > **MANDATORY fields:** `name`, `type`
73
+ > **type values:** `string`, `int`, `long`, `decimal`, `double`, `bool`, `DateTime`, `DateOnly`, `TimeOnly`, `Guid`, `enum:{EnumName}`, `byte[]`
74
+ > **For FK attributes:**
75
+ > ```json
76
+ > {
77
+ > "name": "departmentId",
78
+ > "description": "FK to Department",
79
+ > "type": "Guid",
80
+ > "required": true,
81
+ > "foreignKey": { "targetEntity": "Department", "targetField": "Id", "onDelete": "restrict" }
82
+ > }
83
+ > ```
84
+ > **FORBIDDEN:** Free-text-only validation like `"FK vers Employee"` or `"Max 100 caractères"` without corresponding structured properties.
85
+ >
86
+ > **BaseEntity inheritance:** All entities inherit `tenantId`, `createdAt`, `updatedAt`, `createdBy`, `updatedBy` from SmartStack.BaseEntity. Do NOT redeclare these. Document this once at the top of the entities section.
87
+
88
+ ---
89
+
51
90
  #### 8a. Actors
52
91
 
53
92
  Inherited from application roles → mapped to module permissions.
@@ -234,7 +273,7 @@ const navigationResources = specification.sections.flatMap(section =>
234
273
  );
235
274
  ```
236
275
 
237
- **Write to seedDataCore:**
276
+ **Write seedDataCore to specification:**
238
277
 
239
278
  ```
240
279
  ba-writer.enrichSection({
@@ -254,6 +293,9 @@ ba-writer.enrichSection({
254
293
  })
255
294
  ```
256
295
 
296
+ > **NOTE:** This step writes ONLY seedDataCore. The FULL specification write (actors, useCases, wireframes, sections, etc.) happens in step-03d section 11.
297
+ > ALL data from 8a-8l MUST be carried forward to step-03d. Do NOT discard in-memory data.
298
+
257
299
  **Validation:**
258
300
 
259
301
  - EVERY section in `specification.sections[]` MUST appear in `navigationSections`
@@ -280,8 +322,9 @@ BDD acceptance tests per UC.
280
322
  > ]
281
323
  > }
282
324
  > ```
283
- > **STRUCTURE:** Object with `feature` string + `scenarios[]` array. Each scenario has `given`, `when`, `then` as ARRAYS of strings.
325
+ > **STRUCTURE:** MUST be an ARRAY of objects (NOT a single object). Each object has `feature` string + `scenarios[]` array. Each scenario has `given`, `when`, `then` as ARRAYS of strings.
284
326
  > **FORBIDDEN:** Do NOT use flat arrays of `{uc, scenario, given, when, then}` where given/when/then are single strings.
327
+ > **FORBIDDEN:** Do NOT use a single object `{feature, scenarios}` — MUST be an ARRAY `[{feature, scenarios}]` even with one feature.
285
328
 
286
329
  #### 8h. Validations
287
330
 
@@ -405,6 +448,16 @@ Before loading step-03d-validate, verify all 12 subsections (8a-8l) are populate
405
448
 
406
449
  **IF any subsection is missing → STOP and request the missing data before proceeding.**
407
450
 
451
+ **SCHEMA UNIFORMITY CHECK (multi-module mode):**
452
+ IF this is NOT the first module in moduleOrder:
453
+ Compare THIS module's specification structure against the FIRST specified module:
454
+ - `gherkinScenarios` MUST be array (not object) in ALL modules
455
+ - `validations[].rules` MUST be array (not singular `rule`) in ALL modules
456
+ - `messages[]` MUST have `message` field in ALL modules
457
+ - `specification.apiEndpoints[]` MUST be present in ALL modules
458
+ - `specification.i18nKeys` MUST be present in ALL modules
459
+ IF any structural divergence detected → AUTO-FIX to match the canonical format before proceeding.
460
+
408
461
  ---
409
462
 
410
463
  ## NEXT STEP