@atlashub/smartstack-cli 4.48.0 → 4.49.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 (28) 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-develop/references/quality-gates.md +91 -1
  12. package/templates/skills/business-analyse-develop/steps/step-01-task.md +147 -1
  13. package/templates/skills/business-analyse-handoff/references/acceptance-criteria.md +53 -1
  14. package/templates/skills/business-analyse-handoff/references/handoff-file-templates.md +42 -0
  15. package/templates/skills/business-analyse-handoff/references/handoff-mappings.md +15 -1
  16. package/templates/skills/business-analyse-handoff/references/prd-generation.md +59 -0
  17. package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +25 -1
  18. package/templates/skills/business-analyse-handoff/steps/step-02-export.md +32 -4
  19. package/templates/skills/business-analyse-html/html/ba-interactive.html +64 -5
  20. package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +13 -1
  21. package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +10 -1
  22. package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +1 -1
  23. package/templates/skills/business-analyse-html/html/src/styles/03-navigation.css +2 -2
  24. package/templates/skills/business-analyse-html/html/src/styles/05-modules.css +38 -0
  25. package/templates/skills/controller/references/mcp-scaffold-workflow.md +8 -4
  26. package/templates/skills/controller/steps/step-05-validate.md +2 -2
  27. package/templates/skills/controller/templates.md +4 -3
  28. package/templates/skills/feature-full/steps/step-01-implementation.md +18 -5
