@atlashub/smartstack-cli 4.48.0 → 4.50.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 (41) hide show
  1. package/.documentation/testing-ba-e2e.md +76 -24
  2. package/package.json +1 -1
  3. package/templates/agents/gitflow/init.md +26 -0
  4. package/templates/skills/apex/references/parallel-execution.md +22 -4
  5. package/templates/skills/apex/steps/step-00-init.md +38 -0
  6. package/templates/skills/apex/steps/step-03a-layer0-domain.md +21 -0
  7. package/templates/skills/apex/steps/step-03b-layer1-seed.md +60 -0
  8. package/templates/skills/apex/steps/step-03c-layer2-backend.md +124 -13
  9. package/templates/skills/apex/steps/step-03d-layer3-frontend.md +32 -0
  10. package/templates/skills/application/references/backend-controller-hierarchy.md +14 -4
  11. package/templates/skills/business-analyse/patterns/suggestion-catalog.md +2 -0
  12. package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +2 -0
  13. package/templates/skills/business-analyse/schemas/application-schema.json +36 -1
  14. package/templates/skills/business-analyse/schemas/sections/specification-schema.json +19 -0
  15. package/templates/skills/business-analyse/steps/step-00-init.md +64 -14
  16. package/templates/skills/business-analyse/steps/step-01-cadrage.md +49 -2
  17. package/templates/skills/business-analyse/steps/step-02-structure.md +41 -17
  18. package/templates/skills/business-analyse/steps/step-04-consolidate.md +171 -0
  19. package/templates/skills/business-analyse-develop/references/quality-gates.md +91 -1
  20. package/templates/skills/business-analyse-develop/steps/step-01-task.md +147 -1
  21. package/templates/skills/business-analyse-handoff/references/acceptance-criteria.md +53 -1
  22. package/templates/skills/business-analyse-handoff/references/handoff-file-templates.md +42 -0
  23. package/templates/skills/business-analyse-handoff/references/handoff-mappings.md +15 -1
  24. package/templates/skills/business-analyse-handoff/references/prd-generation.md +59 -0
  25. package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +25 -1
  26. package/templates/skills/business-analyse-handoff/steps/step-02-export.md +32 -4
  27. package/templates/skills/business-analyse-html/html/ba-interactive.html +80 -11
  28. package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +4 -2
  29. package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +16 -2
  30. package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +19 -4
  31. package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +1 -1
  32. package/templates/skills/business-analyse-html/html/src/styles/03-navigation.css +2 -2
  33. package/templates/skills/business-analyse-html/html/src/styles/05-modules.css +38 -0
  34. package/templates/skills/business-analyse-html/references/data-build.md +4 -1
  35. package/templates/skills/business-analyse-html/references/data-mapping.md +4 -1
  36. package/templates/skills/business-analyse-html/steps/step-02-build-data.md +113 -1
  37. package/templates/skills/business-analyse-html/steps/step-04-verify.md +17 -1
  38. package/templates/skills/controller/references/mcp-scaffold-workflow.md +8 -4
  39. package/templates/skills/controller/steps/step-05-validate.md +2 -2
  40. package/templates/skills/controller/templates.md +4 -3
  41. package/templates/skills/feature-full/steps/step-01-implementation.md +18 -5
