@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.
- package/.documentation/testing-ba-e2e.md +76 -24
- package/package.json +1 -1
- package/templates/agents/gitflow/init.md +26 -0
- package/templates/skills/apex/references/parallel-execution.md +22 -4
- package/templates/skills/apex/steps/step-00-init.md +38 -0
- package/templates/skills/apex/steps/step-03a-layer0-domain.md +21 -0
- package/templates/skills/apex/steps/step-03b-layer1-seed.md +60 -0
- package/templates/skills/apex/steps/step-03c-layer2-backend.md +124 -13
- package/templates/skills/apex/steps/step-03d-layer3-frontend.md +32 -0
- package/templates/skills/application/references/backend-controller-hierarchy.md +14 -4
- package/templates/skills/business-analyse-develop/references/quality-gates.md +91 -1
- package/templates/skills/business-analyse-develop/steps/step-01-task.md +147 -1
- package/templates/skills/business-analyse-handoff/references/acceptance-criteria.md +53 -1
- package/templates/skills/business-analyse-handoff/references/handoff-file-templates.md +42 -0
- package/templates/skills/business-analyse-handoff/references/handoff-mappings.md +15 -1
- package/templates/skills/business-analyse-handoff/references/prd-generation.md +59 -0
- package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +25 -1
- package/templates/skills/business-analyse-handoff/steps/step-02-export.md +32 -4
- package/templates/skills/business-analyse-html/html/ba-interactive.html +64 -5
- package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +13 -1
- package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +10 -1
- package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +1 -1
- package/templates/skills/business-analyse-html/html/src/styles/03-navigation.css +2 -2
- package/templates/skills/business-analyse-html/html/src/styles/05-modules.css +38 -0
- package/templates/skills/controller/references/mcp-scaffold-workflow.md +8 -4
- package/templates/skills/controller/steps/step-05-validate.md +2 -2
- package/templates/skills/controller/templates.md +4 -3
- 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:
|
|
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:
|
|
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">•</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
|
-
|
|
3969
|
+
var legend = '<div class="struct-legend">' +
|
|
3970
|
+
'<div class="struct-legend-title">ⓘ 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);">▸</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">•</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
|
-
|
|
623
|
+
var legend = '<div class="struct-legend">' +
|
|
624
|
+
'<div class="struct-legend-title">ⓘ 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);">▸</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:
|
|
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:
|
|
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
|
|
223
|
+
// Manually add — REPLACE [Route] with [NavRoute], do NOT keep both (causes 404s):
|
|
224
224
|
[ApiController]
|
|
225
|
-
[
|
|
226
|
-
[
|
|
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
|
-
|
|
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
|
-
|
|
|
44
|
-
| Authorize attribute | `[Authorize]`
|
|
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
|
-
[
|
|
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
|
|
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]
|
|
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
|
-
|
|
65
|
-
|
|
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]
|
|
69
|
-
[
|
|
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
|
```
|