@@ -378,13 +378,13 @@ body {
378
378
  .nav-icon-section { font-size: 0.5rem; color: var(--accent); }
379
379
  .nav-icon-resource { font-size: 0.7rem; color: var(--border-light); }
380
380
  .nav-resource-link {
381
- cursor: default;
381
+ cursor: pointer;
382
382
  font-size: 0.72rem;
383
383
  color: var(--text-muted);
384
384
  padding-top: 0.2rem;
385
385
  padding-bottom: 0.2rem;
386
386
  }
387
- .nav-resource-link:hover { background: transparent; color: var(--text-muted); }
387
+ .nav-resource-link:hover { background: var(--bg-hover); color: var(--accent); }
388
388
  .nav-resources { margin-left: 0.5rem; }
389
389
 
390
390
 
@@ -1031,6 +1031,44 @@ body {
1031
1031
  color: var(--text-muted);
1032
1032
  }
1033
1033
 
1034
+ /* ============================================
1035
+ STRUCTURE LEGEND
1036
+ ============================================ */
1037
+ .struct-legend {
1038
+ background: var(--bg-card);
1039
+ border: 1px solid var(--border);
1040
+ border-radius: 10px;
1041
+ padding: 0.75rem 1rem;
1042
+ margin-bottom: 1.25rem;
1043
+ }
1044
+ .struct-legend-title {
1045
+ font-size: 0.8rem;
1046
+ font-weight: 600;
1047
+ color: var(--text-muted);
1048
+ margin-bottom: 0.5rem;
1049
+ }
1050
+ .struct-legend-grid {
1051
+ display: grid;
1052
+ grid-template-columns: 1fr 1fr;
1053
+ gap: 0.4rem 1.5rem;
1054
+ }
1055
+ .struct-legend-item {
1056
+ font-size: 0.78rem;
1057
+ color: var(--text-muted);
1058
+ line-height: 1.4;
1059
+ }
1060
+ .struct-legend-code {
1061
+ display: inline-block;
1062
+ font-weight: 600;
1063
+ color: var(--accent);
1064
+ background: rgba(6,182,212,0.1);
1065
+ padding: 0.05rem 0.4rem;
1066
+ border-radius: 3px;
1067
+ font-size: 0.72rem;
1068
+ margin-right: 0.3rem;
1069
+ font-family: monospace;
1070
+ }
1071
+
1034
1072
  /* ============================================
1035
1073
  SECTION GROUPS (Hierarchical Mode)
1036
1074
  ============================================ */
@@ -2762,7 +2800,7 @@ function renderModuleNavItem(mod) {
2762
2800
  html += '<div class="nav-children nav-resources">';
2763
2801
  resources.forEach(function(res) {
2764
2802
  var resName = typeof res === 'string' ? res : (res.code || res.name || '');
2765
- html += '<a class="nav-item nav-resource-link">';
2803
+ html += '<a class="nav-item nav-resource-link" onclick="showSection(\'module-spec-' + code + '\');switchTab(\'' + code + '\',\'mock\');scrollToMockup(\'' + code + '\',\'' + section.code + '\')">';
2766
2804
  html += '<span class="nav-icon nav-icon-resource">&#8226;</span> ' + escapeHtml(resName);
2767
2805
  html += '</a>';
2768
2806
  });
@@ -2785,6 +2823,18 @@ function renderModuleTabNavItem(code, tabId, label, badge) {
2785
2823
  '</a>';
2786
2824
  }
2787
2825
 
2826
+ function scrollToMockup(moduleCode, sectionCode) {
2827
+ setTimeout(function() {
2828
+ var el = document.getElementById('screen-' + moduleCode + '-' + sectionCode);
2829
+ if (el) {
2830
+ el.scrollIntoView({ behavior: 'smooth', block: 'start' });
2831
+ el.style.outline = '2px solid var(--accent)';
2832
+ el.style.borderRadius = '10px';
2833
+ setTimeout(function() { el.style.outline = ''; el.style.borderRadius = ''; }, 2000);
2834
+ }
2835
+ }, 150);
2836
+ }
2837
+
2788
2838
  /* ---------- Collapse/Expand ---------- */
2789
2839
 
2790
2840
  function toggleNavGroup(groupId) {
@@ -3916,7 +3966,16 @@ function renderModuleStructure(code) {
3916
3966
  '</div>';
3917
3967
  }
3918
3968
 
3919
- return sections.map(function(section) {
3969
+ var legend = '<div class="struct-legend">' +
3970
+ '<div class="struct-legend-title">&#9432; Types de sections</div>' +
3971
+ '<div class="struct-legend-grid">' +
3972
+ '<div class="struct-legend-item"><span class="struct-legend-code">list</span> Page principale — grille de données avec filtres, tri et actions (créer, exporter)</div>' +
3973
+ '<div class="struct-legend-item"><span class="struct-legend-code">detail</span> Fiche détaillée — affichée au clic sur une ligne, avec onglets (infos, relations, historique)</div>' +
3974
+ '<div class="struct-legend-item"><span class="struct-legend-code">dashboard</span> Tableau de bord — KPIs, graphiques et métriques du module</div>' +
3975
+ '<div class="struct-legend-item"><span class="struct-legend-code">approve</span> Workflow — file de validation avec actions (approuver, rejeter, mettre en attente)</div>' +
3976
+ '</div></div>';
3977
+
3978
+ return legend + sections.map(function(section) {
3920
3979
  var resources = section.resources || [];
3921
3980
  var sectionUCs = section.useCases || [];
3922
3981
  var sectionBRs = section.businessRules || [];
@@ -4295,7 +4354,7 @@ function renderScreenMockups(code) {
4295
4354
 
4296
4355
  return screens.map(function(screen, si) {
4297
4356
  var resources = screen.resources || [];
4298
- return '<div class="screen-section" style="margin-bottom:2rem;">' +
4357
+ return '<div class="screen-section" id="screen-' + code + '-' + screen.sectionCode + '" style="margin-bottom:2rem;">' +
4299
4358
  '<h3 style="color:var(--text-bright);font-size:1rem;margin-bottom:1rem;">' +
4300
4359
  '<span style="color:var(--accent);">&#9656;</span> ' + escapeHtml(screen.sectionLabel || screen.sectionCode) +
4301
4360
  '</h3>' +
@@ -182,7 +182,7 @@ function renderModuleNavItem(mod) {
182
182
  html += '<div class="nav-children nav-resources">';
183
183
  resources.forEach(function(res) {
184
184
  var resName = typeof res === 'string' ? res : (res.code || res.name || '');
185
- html += '<a class="nav-item nav-resource-link">';
185
+ html += '<a class="nav-item nav-resource-link" onclick="showSection(\'module-spec-' + code + '\');switchTab(\'' + code + '\',\'mock\');scrollToMockup(\'' + code + '\',\'' + section.code + '\')">';
186
186
  html += '<span class="nav-icon nav-icon-resource">&#8226;</span> ' + escapeHtml(resName);
187
187
  html += '</a>';
188
188
  });
@@ -205,6 +205,18 @@ function renderModuleTabNavItem(code, tabId, label, badge) {
205
205
  '</a>';
206
206
  }
207
207
 
208
+ function scrollToMockup(moduleCode, sectionCode) {
209
+ setTimeout(function() {
210
+ var el = document.getElementById('screen-' + moduleCode + '-' + sectionCode);
211
+ if (el) {
212
+ el.scrollIntoView({ behavior: 'smooth', block: 'start' });
213
+ el.style.outline = '2px solid var(--accent)';
214
+ el.style.borderRadius = '10px';
215
+ setTimeout(function() { el.style.outline = ''; el.style.borderRadius = ''; }, 2000);
216
+ }
217
+ }, 150);
218
+ }
219
+
208
220
  /* ---------- Collapse/Expand ---------- */
209
221
 
210
222
  function toggleNavGroup(groupId) {
@@ -620,7 +620,16 @@ function renderModuleStructure(code) {
620
620
  '</div>';
621
621
  }
622
622
 
623
- return sections.map(function(section) {
623
+ var legend = '<div class="struct-legend">' +
624
+ '<div class="struct-legend-title">&#9432; Types de sections</div>' +
625
+ '<div class="struct-legend-grid">' +
626
+ '<div class="struct-legend-item"><span class="struct-legend-code">list</span> Page principale — grille de données avec filtres, tri et actions (créer, exporter)</div>' +
627
+ '<div class="struct-legend-item"><span class="struct-legend-code">detail</span> Fiche détaillée — affichée au clic sur une ligne, avec onglets (infos, relations, historique)</div>' +
628
+ '<div class="struct-legend-item"><span class="struct-legend-code">dashboard</span> Tableau de bord — KPIs, graphiques et métriques du module</div>' +
629
+ '<div class="struct-legend-item"><span class="struct-legend-code">approve</span> Workflow — file de validation avec actions (approuver, rejeter, mettre en attente)</div>' +
630
+ '</div></div>';
631
+
632
+ return legend + sections.map(function(section) {
624
633
  var resources = section.resources || [];
625
634
  var sectionUCs = section.useCases || [];
626
635
  var sectionBRs = section.businessRules || [];
@@ -11,7 +11,7 @@ function renderScreenMockups(code) {
11
11
 
12
12
  return screens.map(function(screen, si) {
13
13
  var resources = screen.resources || [];
14
- return '<div class="screen-section" style="margin-bottom:2rem;">' +
14
+ return '<div class="screen-section" id="screen-' + code + '-' + screen.sectionCode + '" style="margin-bottom:2rem;">' +
15
15
  '<h3 style="color:var(--text-bright);font-size:1rem;margin-bottom:1rem;">' +
16
16
  '<span style="color:var(--accent);">&#9656;</span> ' + escapeHtml(screen.sectionLabel || screen.sectionCode) +
17
17
  '</h3>' +
@@ -110,11 +110,11 @@
110
110
  .nav-icon-section { font-size: 0.5rem; color: var(--accent); }
111
111
  .nav-icon-resource { font-size: 0.7rem; color: var(--border-light); }
112
112
  .nav-resource-link {
113
- cursor: default;
113
+ cursor: pointer;
114
114
  font-size: 0.72rem;
115
115
  color: var(--text-muted);
116
116
  padding-top: 0.2rem;
117
117
  padding-bottom: 0.2rem;
118
118
  }
119
- .nav-resource-link:hover { background: transparent; color: var(--text-muted); }
119
+ .nav-resource-link:hover { background: var(--bg-hover); color: var(--accent); }
120
120
  .nav-resources { margin-left: 0.5rem; }
@@ -443,6 +443,44 @@
443
443
  color: var(--text-muted);
444
444
  }
445
445
 
446
+ /* ============================================
447
+ STRUCTURE LEGEND
448
+ ============================================ */
449
+ .struct-legend {
450
+ background: var(--bg-card);
451
+ border: 1px solid var(--border);
452
+ border-radius: 10px;
453
+ padding: 0.75rem 1rem;
454
+ margin-bottom: 1.25rem;
455
+ }
456
+ .struct-legend-title {
457
+ font-size: 0.8rem;
458
+ font-weight: 600;
459
+ color: var(--text-muted);
460
+ margin-bottom: 0.5rem;
461
+ }
462
+ .struct-legend-grid {
463
+ display: grid;
464
+ grid-template-columns: 1fr 1fr;
465
+ gap: 0.4rem 1.5rem;
466
+ }
467
+ .struct-legend-item {
468
+ font-size: 0.78rem;
469
+ color: var(--text-muted);
470
+ line-height: 1.4;
471
+ }
472
+ .struct-legend-code {
473
+ display: inline-block;
474
+ font-weight: 600;
475
+ color: var(--accent);
476
+ background: rgba(6,182,212,0.1);
477
+ padding: 0.05rem 0.4rem;
478
+ border-radius: 3px;
479
+ font-size: 0.72rem;
480
+ margin-right: 0.3rem;
481
+ font-family: monospace;
482
+ }
483
+
446
484
  /* ============================================
447
485
  SECTION GROUPS (Hierarchical Mode)
448
486
  ============================================ */
@@ -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
  ```