@atlashub/smartstack-cli 3.43.0 → 3.44.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/mcp-entry.mjs +201 -22
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/agents/efcore/migration.md +11 -0
- package/templates/agents/efcore/rebase-snapshot.md +7 -0
- package/templates/agents/efcore/squash.md +7 -0
- package/templates/skills/apex/SKILL.md +14 -9
- package/templates/skills/apex/_shared.md +3 -0
- package/templates/skills/apex/references/analysis-methods.md +1 -1
- package/templates/skills/apex/references/challenge-questions.md +21 -0
- package/templates/skills/apex/references/core-seed-data.md +59 -104
- package/templates/skills/apex/references/post-checks.md +289 -225
- package/templates/skills/apex/references/smartstack-api.md +33 -35
- package/templates/skills/apex/references/smartstack-frontend.md +99 -3
- package/templates/skills/apex/references/smartstack-layers.md +145 -23
- package/templates/skills/apex/steps/step-00-init.md +2 -2
- package/templates/skills/apex/steps/step-01-analyze.md +1 -0
- package/templates/skills/apex/steps/step-02-plan.md +4 -3
- package/templates/skills/apex/steps/step-03-execute.md +24 -24
- package/templates/skills/apex/steps/step-04-examine.md +64 -24
- package/templates/skills/apex/steps/step-05-deep-review.md +1 -1
- package/templates/skills/apex/steps/step-08-run-tests.md +21 -13
- package/templates/skills/application/references/application-roles-template.md +10 -15
- package/templates/skills/application/references/backend-entity-seeding.md +6 -5
- package/templates/skills/application/references/backend-seeding-and-dto-output.md +1 -1
- package/templates/skills/application/references/nav-fallback-procedure.md +14 -17
- package/templates/skills/application/references/provider-template.md +5 -5
- package/templates/skills/application/references/roles-client-project-handling.md +1 -1
- package/templates/skills/application/references/roles-fallback-procedure.md +10 -15
- package/templates/skills/application/steps/step-01-navigation.md +1 -1
- package/templates/skills/application/steps/step-02-permissions.md +3 -3
- package/templates/skills/application/steps/step-03b-provider.md +1 -0
- package/templates/skills/application/templates-seed.md +41 -47
- package/templates/skills/business-analyse/references/team-orchestration.md +2 -2
- package/templates/skills/controller/steps/step-04-perms.md +1 -1
- package/templates/skills/efcore/references/troubleshooting.md +2 -2
- package/templates/skills/apex/references/examine-build-validation.md +0 -82
- package/templates/skills/apex/references/execution-frontend-gates.md +0 -177
- package/templates/skills/apex/references/execution-frontend-patterns.md +0 -105
- package/templates/skills/apex/references/execution-layer1-rules.md +0 -96
- package/templates/skills/apex/references/initialization-challenge-flow.md +0 -110
- package/templates/skills/apex/references/planning-layer-mapping.md +0 -151
|
@@ -505,12 +505,12 @@ public class {Name}Controller : ControllerBase
|
|
|
505
505
|
- FORBIDDEN: `humanresources.employees.read` (no kebab-case — mismatches NavRoute)
|
|
506
506
|
- SmartStack.app convention: `support-client.my-tickets.read` (always kebab-case)
|
|
507
507
|
|
|
508
|
-
### Section-Level Controller (NavRoute with
|
|
508
|
+
### Section-Level Controller (NavRoute with 3 segments)
|
|
509
509
|
|
|
510
|
-
When a module has sections, each section gets its own controller with a
|
|
510
|
+
When a module has sections, each section gets its own controller with a 3-segment navRoute:
|
|
511
511
|
|
|
512
512
|
```csharp
|
|
513
|
-
// Section-level controller: navRoute has
|
|
513
|
+
// Section-level controller: navRoute has 3 segments
|
|
514
514
|
[ApiController]
|
|
515
515
|
[NavRoute("{app}.{module}.{section}")]
|
|
516
516
|
[Authorize]
|
|
@@ -528,11 +528,17 @@ public class {Section}Controller : ControllerBase
|
|
|
528
528
|
}
|
|
529
529
|
```
|
|
530
530
|
|
|
531
|
-
**NavRoute segment rules:**
|
|
531
|
+
**NavRoute segment rules (minimum 2 segments):**
|
|
532
532
|
| Level | NavRoute format | Example |
|
|
533
533
|
|-------|----------------|---------|
|
|
534
|
-
| Module | `{app}.{module}` (2 segments) | `
|
|
535
|
-
| Section | `{app}.{module}.{section}` (3 segments) | `
|
|
534
|
+
| Module | `{app}.{module}` (2 segments) | `administration.users` |
|
|
535
|
+
| Section | `{app}.{module}.{section}` (3 segments) | `administration.users.groups` |
|
|
536
|
+
| Sub-resource (Suffix) | `{app}.{module}` + Suffix | `administration.ai` + `Suffix = "prompts"` |
|
|
537
|
+
|
|
538
|
+
> **POST-CONTEXT REMOVAL:** The old "context" level (1st segment) has been removed.
|
|
539
|
+
> Before: `platform.administration.users` (3 segments). After: `administration.users` (2 segments).
|
|
540
|
+
> The NavigationRouteRegistryBuilder builds 2-segment paths from DB (application.module).
|
|
541
|
+
> Controllers with 3+ segments use the fallback route generator (dots → slashes).
|
|
536
542
|
|
|
537
543
|
**Namespace:** `SmartStack.Api.Routing` (NOT `SmartStack.Api.Core.Routing`)
|
|
538
544
|
|
|
@@ -540,18 +546,18 @@ public class {Section}Controller : ControllerBase
|
|
|
540
546
|
|
|
541
547
|
### Sub-Resource Pattern (NavRoute Suffix)
|
|
542
548
|
|
|
543
|
-
When an entity is a child of another entity (e.g.,
|
|
549
|
+
When an entity is a child of another entity (e.g., AiPrompts under AI), use `[NavRoute(..., Suffix = "...")]`:
|
|
544
550
|
|
|
545
551
|
```csharp
|
|
546
|
-
// Sub-resource controller:
|
|
552
|
+
// Sub-resource controller: prompts are nested under AI module
|
|
547
553
|
[ApiController]
|
|
548
|
-
[NavRoute("
|
|
554
|
+
[NavRoute("administration.ai", Suffix = "prompts")]
|
|
549
555
|
[Authorize]
|
|
550
|
-
public class
|
|
556
|
+
public class AiPromptsController : ControllerBase
|
|
551
557
|
{
|
|
552
558
|
[HttpGet]
|
|
553
|
-
[RequirePermission(Permissions.
|
|
554
|
-
public async Task<ActionResult<PaginatedResult<
|
|
559
|
+
[RequirePermission(Permissions.Ai.Prompts.Read)]
|
|
560
|
+
public async Task<ActionResult<PaginatedResult<AiPromptResponseDto>>> GetAll(...)
|
|
555
561
|
=> Ok(await _service.GetAllAsync(search, page, pageSize, ct));
|
|
556
562
|
}
|
|
557
563
|
```
|
|
@@ -610,28 +616,13 @@ private static string ToKebabCase(string value)
|
|
|
610
616
|
.ToLowerInvariant();
|
|
611
617
|
```
|
|
612
618
|
|
|
613
|
-
###
|
|
619
|
+
### GUID Generation Rule
|
|
614
620
|
|
|
615
621
|
```csharp
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
public static readonly Guid ApplicationId = DeterministicGuid("nav:human-resources");
|
|
621
|
-
public static readonly Guid ModuleId = DeterministicGuid("nav:human-resources.employees");
|
|
622
|
-
public static readonly Guid SectionId = DeterministicGuid("nav:human-resources.employees.departments");
|
|
623
|
-
|
|
624
|
-
private static Guid DeterministicGuid(string input)
|
|
625
|
-
{
|
|
626
|
-
var hash = System.Security.Cryptography.SHA256.HashData(
|
|
627
|
-
System.Text.Encoding.UTF8.GetBytes(input));
|
|
628
|
-
var bytes = new byte[16];
|
|
629
|
-
Array.Copy(hash, bytes, 16);
|
|
630
|
-
bytes[6] = (byte)((bytes[6] & 0x0F) | 0x50); // version 5
|
|
631
|
-
bytes[8] = (byte)((bytes[8] & 0x3F) | 0x80); // variant
|
|
632
|
-
return new Guid(bytes);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
622
|
+
// ALWAYS use Guid.NewGuid() for ALL seed data IDs
|
|
623
|
+
// Avoids conflicts between projects/tenants/environments
|
|
624
|
+
// Idempotence is handled by Code-based lookups at runtime
|
|
625
|
+
// Navigation entities are resolved by Code, not by fixed GUIDs
|
|
635
626
|
```
|
|
636
627
|
|
|
637
628
|
### Navigation Seed Data Example
|
|
@@ -665,7 +656,7 @@ var section = NavigationSection.Create(
|
|
|
665
656
|
|---------|---------|
|
|
666
657
|
| `"humanresources"` as route | Must be `"/human-resources"` (full path, kebab-case) |
|
|
667
658
|
| `"employees"` as route | Must be `"/human-resources/employees"` (includes parent) |
|
|
668
|
-
|
|
|
659
|
+
| Deterministic/sequential/fixed GUIDs in seed data | ALWAYS use `Guid.NewGuid()` |
|
|
669
660
|
| Missing translations | Must have 4 languages: fr, en, it, de |
|
|
670
661
|
| Missing NavigationApplicationSeedData | Menu invisible without Application level |
|
|
671
662
|
|
|
@@ -740,6 +731,13 @@ services.AddValidatorsFromAssemblyContaining<Create{Name}DtoValidator>();
|
|
|
740
731
|
| `DateTime` for date-only | Use `DateOnly` when no time component needed |
|
|
741
732
|
| FK field as plain text input | Frontend MUST use `EntityLookup` component for Guid FK fields |
|
|
742
733
|
| `PagedResult<T>` / `PaginatedResultDto<T>` | FORBIDDEN — use `PaginatedResult<T>` only |
|
|
734
|
+
| Controller injects `DbContext` | **Clean Architecture violation** — create an Application service and inject it instead |
|
|
735
|
+
| Domain entity has `[Table]` attribute | Infrastructure concern in Domain — move to `IEntityTypeConfiguration<T>` in Infrastructure |
|
|
736
|
+
| `using Microsoft.EntityFrameworkCore` in Domain | EF Core belongs in Infrastructure, not Domain — Domain must be persistence-ignorant |
|
|
737
|
+
| Controller returns `Employee` entity | Domain leak in API response — return `EmployeeResponseDto` instead |
|
|
738
|
+
| `IEmployeeService.cs` in Infrastructure | Interface belongs in Application — move to `Application/Interfaces/` |
|
|
739
|
+
| Service implementation in Application layer | Implementations belong in Infrastructure — Application only contains interfaces |
|
|
740
|
+
| Controller injects `IRepository<T>` directly | Controllers use Application services, not repositories — add a service layer |
|
|
743
741
|
|
|
744
742
|
---
|
|
745
743
|
|
|
@@ -861,8 +859,8 @@ export interface PaginationParams {
|
|
|
861
859
|
- **Max pageSize = 100** — enforced via `Math.Clamp(pageSize, 1, 100)` or extension method
|
|
862
860
|
- **Default page = 1, pageSize = 20** — all GetAll endpoints
|
|
863
861
|
- **Search param mandatory** — enables `EntityLookup` on frontend
|
|
864
|
-
- **POST-CHECK
|
|
865
|
-
- **POST-CHECK
|
|
862
|
+
- **POST-CHECK 11** blocks `List<T>` returns on GetAll
|
|
863
|
+
- **POST-CHECK 26** blocks non-canonical pagination type names
|
|
866
864
|
|
|
867
865
|
---
|
|
868
866
|
|
|
@@ -211,7 +211,7 @@ resources: {
|
|
|
211
211
|
ns: ['common', 'navigation', 'employees', 'projects', 'clients'],
|
|
212
212
|
```
|
|
213
213
|
|
|
214
|
-
POST-CHECK
|
|
214
|
+
POST-CHECK 37 validates this. Unregistered namespaces → BLOCKING.
|
|
215
215
|
|
|
216
216
|
### Rules
|
|
217
217
|
|
|
@@ -407,7 +407,7 @@ const handleTabClick = (tab: TabKey) => {
|
|
|
407
407
|
- Users expect tabs to switch content in-place, not redirect to a different page
|
|
408
408
|
- The browser back button should go to the list page, not toggle between tabs
|
|
409
409
|
|
|
410
|
-
**POST-CHECK
|
|
410
|
+
**POST-CHECK 35 enforces this rule.**
|
|
411
411
|
|
|
412
412
|
---
|
|
413
413
|
|
|
@@ -1179,7 +1179,7 @@ Before marking frontend tasks as complete, verify:
|
|
|
1179
1179
|
- [ ] Translation files exist for **all 4 languages** (fr, en, it, de) in `src/i18n/locales/`
|
|
1180
1180
|
- [ ] All `t()` calls include namespace prefix AND fallback value
|
|
1181
1181
|
- [ ] No hardcoded strings in JSX — all text goes through `t()`
|
|
1182
|
-
- [ ] CSS uses variables only — no hardcoded Tailwind colors (BLOCKING POST-CHECK
|
|
1182
|
+
- [ ] CSS uses variables only — no hardcoded Tailwind colors (BLOCKING POST-CHECK 9)
|
|
1183
1183
|
- [ ] Pages follow loading → error → content pattern
|
|
1184
1184
|
- [ ] Pages use `src/pages/{App}/{Module}/` hierarchy
|
|
1185
1185
|
- [ ] API calls use generated hooks or `apiClient` (never raw axios)
|
|
@@ -1569,3 +1569,99 @@ describe('EntityEditPage', () => {
|
|
|
1569
1569
|
- Use `@testing-library/react` + `@testing-library/user-event` (NEVER enzyme)
|
|
1570
1570
|
- Mock API with `vi.mock()` or MSW — NEVER make real API calls in tests
|
|
1571
1571
|
- Test files live next to their component (co-located, NOT in a separate `__tests__/` folder)
|
|
1572
|
+
|
|
1573
|
+
---
|
|
1574
|
+
|
|
1575
|
+
## 9. Frontend Compliance Gates (5 Mandatory Checks)
|
|
1576
|
+
|
|
1577
|
+
> **Run these checks before any frontend commit.** All 5 gates MUST pass.
|
|
1578
|
+
> Previously in separate files `execution-frontend-gates.md` and `execution-frontend-patterns.md` — now consolidated here.
|
|
1579
|
+
|
|
1580
|
+
### Gate 1: CSS Variables (Theme System)
|
|
1581
|
+
|
|
1582
|
+
```bash
|
|
1583
|
+
ALL_PAGES=$(find src/pages/ src/components/ -name "*.tsx" 2>/dev/null | grep -v node_modules | grep -v "\.test\.")
|
|
1584
|
+
if [ -n "$ALL_PAGES" ]; then
|
|
1585
|
+
HARDCODED=$(grep -Pn '(bg|text|border)-(?!\[)(red|blue|green|gray|white|black|slate|zinc|neutral|stone)-' $ALL_PAGES 2>/dev/null)
|
|
1586
|
+
if [ -n "$HARDCODED" ]; then
|
|
1587
|
+
echo "FAIL: Hardcoded Tailwind colors found — must use CSS variables (see section 4)"
|
|
1588
|
+
echo "$HARDCODED"
|
|
1589
|
+
else
|
|
1590
|
+
echo "PASS: CSS variables"
|
|
1591
|
+
fi
|
|
1592
|
+
fi
|
|
1593
|
+
```
|
|
1594
|
+
|
|
1595
|
+
**Fix mapping:** See section 4 (CSS Variables) for the complete variable reference table.
|
|
1596
|
+
|
|
1597
|
+
### Gate 2: Forms as Pages (ZERO Modals/Drawers)
|
|
1598
|
+
|
|
1599
|
+
```bash
|
|
1600
|
+
PAGE_FILES=$(find src/pages/ -name "*.tsx" 2>/dev/null)
|
|
1601
|
+
if [ -n "$PAGE_FILES" ]; then
|
|
1602
|
+
FAIL=false
|
|
1603
|
+
MODAL_IMPORTS=$(grep -Pn "import.*(?:Modal|Dialog|Drawer|Popup|Sheet|SlideOver|Overlay)" $PAGE_FILES 2>/dev/null)
|
|
1604
|
+
if [ -n "$MODAL_IMPORTS" ]; then
|
|
1605
|
+
echo "FAIL: Modal/Dialog/Drawer imports — forms MUST be full pages (see section 3b)"
|
|
1606
|
+
echo "$MODAL_IMPORTS"
|
|
1607
|
+
FAIL=true
|
|
1608
|
+
fi
|
|
1609
|
+
MODAL_STATE=$(grep -Pn "useState.*(?:isOpen|showModal|showDialog|showCreate|showEdit|showForm|isCreating|isEditing|showDrawer|showPanel|showSlideOver|selectedEntity|editingEntity)" $PAGE_FILES 2>/dev/null)
|
|
1610
|
+
if [ -n "$MODAL_STATE" ]; then
|
|
1611
|
+
echo "FAIL: Inline form state detected — forms MUST be separate pages (see section 3b)"
|
|
1612
|
+
echo "$MODAL_STATE"
|
|
1613
|
+
FAIL=true
|
|
1614
|
+
fi
|
|
1615
|
+
if [ "$FAIL" = false ]; then echo "PASS: No modals/drawers"; fi
|
|
1616
|
+
fi
|
|
1617
|
+
```
|
|
1618
|
+
|
|
1619
|
+
### Gate 3: I18n File Structure
|
|
1620
|
+
|
|
1621
|
+
```bash
|
|
1622
|
+
if [ ! -d "src/i18n/locales" ]; then
|
|
1623
|
+
echo "FAIL: Missing src/i18n/locales/ directory"
|
|
1624
|
+
else
|
|
1625
|
+
for LANG in fr en it de; do
|
|
1626
|
+
JSON_FILES=$(find "src/i18n/locales/$LANG" -name "*.json" 2>/dev/null | wc -l)
|
|
1627
|
+
if [ "$JSON_FILES" -eq 0 ]; then
|
|
1628
|
+
echo "FAIL: No JSON files in src/i18n/locales/$LANG/"
|
|
1629
|
+
else
|
|
1630
|
+
echo "PASS: $LANG ($JSON_FILES files)"
|
|
1631
|
+
fi
|
|
1632
|
+
done
|
|
1633
|
+
fi
|
|
1634
|
+
```
|
|
1635
|
+
|
|
1636
|
+
### Gate 4: Lazy Loading
|
|
1637
|
+
|
|
1638
|
+
```bash
|
|
1639
|
+
APP_TSX=$(find src/ -name "App.tsx" -not -path "*/node_modules/*" 2>/dev/null | head -1)
|
|
1640
|
+
ROUTE_FILES=$(find src/routes/ -name "*.tsx" -o -name "*.ts" 2>/dev/null)
|
|
1641
|
+
if [ -n "$APP_TSX" ]; then
|
|
1642
|
+
STATIC_IMPORTS=$(grep -Pn "^import .+ from '@/pages/" "$APP_TSX" $ROUTE_FILES 2>/dev/null)
|
|
1643
|
+
if [ -n "$STATIC_IMPORTS" ]; then
|
|
1644
|
+
echo "FAIL: Static page imports — MUST use React.lazy() (see section 1)"
|
|
1645
|
+
echo "$STATIC_IMPORTS"
|
|
1646
|
+
else
|
|
1647
|
+
echo "PASS: Lazy loading"
|
|
1648
|
+
fi
|
|
1649
|
+
fi
|
|
1650
|
+
```
|
|
1651
|
+
|
|
1652
|
+
### Gate 5: useTranslation in Pages
|
|
1653
|
+
|
|
1654
|
+
```bash
|
|
1655
|
+
PAGE_FILES=$(find src/pages/ -name "*.tsx" 2>/dev/null | grep -v "\.test\." | grep -v node_modules)
|
|
1656
|
+
if [ -n "$PAGE_FILES" ]; then
|
|
1657
|
+
TOTAL=$(echo "$PAGE_FILES" | wc -l)
|
|
1658
|
+
WITH_I18N=$(grep -l "useTranslation" $PAGE_FILES 2>/dev/null | wc -l)
|
|
1659
|
+
if [ "$WITH_I18N" -eq 0 ]; then
|
|
1660
|
+
echo "FAIL: No pages use useTranslation — all text must be translated (see section 2)"
|
|
1661
|
+
else
|
|
1662
|
+
echo "PASS: $WITH_I18N/$TOTAL pages use useTranslation"
|
|
1663
|
+
fi
|
|
1664
|
+
fi
|
|
1665
|
+
```
|
|
1666
|
+
|
|
1667
|
+
> **ALL 5 gates MUST pass before frontend commit.** When delegating to `/ui-components` skill, include explicit instructions: CSS variables only, forms as full pages, i18n with namespace + fallback.
|
|
@@ -5,6 +5,38 @@
|
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
## Layer Isolation Rules (Clean Architecture)
|
|
9
|
+
|
|
10
|
+
### Dependency Graph (allowed imports)
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Domain → (nothing)
|
|
14
|
+
Application → Domain
|
|
15
|
+
Infrastructure → Domain, Application
|
|
16
|
+
Api → Application, Infrastructure
|
|
17
|
+
Web → Application (via API clients)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### FORBIDDEN Patterns
|
|
21
|
+
|
|
22
|
+
| Layer | FORBIDDEN import | Why |
|
|
23
|
+
|-------|-----------------|-----|
|
|
24
|
+
| Domain | Application, Infrastructure, Api | Domain is the core, depends on nothing |
|
|
25
|
+
| Application | Infrastructure, Api | Application defines interfaces, Infrastructure implements them |
|
|
26
|
+
| Controller | DbContext (direct injection) | Controllers use Application services, not database directly |
|
|
27
|
+
| Controller | IRepository (direct injection) | Controllers use Application services, not repositories |
|
|
28
|
+
| Domain | EF Core attributes (`[Table]`, `[Column]`, `[Index]`) | Domain must be persistence-ignorant; use `IEntityTypeConfiguration<T>` in Infrastructure |
|
|
29
|
+
| Domain | `using Microsoft.EntityFrameworkCore` | Infrastructure concern leaking into Domain |
|
|
30
|
+
| API response | Domain entity (e.g., `ActionResult<Employee>`) | Return DTOs (`EmployeeResponseDto`), never Domain entities |
|
|
31
|
+
|
|
32
|
+
### Enforcement
|
|
33
|
+
|
|
34
|
+
- **MCP `validate_conventions(checks: ['architecture'])`** — scans `.cs` files for forbidden imports, DbContext injection, entity exposure, and service interface placement
|
|
35
|
+
- **MCP `review_code(checks: ['architecture'])`** — detects layer violations, DbContext in controllers, EF Core attributes in Domain, entity exposure in API responses
|
|
36
|
+
- **POST-CHECKs A1–A7** — bash-based defense-in-depth (see `post-checks.md`)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
8
40
|
## Layer 0 — Domain (sequential)
|
|
9
41
|
|
|
10
42
|
**Entities:** `Domain/Entities/{App}/{Module}/`
|
|
@@ -51,7 +83,7 @@
|
|
|
51
83
|
|
|
52
84
|
**BLOCKING:** `dotnet build --no-restore` MUST pass after migration.
|
|
53
85
|
|
|
54
|
-
> **CRITICAL — Migration must cover ALL entities (POST-CHECK
|
|
86
|
+
> **CRITICAL — Migration must cover ALL entities (POST-CHECK 36, 40):**
|
|
55
87
|
> Create/update migration AFTER ALL entities and EF configs are registered in DbContext.
|
|
56
88
|
> Verify with `dotnet ef migrations has-pending-model-changes` — must report NO pending changes.
|
|
57
89
|
> If entities are added incrementally across modules, create a NEW migration for each batch.
|
|
@@ -82,8 +114,8 @@
|
|
|
82
114
|
- CQRS with MediatR
|
|
83
115
|
- FluentValidation for all commands — **MUST register validators via DI:**
|
|
84
116
|
`services.AddValidatorsFromAssemblyContaining<Create{Entity}DtoValidator>();`
|
|
85
|
-
Without DI registration, `[FromBody]` DTOs are never validated (POST-CHECK
|
|
86
|
-
- **Date fields in DTOs MUST use `DateOnly`**, not `string` (POST-CHECK
|
|
117
|
+
Without DI registration, `[FromBody]` DTOs are never validated (POST-CHECK 38)
|
|
118
|
+
- **Date fields in DTOs MUST use `DateOnly`**, not `string` (POST-CHECK 39). See `smartstack-api.md` DTO Type Mapping.
|
|
87
119
|
- DTOs separate from domain entities
|
|
88
120
|
- Service interfaces in Application, implementations in Infrastructure
|
|
89
121
|
- **FORBIDDEN:** `tenantId: Guid.Empty`, `TenantId!.Value`, queries without TenantId filter, `ICurrentUser` (does not exist — use `ICurrentUserService` + `ICurrentTenantService`), `string` type for date fields
|
|
@@ -102,6 +134,10 @@
|
|
|
102
134
|
|
|
103
135
|
**Rules:**
|
|
104
136
|
- `[RequirePermission(Permissions.{Module}.{Action})]` on EVERY endpoint
|
|
137
|
+
- **NavRoute minimum 2 segments** (application.module):
|
|
138
|
+
- `[NavRoute("human-resources.employees")]` (CORRECT — module-level, 2 segments)
|
|
139
|
+
- `[NavRoute("human-resources.employees.departments")]` (CORRECT — section-level, 3 segments)
|
|
140
|
+
- `[NavRoute("administration.ai", Suffix = "prompts")]` (CORRECT — sub-resource with Suffix)
|
|
105
141
|
- **NavRoute values MUST use kebab-case for ALL multi-word segments:**
|
|
106
142
|
- `[NavRoute("human-resources.employees")]` (CORRECT)
|
|
107
143
|
- `[NavRoute("humanresources.employees")]` (WRONG — missing hyphens)
|
|
@@ -109,8 +145,8 @@
|
|
|
109
145
|
- `[NavRoute("projectmanagement.projects")]` (WRONG)
|
|
110
146
|
- Permission paths MUST use kebab-case matching NavRoute codes (e.g., `human-resources.employees.read`)
|
|
111
147
|
- FORBIDDEN: concatenated segments like `humanresources` — must be `human-resources`
|
|
112
|
-
- POST-CHECK
|
|
113
|
-
- **FORBIDDEN:** `[Route("api/...")]` alongside `[NavRoute]` — causes 404s (POST-CHECK
|
|
148
|
+
- POST-CHECK 32 detects non-kebab-case NavRoute values. POST-CHECK 33 detects non-kebab-case permissions
|
|
149
|
+
- **FORBIDDEN:** `[Route("api/...")]` alongside `[NavRoute]` — causes 404s (POST-CHECK 41)
|
|
114
150
|
- `[NavRoute]` is the ONLY route attribute needed — resolves routes from DB at startup
|
|
115
151
|
- NEVER use `[Authorize]` without specific permission
|
|
116
152
|
- Swagger XML documentation
|
|
@@ -136,10 +172,10 @@
|
|
|
136
172
|
|
|
137
173
|
**Application-level (created ONCE, shared across modules):**
|
|
138
174
|
1. **NavigationApplicationSeedData.cs** — Application-level navigation entry (MUST be first)
|
|
139
|
-
2. **ApplicationRolesSeedData.cs** — Application-scoped roles (admin, manager, contributor, viewer) with
|
|
175
|
+
2. **ApplicationRolesSeedData.cs** — Application-scoped roles (admin, manager, contributor, viewer) with random GUIDs (`Guid.NewGuid()`). Provides role entries for SeedRolesAsync().
|
|
140
176
|
|
|
141
177
|
**Per-module:**
|
|
142
|
-
3. **NavigationModuleSeedData.cs** —
|
|
178
|
+
3. **NavigationModuleSeedData.cs** — Random GUIDs (`Guid.NewGuid()`), 4 languages (fr, en, it, de)
|
|
143
179
|
4. **NavigationSectionSeedData.cs** — Section-level navigation (if sections defined)
|
|
144
180
|
5. **NavigationResourceSeedData.cs** — Resource-level navigation (if resources defined)
|
|
145
181
|
6. **Permissions.cs** — Static permission constants: `public static class {Module} { public const string Read = "..."; }`. Referenced by `[RequirePermission(Permissions.{Module}.Read)]`.
|
|
@@ -154,21 +190,13 @@
|
|
|
154
190
|
- `SeedRolePermissionsAsync()` — maps roles to permissions (roles resolved by Code, NOT by GUID)
|
|
155
191
|
- DI: `services.AddScoped<IClientSeedDataProvider, {App}SeedDataProvider>()`
|
|
156
192
|
|
|
157
|
-
###
|
|
193
|
+
### GUID Generation Rule
|
|
158
194
|
|
|
159
195
|
```csharp
|
|
160
|
-
//
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
private static Guid GenerateDeterministicGuid(string input)
|
|
165
|
-
{
|
|
166
|
-
var hash = System.Security.Cryptography.SHA256.HashData(
|
|
167
|
-
System.Text.Encoding.UTF8.GetBytes(input));
|
|
168
|
-
var bytes = new byte[16];
|
|
169
|
-
Array.Copy(hash, bytes, 16);
|
|
170
|
-
return new Guid(bytes);
|
|
171
|
-
}
|
|
196
|
+
// ALWAYS use Guid.NewGuid() for ALL seed data IDs
|
|
197
|
+
// Avoids conflicts between projects/tenants/environments
|
|
198
|
+
// Idempotence is handled by Code-based lookups at runtime
|
|
199
|
+
public static readonly Guid ModuleId = Guid.NewGuid();
|
|
172
200
|
```
|
|
173
201
|
|
|
174
202
|
### Route Convention (CRITICAL — Full Paths Required)
|
|
@@ -217,7 +245,7 @@ var sectionRoute = $"{moduleRoute}/{ToKebabCase(sectionCode)}";
|
|
|
217
245
|
> - Other sections (dashboard, approve, import) = module route + `/{section-kebab}` (normal)
|
|
218
246
|
|
|
219
247
|
**FORBIDDEN:**
|
|
220
|
-
- `Guid.NewGuid()`
|
|
248
|
+
- Deterministic/sequential/fixed GUIDs → ALWAYS use `Guid.NewGuid()`
|
|
221
249
|
- Missing translations (must have fr, en, it, de)
|
|
222
250
|
- Empty seed classes with no seeding logic
|
|
223
251
|
- PascalCase in route URLs → always kebab-case
|
|
@@ -275,7 +303,7 @@ const [loading, setLoading] = useState(true);
|
|
|
275
303
|
### Components & CSS
|
|
276
304
|
|
|
277
305
|
**Components:** SmartTable, SmartFilter, EntityCard, SmartForm, StatCard (NEVER raw HTML)
|
|
278
|
-
**CSS:** Variables ONLY — hardcoded Tailwind colors are **BLOCKING** in POST-CHECK
|
|
306
|
+
**CSS:** Variables ONLY — hardcoded Tailwind colors are **BLOCKING** in POST-CHECK 9:
|
|
279
307
|
|
|
280
308
|
| Instead of | Use |
|
|
281
309
|
|-----------|-----|
|
|
@@ -375,7 +403,7 @@ t('{module}:actions.create', 'Create entity') // ALWAYS with namespace prefix
|
|
|
375
403
|
| Action | Tool |
|
|
376
404
|
|--------|------|
|
|
377
405
|
| Generate doc-data.ts + page wrapper | `/documentation` skill (type: user) |
|
|
378
|
-
| Verify DocToggleButton in pages | POST-CHECK
|
|
406
|
+
| Verify DocToggleButton in pages | POST-CHECK 24 |
|
|
379
407
|
|
|
380
408
|
**Output files:**
|
|
381
409
|
- `src/pages/docs/business/{app}/{module}/doc-data.ts` — data-driven documentation
|
|
@@ -400,3 +428,97 @@ See `references/smartstack-frontend.md` section 7 for the component pattern.
|
|
|
400
428
|
|
|
401
429
|
**Target:** >= 80% coverage, 100% pass rate.
|
|
402
430
|
**Fix CODE, not tests.**
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## Planning Template — Per-File Plan Format
|
|
435
|
+
|
|
436
|
+
> **Used by step-02 when creating the execution plan.** Each entity MUST include:
|
|
437
|
+
|
|
438
|
+
```yaml
|
|
439
|
+
Entity: {EntityName}
|
|
440
|
+
- tenantMode: strict | optional | scoped | none
|
|
441
|
+
- codePattern: auto-generated strategy (if applicable)
|
|
442
|
+
- fkFields: [{field, targetEntity}] (if applicable)
|
|
443
|
+
- acceptance criteria: [AC1, AC2, ...]
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
For EACH file in the plan, specify HOW it will be created/modified:
|
|
447
|
+
|
|
448
|
+
**Layer 0 — Domain + Infrastructure (sequential):**
|
|
449
|
+
|
|
450
|
+
| # | File | Action | Tool |
|
|
451
|
+
|---|------|--------|------|
|
|
452
|
+
| 1 | Domain/Entities/.../Entity.cs | create | MCP scaffold_extension |
|
|
453
|
+
| 2 | Infrastructure/.../EntityConfiguration.cs | create | MCP scaffold_extension |
|
|
454
|
+
| 3 | Infrastructure/Migrations/ | create | MCP suggest_migration + dotnet ef |
|
|
455
|
+
|
|
456
|
+
**Layer 1 — Application + API + Seed Data (parallel):**
|
|
457
|
+
|
|
458
|
+
| # | File | Action | Tool |
|
|
459
|
+
|---|------|--------|------|
|
|
460
|
+
| 4 | Application/Services/.../Service.cs | create | MCP scaffold_extension |
|
|
461
|
+
| 5 | Application/DTOs/.../Dto.cs | create | MCP scaffold_extension |
|
|
462
|
+
| 6 | Api/Controllers/.../Controller.cs | create | /controller skill or MCP scaffold_extension |
|
|
463
|
+
| 7 | Seeding/Data/NavigationApplicationSeedData.cs | create | Reference Layer 1 Seed Data (once per app) |
|
|
464
|
+
| 7b | Seeding/Data/ApplicationRolesSeedData.cs | create | Reference Layer 1 Seed Data (once per app) |
|
|
465
|
+
| 7c | Infrastructure/Services/CodeGeneration/ | create | Reference code-generation.md (if codePattern != manual) |
|
|
466
|
+
| 8 | Seeding/Data/.../NavigationModuleSeedData.cs | create | Reference core-seed-data.md (4 langs) |
|
|
467
|
+
| 8b | Application/Authorization/Permissions.cs | create | MCP generate_permissions |
|
|
468
|
+
| 9 | Seeding/Data/.../PermissionsSeedData.cs | create | MCP generate_permissions |
|
|
469
|
+
| 10 | Seeding/Data/.../RolesSeedData.cs | create | Reference Layer 1 Seed Data |
|
|
470
|
+
| 10b | Seeding/{App}SeedDataProvider.cs | create | Reference core-seed-data.md (IClientSeedDataProvider + DI) |
|
|
471
|
+
|
|
472
|
+
**Layer 1 — Frontend (parallel):**
|
|
473
|
+
|
|
474
|
+
| # | File | Action | Tool |
|
|
475
|
+
|---|------|--------|------|
|
|
476
|
+
| 11 | src/pages/{App}/{Mod}/ListPage.tsx | create | /ui-components skill |
|
|
477
|
+
| 11b | src/pages/{App}/{Mod}/CreatePage.tsx | create | /ui-components skill (FK: EntityLookup) |
|
|
478
|
+
| 11c | src/pages/{App}/{Mod}/EditPage.tsx | create | /ui-components skill (FK: EntityLookup) |
|
|
479
|
+
| 12 | src/services/api/{module}Api.ts | create | MCP scaffold_api_client |
|
|
480
|
+
| 13 | src/routes/{module}.tsx | create | MCP scaffold_routes |
|
|
481
|
+
| 14 | src/i18n/locales/{lang}/{module}.json | create | Reference smartstack-frontend.md (4 languages) |
|
|
482
|
+
|
|
483
|
+
**Layer 2b — Documentation (after frontend):**
|
|
484
|
+
|
|
485
|
+
| # | File | Action | Tool |
|
|
486
|
+
|---|------|--------|------|
|
|
487
|
+
| 14b | src/pages/docs/business/{app}/{module}/doc-data.ts | create | /documentation skill |
|
|
488
|
+
| 14c | src/pages/docs/business/{app}/{module}/index.tsx | create | /documentation skill |
|
|
489
|
+
|
|
490
|
+
**Layer 3 — Tests (sequential):**
|
|
491
|
+
|
|
492
|
+
| # | File | Action | Tool |
|
|
493
|
+
|---|------|--------|------|
|
|
494
|
+
| 15 | tests/.../EntityTests.cs | create | MCP scaffold_tests |
|
|
495
|
+
| 16 | tests/.../ServiceTests.cs | create | MCP scaffold_tests |
|
|
496
|
+
|
|
497
|
+
**FK Field Guidance:** If step-01 identified `fkFields[]`, every Create/Edit page MUST use `EntityLookup` for those fields (see `smartstack-frontend.md` section 6).
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## Parallelization Strategy (Agent Teams)
|
|
502
|
+
|
|
503
|
+
If NOT economy_mode AND Layer 1 has both backend and frontend work:
|
|
504
|
+
|
|
505
|
+
**Create agent teams to execute Layer 1 backend and frontend in parallel.**
|
|
506
|
+
|
|
507
|
+
See `references/agent-teams-protocol.md` for team creation, teammate spawning, task coordination, and shutdown.
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Delegate Mode Fast Path
|
|
512
|
+
|
|
513
|
+
When `/ralph-loop` invokes `/apex -d {prd_path}`, PRD tasks already define the scope.
|
|
514
|
+
|
|
515
|
+
Map each PRD task to a layer based on `task.category`:
|
|
516
|
+
- `domain` → Layer 0
|
|
517
|
+
- `infrastructure` → Layer 0
|
|
518
|
+
- `application` → Layer 1
|
|
519
|
+
- `api` → Layer 1
|
|
520
|
+
- `seedData` → Layer 1
|
|
521
|
+
- `frontend` → Layer 2
|
|
522
|
+
- `test` → Layer 3
|
|
523
|
+
|
|
524
|
+
For each task: infer file_path, action, and tool from category. SKIP user checkpoint. Jump to "Estimated Commits" section.
|
|
@@ -131,9 +131,9 @@ IF failure → warn user, continue in degraded mode (manual tools only)
|
|
|
131
131
|
|
|
132
132
|
## 4. Define Navigation Hierarchy (4 Levels)
|
|
133
133
|
|
|
134
|
-
> **Reference:** Load `references/
|
|
134
|
+
> **Reference:** Load `references/challenge-questions.md` for hierarchy rules and challenge questions:
|
|
135
135
|
> - 4-level hierarchy structure (Application → Module → Section → Resource)
|
|
136
|
-
> - Challenge questions (4a: Application, 4b: Module, 4c: Sections)
|
|
136
|
+
> - Challenge questions (4a: Application, 4b: Module, 4c: Sections, 5a: Entities, 5b: Dependencies)
|
|
137
137
|
> - Validation rules (sections MUST have at least one entry)
|
|
138
138
|
> - Storage format for each level
|
|
139
139
|
> - Delegate mode skip (if -d)
|
|
@@ -13,6 +13,7 @@ next_step: steps/step-02-plan.md
|
|
|
13
13
|
## LOAD CONDITIONALLY
|
|
14
14
|
|
|
15
15
|
- **ALWAYS** read `references/smartstack-api.md` — BaseEntity API, entity/config/controller patterns
|
|
16
|
+
> **CONTEXT NOTE:** This file stays in context and is reused by step-03. Do NOT re-read it there.
|
|
16
17
|
- If NOT `{economy_mode}`: read `references/agent-teams-protocol.md`
|
|
17
18
|
|
|
18
19
|
---
|
|
@@ -12,7 +12,8 @@ next_step: steps/step-03-execute.md
|
|
|
12
12
|
|
|
13
13
|
## LOAD CONDITIONALLY
|
|
14
14
|
|
|
15
|
-
Read `references/smartstack-layers.md` for layer execution rules
|
|
15
|
+
Read `references/smartstack-layers.md` for layer execution rules, skill/MCP mapping, planning templates, and delegate mode fast path.
|
|
16
|
+
> **CONTEXT NOTE:** This file stays in context and is reused by step-03. Do NOT re-read it there.
|
|
16
17
|
|
|
17
18
|
---
|
|
18
19
|
|
|
@@ -54,11 +55,11 @@ IF delegate_mode:
|
|
|
54
55
|
|
|
55
56
|
## 1-3. Layer Mapping, Skill Assignment, Parallelization
|
|
56
57
|
|
|
57
|
-
> **Reference:**
|
|
58
|
+
> **Reference:** All planning procedures are now in `references/smartstack-layers.md` (already loaded above):
|
|
58
59
|
> - Layer assignment matrix (Domain/Infrastructure/Application/API/Seed/Frontend/Tests)
|
|
59
60
|
> - Entity definition template (tenantMode, codePattern, fkFields, ACs)
|
|
60
61
|
> - Skill/MCP assignment table (per file, per layer)
|
|
61
|
-
> - Layer 0/1/2b/3 file lists with tools
|
|
62
|
+
> - Layer 0/1/2b/3 file lists with tools (see "Planning Template" section)
|
|
62
63
|
> - FK field guidance (EntityLookup + backend ?search= parameter)
|
|
63
64
|
> - Parallelization strategy (Agent Teams for Layer 1 backend+frontend)
|
|
64
65
|
> - Delegate mode fast path (PRD task mapping to layers)
|
|
@@ -13,9 +13,9 @@ All code goes through skills (/controller, /application, /ui-components, /efcore
|
|
|
13
13
|
|
|
14
14
|
## LOAD CONDITIONALLY
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
16
|
+
> **CONTEXT REUSE:** `smartstack-api.md` (loaded in step-01) and `smartstack-layers.md` (loaded in step-02) are already in context. Do NOT re-read them.
|
|
17
|
+
|
|
18
|
+
- **ALWAYS** read `references/smartstack-frontend.md` — lazy loading, i18n, page structure, CSS variables, EntityLookup, compliance gates (sections 1-9)
|
|
19
19
|
- If NOT `{economy_mode}` AND Layer 1 has parallel work: read `references/agent-teams-protocol.md`
|
|
20
20
|
- If `{delegate_mode}` AND seedData tasks exist: read `references/core-seed-data.md` — comprehensive seed data templates
|
|
21
21
|
- If build failure during execution: read `references/error-classification.md` — error diagnosis categories A-F
|
|
@@ -98,12 +98,12 @@ dotnet build
|
|
|
98
98
|
|
|
99
99
|
## Layer 1 — Application + API + Seed Data
|
|
100
100
|
|
|
101
|
-
> **
|
|
102
|
-
> - NavRoute and permission kebab-case (
|
|
103
|
-
> - Controller route attributes (
|
|
104
|
-
> - Validators DI registration
|
|
105
|
-
> - DateOnly vs string
|
|
106
|
-
> - Code generation patterns (ICodeGenerator<T> registration)
|
|
101
|
+
> **Layer 1 rules** are in `references/smartstack-layers.md` (already in context from step-02):
|
|
102
|
+
> - NavRoute and permission kebab-case (Layer 1 - API section)
|
|
103
|
+
> - Controller route attributes (FORBIDDEN: [Route] alongside [NavRoute])
|
|
104
|
+
> - Validators DI registration
|
|
105
|
+
> - DateOnly vs string for DTO date fields
|
|
106
|
+
> - Code generation patterns (ICodeGenerator<T> registration, see references/code-generation.md)
|
|
107
107
|
|
|
108
108
|
### Backend Tasks (sequential or parallel)
|
|
109
109
|
|
|
@@ -114,17 +114,17 @@ dotnet build
|
|
|
114
114
|
|
|
115
115
|
### Frontend Tasks (sequential or parallel)
|
|
116
116
|
|
|
117
|
-
> **
|
|
117
|
+
> **Frontend patterns** are in `references/smartstack-frontend.md` (already loaded above):
|
|
118
118
|
> - API client generation (MCP scaffold_api_client)
|
|
119
|
-
> - Route scaffolding (MCP scaffold_routes)
|
|
120
|
-
> - Page types (ListPage, DetailPage, CreatePage, EditPage)
|
|
121
|
-
> - FK field handling (EntityLookup component)
|
|
122
|
-
> - Form structure (ZERO modals — all full pages)
|
|
123
|
-
> - Detail page tabs (local state only)
|
|
124
|
-
> - Testing patterns (co-located form tests)
|
|
125
|
-
> - Section-level routes and permissions
|
|
126
|
-
> -
|
|
127
|
-
> -
|
|
119
|
+
> - Route scaffolding (MCP scaffold_routes) — section 1 + 3b
|
|
120
|
+
> - Page types (ListPage, DetailPage, CreatePage, EditPage) — section 3
|
|
121
|
+
> - FK field handling (EntityLookup component) — section 6
|
|
122
|
+
> - Form structure (ZERO modals — all full pages) — section 3b
|
|
123
|
+
> - Detail page tabs (local state only) — section 3 "Tab Behavior Rules"
|
|
124
|
+
> - Testing patterns (co-located form tests) — section 8
|
|
125
|
+
> - Section-level routes and permissions — section 3b
|
|
126
|
+
> - I18n JSON structure and registration — section 2
|
|
127
|
+
> - Compliance gates (5 mandatory checks) — section 9
|
|
128
128
|
|
|
129
129
|
### If NOT economy_mode: Agent Teams (parallel)
|
|
130
130
|
|
|
@@ -187,8 +187,8 @@ Spawn 2 teammates (Opus, full tools):
|
|
|
187
187
|
→ EntityEditPage.test.tsx (co-located next to page)
|
|
188
188
|
→ Cover: rendering, validation, submit, pre-fill, navigation, errors
|
|
189
189
|
→ See smartstack-frontend.md section 8 for test templates
|
|
190
|
-
- **
|
|
191
|
-
also call MCP generate_permissions for EACH section
|
|
190
|
+
- **PERMISSIONS:** Call MCP generate_permissions for the module permission root (2 segments: {app}.{module}),
|
|
191
|
+
then also call MCP generate_permissions for EACH section (3 segments: {app}.{module}.{section}).
|
|
192
192
|
- **SECTION ROUTES:** Add section child routes to the module's children array.
|
|
193
193
|
Wire PermissionGuard for section routes with section-level permissions.
|
|
194
194
|
- I18n: Generate 4 JSON files per module namespace (fr, en, it, de)
|
|
@@ -253,7 +253,7 @@ After Layer 1 completes:
|
|
|
253
253
|
```
|
|
254
254
|
1. Verify seed data completeness:
|
|
255
255
|
- NavigationModuleSeedData.cs with 4 languages
|
|
256
|
-
- PermissionsSeedData.cs with
|
|
256
|
+
- PermissionsSeedData.cs with Guid.NewGuid()
|
|
257
257
|
- RolesSeedData.cs with context-based role mapping
|
|
258
258
|
- IClientSeedDataProvider updated
|
|
259
259
|
- DI registration added
|
|
@@ -267,8 +267,8 @@ After Layer 1 completes:
|
|
|
267
267
|
|
|
268
268
|
## FRONTEND COMPLIANCE GATE (MANDATORY before commit)
|
|
269
269
|
|
|
270
|
-
> **Reference:**
|
|
271
|
-
> 1. CSS Variables (theme system)
|
|
270
|
+
> **Reference:** See `references/smartstack-frontend.md` section 9 "Compliance Gates" for all 5 mandatory checks:
|
|
271
|
+
> 1. CSS Variables (theme system)
|
|
272
272
|
> 2. Forms as Pages (ZERO modals/drawers/slide-overs)
|
|
273
273
|
> 3. I18n File Structure (4 languages, separate JSON files)
|
|
274
274
|
> 4. Lazy Loading (React.lazy() — no static imports)
|