@@ -89,7 +89,11 @@ modules: master.modules.map(m => ({
89
89
  description: m.description || "",
90
90
  featureType: m.featureType || "data-centric",
91
91
  entities: m.entities || [],
92
- anticipatedSections: m.anticipatedSections || [],
92
+ anticipatedSections: (m.anticipatedSections || []).map(s =>
93
+ typeof s === 'string'
94
+ ? { code: s, name: s, description: "", resources: [] }
95
+ : { code: s.code || s.name || "", name: s.label || s.name || s.code || "", description: s.description || "", resources: s.resources || [], route: s.route || "", permission: s.permission || "" }
96
+ ),
93
97
  dependencies: m.dependencies || [],
94
98
  dependents: m.dependents || [],
95
99
  estimatedComplexity: m.estimatedComplexity || "medium",
@@ -135,6 +139,50 @@ moduleSpecs[moduleCode] = {
135
139
  permissions: buildPermissionKeys(mod.permissions),
136
140
  apiEndpoints: mod.usecases?.apiEndpoints || []
137
141
  }
142
+
143
+ // BUILD screens[] for HTML interactive mockups (SmartTable/SmartForm rendering)
144
+ const flatScr = mod.screens?.screens || [];
145
+ let screens = [];
146
+ if (flatScr.length > 0) {
147
+ const bySec = {};
148
+ flatScr.forEach(s => {
149
+ const sec = s.section || "default";
150
+ if (!bySec[sec]) bySec[sec] = {
151
+ sectionCode: sec,
152
+ sectionLabel: s.sectionLabel || s.sectionDescription || sec,
153
+ resources: []
154
+ };
155
+ bySec[sec].resources.push({
156
+ code: s.screen || s.name || "",
157
+ label: s.sectionLabel || s.description || s.screen || "",
158
+ type: s.componentType || "unknown",
159
+ columns: (s.columns || []).map(c => ({
160
+ field: c.code || c.field || "", label: c.label || c.code || "",
161
+ type: c.type || c.dataType || "text", sortable: !!c.sortable
162
+ })),
163
+ filters: (s.filters || []).map(f =>
164
+ typeof f === 'string' ? f : (f.label || f.filterLabel || f.code || f.filterCode || "")),
165
+ fields: [],
166
+ tabs: (s.tabs || []).map(t => ({
167
+ label: t.label || t.tabLabel || t.code || "",
168
+ fields: (t.fields || []).map(f => ({
169
+ field: f.code || f.fieldCode || f.field || "",
170
+ label: f.label || f.code || "",
171
+ type: f.type || f.dataType || "text",
172
+ required: !!f.required
173
+ }))
174
+ })),
175
+ actions: (s.actions || []).map(a =>
176
+ typeof a === 'string' ? a : (a.code || a.label || a.actionCode || "")),
177
+ kpis: s.kpis || [],
178
+ options: s.options || [],
179
+ permission: s.permission || "",
180
+ notes: s.description || ""
181
+ });
182
+ });
183
+ screens = Object.values(bySec);
184
+ }
185
+ moduleSpecs[moduleCode].screens = screens;
138
186
  ```
139
187
 
140
188
  > See `references/data-mapping.md` for `buildPermissionKeys()` implementation.
@@ -156,6 +204,44 @@ FEATURE_DATA.modules.forEach(m => {
156
204
 
157
205
  > This step is CRITICAL for the HTML viewer to display UC/BR grouped by section.
158
206
 
207
+ ### Post-Build Self-Check (MANDATORY — BLOCKING)
208
+
209
+ After enriching anticipatedSections, run this self-check to detect data loss:
210
+
211
+ ```javascript
212
+ // SELF-CHECK: compare source file counts vs FEATURE_DATA counts
213
+ const errors = [];
214
+ FEATURE_DATA.modules.forEach(m => {
215
+ const spec = FEATURE_DATA.moduleSpecs[m.code];
216
+ const source = collected_data.modules[m.code];
217
+ if (!spec) { errors.push(`MISSING moduleSpecs[${m.code}]`); return; }
218
+
219
+ const srcUC = (source?.usecases?.useCases || []).length;
220
+ const bltUC = (spec.useCases || []).length;
221
+ if (srcUC > 0 && bltUC === 0)
222
+ errors.push(`${m.code}: useCases EMPTY but source has ${srcUC}`);
223
+
224
+ const srcBR = (source?.rules?.rules || []).length;
225
+ const bltBR = (spec.businessRules || []).length;
226
+ if (srcBR > 0 && bltBR === 0)
227
+ errors.push(`${m.code}: businessRules EMPTY but source has ${srcBR}`);
228
+
229
+ const srcEnt = (source?.entities?.entities || []).length;
230
+ const bltEnt = (spec.entities || []).length;
231
+ if (srcEnt > 0 && bltEnt === 0)
232
+ errors.push(`${m.code}: entities EMPTY but source has ${srcEnt}`);
233
+ });
234
+
235
+ if (errors.length > 0) {
236
+ Display("⛔ SELF-CHECK FAILED — data loss detected:");
237
+ errors.forEach(e => Display(" - " + e));
238
+ // FIX: re-map the failing modules from collected_data before continuing
239
+ }
240
+ ```
241
+
242
+ > If self-check detects errors, you MUST re-read the source data and re-build the failing moduleSpecs entries.
243
+ > Do NOT proceed with empty arrays when source data exists.
244
+
159
245
  **consolidation:**
160
246
  ```javascript
161
247
  consolidation: {
@@ -223,6 +309,31 @@ for (const section of sections) {
223
309
  }
224
310
  }
225
311
 
312
+ // Source C: screens without mockup → auto-generate text description as wireframe fallback
313
+ const screensWithoutMockup = flatScreens.filter(s => !s.mockup && !s.mockupFormat);
314
+ for (const screen of screensWithoutMockup) {
315
+ const type = screen.componentType || "";
316
+ let desc = "";
317
+ if (type.includes("Table") || type.includes("Grid")) {
318
+ const cols = screen.columns || [];
319
+ desc = "Tableau avec " + cols.length + " colonnes : " + cols.map(c => c.label || c.code).join(", ");
320
+ } else if (type.includes("Form")) {
321
+ const tabs = screen.tabs || [];
322
+ desc = "Formulaire " + (tabs.length > 0 ? "avec " + tabs.length + " onglet(s)" : "");
323
+ } else if (type.includes("Dashboard")) {
324
+ desc = "Tableau de bord avec KPIs";
325
+ } else if (type.includes("Kanban")) {
326
+ desc = "Vue Kanban";
327
+ }
328
+ if (desc) {
329
+ rawWireframes.push({
330
+ screen: screen.screen || "", section: screen.section || "",
331
+ mockupFormat: "text", mockup: desc,
332
+ description: screen.sectionDescription || "", elements: [], componentMapping: []
333
+ });
334
+ }
335
+ }
336
+
226
337
  // STEP 2: Map to HTML format (RENAME: mockupFormat → format, mockup → content)
227
338
  wireframes: {
228
339
  [moduleCode]: rawWireframes.map(wf => ({
@@ -287,6 +398,7 @@ dependencyGraph: {
287
398
  - FEATURE_DATA.moduleSpecs must have ONE entry per module
288
399
  - cadrage.scope uses HTML keys (inscope/outofscope)
289
400
  - Wireframe fields use format/content (NOT mockupFormat/mockup)
401
+ - Per-module: useCases/businessRules/entities count must match source (empty when source has data = BUG)
290
402
 
291
403
  ## NEXT STEP
292
404
 
@@ -8,7 +8,7 @@ model: opus
8
8
 
9
9
  ## YOUR TASK
10
10
 
11
- Run 5 blocking validations on the generated HTML file and display the completion summary.
11
+ Run 6 blocking validations on the generated HTML file and display the completion summary.
12
12
 
13
13
  ---
14
14
 
@@ -53,6 +53,22 @@ FOR each module in FEATURE_DATA.modules:
53
53
  BLOCKING_ERROR("Module {module.code} not in wireframes")
54
54
  ```
55
55
 
56
+ **Check 6 — Per-module data completeness (source vs HTML):**
57
+ ```
58
+ FOR each module in FEATURE_DATA.modules:
59
+ Read source: docs/{app}/{module.code}/business-analyse/v{version}/usecases.json
60
+ sourceUCCount = count of useCases in source file
61
+ htmlUCCount = count in FEATURE_DATA.moduleSpecs[module.code].useCases
62
+ IF sourceUCCount > 0 AND htmlUCCount === 0:
63
+ BLOCKING_ERROR("Module {module.code}: 0 useCases in HTML but {sourceUCCount} in source")
64
+
65
+ Read source: docs/{app}/{module.code}/business-analyse/v{version}/rules.json
66
+ sourceBRCount = count of rules in source file
67
+ htmlBRCount = count in FEATURE_DATA.moduleSpecs[module.code].businessRules
68
+ IF sourceBRCount > 0 AND htmlBRCount === 0:
69
+ BLOCKING_ERROR("Module {module.code}: 0 businessRules in HTML but {sourceBRCount} in source")
70
+ ```
71
+
56
72
  > **IF any check fails:** fix the issue and re-run the failing step before completing.
57
73
 
58
74
  ---
@@ -220,14 +220,18 @@ console.log(`✅ All checks passed — controller ready for step-04`);
220
220
  If MCP doesn't generate [NavRoute] attribute:
221
221
 
222
222
  ```csharp
223
- // Manually add if missing:
223
+ // Manually add REPLACE [Route] with [NavRoute], do NOT keep both (causes 404s):
224
224
  [ApiController]
225
- [Route("api/[controller]")]
226
- [NavRoute("app.module.resource")] // <-- Add this line
225
+ [NavRoute("app.module.resource")]
226
+ [Microsoft.AspNetCore.Authorization.Authorize]
227
+ [Produces("application/json")]
228
+ [Tags("{EntityNamePlural}")]
227
229
  public class {EntityName}Controller : ControllerBase
228
230
  {
229
231
  // ...
230
232
  }
231
233
  ```
232
234
 
233
- But this indicates MCP failure and should not be needed in normal operation.
235
+ **CRITICAL:** Remove `[Route("api/...")]` if present combining `[Route]` and `[NavRoute]` causes 404 errors.
236
+
237
+ This indicates MCP failure and should not be needed in normal operation.
@@ -40,8 +40,8 @@ mcp__smartstack__validate_conventions:
40
40
 
41
41
  | Convention | Check | Status |
42
42
  |------------|-------|--------|
43
- | Route attribute | `[Route("api/{area}/[controller]")]` | ✅/❌ |
44
- | Authorize attribute | `[Authorize]` present | ✅/❌ |
43
+ | NavRoute attribute | `[NavRoute("{app}.{module}")]` present (NOT `[Route]`) | ✅/❌ |
44
+ | Authorize attribute | `[Microsoft.AspNetCore.Authorization.Authorize]` (fully qualified) | ✅/❌ |
45
45
  | RequirePermission | Uses `Permissions.*` constants | ✅/❌ |
46
46
  | ProducesResponseType | All endpoints documented | ✅/❌ |
47
47
  | Logging | All CRUD operations logged | ✅/❌ |
@@ -30,12 +30,13 @@ using SmartStack.Domain.{DomainNamespace};
30
30
  namespace SmartStack.Api.Controllers.{Area};
31
31
 
32
32
  [ApiController]
33
- [Route("api/{area-kebab}/{module-kebab}")]
34
- [Authorize]
33
+ [NavRoute("{area}.{module}")]
34
+ [Microsoft.AspNetCore.Authorization.Authorize]
35
+ [Produces("application/json")]
35
36
  [Tags("{Module}")]
36
37
  public class {Module}Controller : ControllerBase
37
38
  {
38
- private readonly IApplicationDbContext _context;
39
+ private readonly ISender _mediator; // MediatR — NOT IApplicationDbContext
39
40
  private readonly ICurrentUserService _currentUser;
40
41
  private readonly ILogger<{Module}Controller> _logger;
41
42
 
@@ -58,15 +58,28 @@ services.AddScoped<I{Entity}Service, {Entity}Service>();
58
58
  ## Phase 5: API
59
59
 
60
60
  ```csharp
61
- [ApiController][Route("api/{area}/{module}")][Authorize]
61
+ [ApiController]
62
+ [NavRoute("{area}.{module}")]
63
+ [Microsoft.AspNetCore.Authorization.Authorize]
64
+ [Produces("application/json")]
65
+ [Tags("{EntityPlural}")]
62
66
  public class {Entity}Controller : ControllerBase
63
67
  {
64
- [HttpGet][RequirePermission(Permissions.{Area}.{Module}.View)]
65
- [ProducesResponseType(typeof(PaginatedResult<{Entity}Dto>), 200)]
68
+ private readonly ISender _mediator;
69
+
70
+ [HttpGet]
71
+ [RequirePermission(Permissions.{Area}.{Module}.View)]
72
+ [ProducesResponseType(typeof(PaginatedResult<{Entity}Dto>), StatusCodes.Status200OK)]
73
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
74
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
66
75
  public async Task<ActionResult<PaginatedResult<{Entity}Dto>>> GetAll(...);
67
76
 
68
- [HttpPost][RequirePermission(Permissions.{Area}.{Module}.Create)]
69
- [ProducesResponseType(typeof({Entity}Dto), 201)]
77
+ [HttpPost]
78
+ [RequirePermission(Permissions.{Area}.{Module}.Create)]
79
+ [ProducesResponseType(typeof({Entity}Dto), StatusCodes.Status201Created)]
80
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
81
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
82
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
70
83
  public async Task<ActionResult<{Entity}Dto>> Create([FromBody] request, CancellationToken ct);
71
84
  }
72
85
  ```