@atlashub/smartstack-cli 4.32.0 → 4.34.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 (46) hide show
  1. package/.documentation/index.html +2 -2
  2. package/.documentation/init.html +358 -174
  3. package/dist/index.js +45 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/mcp-entry.mjs +271 -44
  6. package/dist/mcp-entry.mjs.map +1 -1
  7. package/package.json +1 -1
  8. package/templates/mcp-scaffolding/controller.cs.hbs +54 -128
  9. package/templates/project/README.md +19 -0
  10. package/templates/project/claude-md/api.CLAUDE.md.template +315 -0
  11. package/templates/project/claude-md/application.CLAUDE.md.template +181 -0
  12. package/templates/project/claude-md/domain.CLAUDE.md.template +125 -0
  13. package/templates/project/claude-md/infrastructure.CLAUDE.md.template +168 -0
  14. package/templates/project/claude-md/root.CLAUDE.md.template +339 -0
  15. package/templates/project/claude-md/web.CLAUDE.md.template +339 -0
  16. package/templates/skills/apex/SKILL.md +16 -10
  17. package/templates/skills/apex/_shared.md +1 -1
  18. package/templates/skills/apex/references/checks/architecture-checks.sh +154 -0
  19. package/templates/skills/apex/references/checks/backend-checks.sh +194 -0
  20. package/templates/skills/apex/references/checks/frontend-checks.sh +448 -0
  21. package/templates/skills/apex/references/checks/infrastructure-checks.sh +255 -0
  22. package/templates/skills/apex/references/checks/security-checks.sh +153 -0
  23. package/templates/skills/apex/references/checks/seed-checks.sh +536 -0
  24. package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +49 -192
  25. package/templates/skills/apex/references/post-checks.md +124 -2156
  26. package/templates/skills/apex/references/smartstack-api.md +160 -957
  27. package/templates/skills/apex/references/smartstack-frontend.md +134 -1022
  28. package/templates/skills/apex/references/smartstack-layers.md +12 -6
  29. package/templates/skills/apex/steps/step-00-init.md +81 -238
  30. package/templates/skills/apex/steps/step-03-execute.md +25 -752
  31. package/templates/skills/apex/steps/step-03a-layer0-domain.md +118 -0
  32. package/templates/skills/apex/steps/step-03b-layer1-seed.md +91 -0
  33. package/templates/skills/apex/steps/step-03c-layer2-backend.md +240 -0
  34. package/templates/skills/apex/steps/step-03d-layer3-frontend.md +300 -0
  35. package/templates/skills/apex/steps/step-03e-layer4-devdata.md +44 -0
  36. package/templates/skills/apex/steps/step-04-examine.md +70 -150
  37. package/templates/skills/application/references/frontend-i18n-and-output.md +2 -2
  38. package/templates/skills/application/references/frontend-route-naming.md +5 -1
  39. package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +49 -198
  40. package/templates/skills/application/references/frontend-verification.md +11 -11
  41. package/templates/skills/application/steps/step-05-frontend.md +26 -15
  42. package/templates/skills/application/templates-frontend.md +4 -0
  43. package/templates/skills/cli-app-sync/SKILL.md +2 -2
  44. package/templates/skills/cli-app-sync/references/comparison-map.md +1 -1
  45. package/templates/skills/controller/references/controller-code-templates.md +70 -67
  46. package/templates/skills/controller/references/mcp-scaffold-workflow.md +5 -1
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: step-03a-layer0-domain
3
+ description: "Layer 0: Domain entities, EF configs, migration"
4
+ model: opus
5
+ parent_step: steps/step-03-execute.md
6
+ ---
7
+
8
+ ## Layer 0 — Domain + Infrastructure (sequential, agent principal)
9
+
10
+ ### Task Progress
11
+ TaskUpdate(taskId: layer0_task_id, status: "in_progress")
12
+ TaskUpdate(taskId: progress_tracker_id,
13
+ description: "Module: {module_code}. Current: step-03 (Execute), Layer 0",
14
+ activeForm: "Executing Layer 0")
15
+
16
+ ### Domain Entities
17
+
18
+ ```
19
+ For each entity to create/modify:
20
+ → MCP scaffold_extension (type: "entity", target: entity_name)
21
+ → Verify: inherits BaseEntity, implements ITenantEntity + IAuditableEntity
22
+ → Verify entity matches patterns in references/smartstack-api.md
23
+ ```
24
+
25
+ ### Code Generation Integration
26
+
27
+ ```
28
+ For each entity with auto-generated code ({code_patterns} from step-00):
29
+ IF {code_patterns} has entry for this entity AND strategy != "manual":
30
+ → Pass codePattern in scaffold_extension options:
31
+ MCP scaffold_extension (type: "entity", target: entity_name, options: {
32
+ codePattern: {
33
+ strategy: {code_patterns[entity].strategy},
34
+ prefix: {code_patterns[entity].prefix},
35
+ digits: {code_patterns[entity].digits},
36
+ includeTenantSlug: {code_patterns[entity].includeTenantSlug},
37
+ separator: {code_patterns[entity].separator}
38
+ }
39
+ })
40
+ → Verify: Code property exists on entity but is NOT in CreateDto
41
+ → Verify: ICodeGenerator<{Entity}> is ready for DI registration (Layer 2)
42
+ ELSE:
43
+ → Default behavior (strategy: "manual", Code in CreateDto)
44
+ ```
45
+
46
+ ### Enum Serialization Check
47
+
48
+ ```
49
+ For each enum type created in Domain/Enums/:
50
+ 1. Grep("JsonStringEnumConverter", "src/**/Program.cs")
51
+ 2. IF global config exists → no action
52
+ 3. IF no global config → add [JsonConverter(typeof(JsonStringEnumConverter))] on each enum
53
+ ```
54
+
55
+ ### Person Extension Detection
56
+
57
+ **If entity has personRoleConfig (mandatory or optional UserId link):**
58
+ See `references/person-extension-pattern.md` for full entity, EF config, service, DTO, and frontend patterns.
59
+
60
+ ```
61
+ 1. scaffold_extension with options: { isPersonRole: true, userLinkMode: 'mandatory' | 'optional' }
62
+ 2. Verify: EF config has unique index on (TenantId, UserId)
63
+ → Mandatory variant: plain .IsUnique()
64
+ → Optional variant: .IsUnique().HasFilter("[UserId] IS NOT NULL")
65
+ 3. Verify all build checks pass before continuing
66
+ ```
67
+
68
+ ### EF Core Configurations
69
+
70
+ ```
71
+ For each entity:
72
+ → Create IEntityTypeConfiguration<T> manually per smartstack-api.md patterns
73
+ → Verify: table name, relationships, indexes
74
+ → Register DbSet in ExtensionsDbContext if new entity
75
+ ```
76
+
77
+ <!-- TODO A6: Replace with MCP scaffold_extension(type: "ef-config") when B2 is ready -->
78
+
79
+ ### Migration
80
+
81
+ > Migration must cover ALL entities. Root cause (test-apex-007): Migration was created once for 3 entities, then 4 more entities were added later without re-running → 4 entities had no tables. Create/update migration AFTER ALL entities and EF configs are registered in DbContext. If entities are added incrementally, create a new migration for each batch.
82
+
83
+ ```
84
+ 1. Verify all entities have been added as DbSet in ExtensionsDbContext
85
+ 2. Verify all EF configurations are registered (ApplyConfigurationsFromAssembly or individual)
86
+ 3. MCP suggest_migration → get standardized name
87
+ 4. dotnet ef migrations add {Name} --project src/{Infra}.csproj --startup-project src/{Api}.csproj -o Persistence/Migrations
88
+ 5. dotnet ef database update (if local DB)
89
+ 6. dotnet build
90
+ 7. Verify: dotnet ef migrations has-pending-model-changes → must report "No pending model changes"
91
+ ```
92
+
93
+ If build fails after migration, fix EF configs before proceeding.
94
+ If `has-pending-model-changes` reports pending changes, entities are missing from the migration — create a new migration.
95
+
96
+ ### Post-Layer 0 Build Gate
97
+
98
+ ```bash
99
+ dotnet build
100
+ # Note: WSL bin\Debug cleanup handled by PostToolUse hook (wsl-dotnet-cleanup.sh)
101
+ ```
102
+
103
+ Must pass before Layer 1. If NuGet error, run `dotnet restore` first. If file lock (MSB3021), use `--output /tmp/{project}_build`.
104
+
105
+ TaskUpdate(taskId: layer0_task_id, status: "completed",
106
+ metadata: { build_gate: "pass" })
107
+
108
+ ### Layer 0 Commit
109
+
110
+ ```
111
+ feat({module}): [domain+infra] {short description}
112
+ ```
113
+
114
+ ---
115
+
116
+ ## NEXT SUB-STEP
117
+
118
+ Load `steps/step-03b-layer1-seed.md`
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: step-03b-layer1-seed
3
+ description: "Layer 1: Seed data (navigation, permissions, roles)"
4
+ model: opus
5
+ parent_step: steps/step-03-execute.md
6
+ ---
7
+
8
+ ## Layer 1 — Seed Data (DEDICATED LAYER — sequential, agent principal)
9
+
10
+ ### Task Progress
11
+ TaskUpdate(taskId: layer1_task_id, status: "in_progress")
12
+ TaskUpdate(taskId: progress_tracker_id,
13
+ description: "Module: {module_code}. Current: step-03 (Execute), Layer 1",
14
+ activeForm: "Executing Layer 1")
15
+
16
+ > This layer is required. Seed data makes modules visible in the UI. Without it, the module exists in code but is invisible to users. Reference: `references/core-seed-data.md` (loaded above) for complete C# templates.
17
+
18
+ ### Application-Level Seed Data (ONCE per application)
19
+
20
+ ```
21
+ 1. NavigationApplicationSeedData.cs
22
+ → Application-level navigation entry (MUST be first)
23
+ → 4 language translations (fr, en, it, de)
24
+
25
+ 2. ApplicationRolesSeedData.cs
26
+ → 4 roles: admin, manager, contributor, viewer
27
+ → References NavigationApplicationSeedData.ApplicationId
28
+ ```
29
+
30
+ ### Per-Module Seed Data
31
+
32
+ ```
33
+ 3. NavigationModuleSeedData.cs
34
+ → 4 languages (fr, en, it, de), GetModuleEntry() + GetTranslationEntries()
35
+ → If sections defined: GetSectionEntries() + GetSectionTranslationEntries()
36
+ → If resources defined: GetResourceEntries() + resource translations
37
+ → Query actual parent from DB for FK (NOT deterministic GUID)
38
+
39
+ 4. Permissions.cs
40
+ → MCP generate_permissions (PRIMARY tool)
41
+ → Static constants: public static class {Module} { public const string Read = "..."; }
42
+ → Permission paths MUST use kebab-case matching NavRoute codes
43
+
44
+ 5. PermissionsSeedData.cs
45
+ → MCP generate_permissions first, fallback template
46
+ → Paths match Permissions.cs, wildcard + CRUD
47
+
48
+ 6. RolesSeedData.cs
49
+ → Admin=wildcard(*), Manager=CRU, Contributor=CR, Viewer=R
50
+ → Code-based role mapping (not deterministic GUIDs for roles)
51
+ → Look up roles by Code at runtime
52
+ ```
53
+
54
+ ### Infrastructure Provider (ONCE per application)
55
+
56
+ ```
57
+ 7. {App}SeedDataProvider.cs
58
+ → Implements IClientSeedDataProvider
59
+ → SeedNavigationAsync(): Application → Module → Section → Resource + translations
60
+ → SeedRolesAsync(): application-scoped roles from ApplicationRolesSeedData
61
+ → SeedPermissionsAsync(): permission entries from PermissionsSeedData
62
+ → SeedRolePermissionsAsync(): maps roles to permissions (by Code, NOT by GUID)
63
+ → DI: services.AddScoped<IClientSeedDataProvider, {App}SeedDataProvider>()
64
+ ```
65
+
66
+ <!-- TODO A4: Replace direct seed generation with MCP scaffold_seed_data when B1 is ready. This will eliminate the need for references/core-seed-data.md (1464 lines). -->
67
+
68
+ ### Post-Layer 1 Build Gate
69
+
70
+ ```bash
71
+ dotnet build
72
+ ```
73
+
74
+ Must pass before Layer 2.
75
+
76
+ TaskUpdate(taskId: layer1_task_id, status: "completed",
77
+ metadata: { build_gate: "pass" })
78
+
79
+ ### Layer 1 Commit
80
+
81
+ ```
82
+ feat({module}): [seed] navigation, permissions, roles
83
+ ```
84
+
85
+ > **Context release:** `references/core-seed-data.md` is no longer needed after Layer 1. Its templates have been consumed. Do not reference it in Layer 2+.
86
+
87
+ ---
88
+
89
+ ## NEXT SUB-STEP
90
+
91
+ Load `steps/step-03c-layer2-backend.md`
@@ -0,0 +1,240 @@
1
+ ---
2
+ name: step-03c-layer2-backend
3
+ description: "Layer 2: Backend services, controllers, and tests"
4
+ model: opus
5
+ parent_step: steps/step-03-execute.md
6
+ ---
7
+
8
+ ## Layer 2 — Backend (Services + Controllers)
9
+
10
+ ### Task Progress
11
+ TaskUpdate(taskId: layer2_task_id, status: "in_progress")
12
+ TaskUpdate(taskId: progress_tracker_id,
13
+ description: "Module: {module_code}. Current: step-03 (Execute), Layer 2",
14
+ activeForm: "Executing Layer 2")
15
+
16
+ > **Layer 2 rules** are in `references/smartstack-layers.md` (already in context from step-02):
17
+ > - NavRoute and permission kebab-case (Layer 2 - API section)
18
+ > - Controller route attributes (FORBIDDEN: [Route] alongside [NavRoute])
19
+ > - Validators DI registration
20
+ > - DateOnly vs string for DTO date fields
21
+ > - Code generation patterns (ICodeGenerator<T> registration, see references/code-generation.md)
22
+
23
+ ### Backend Tasks (sequential or parallel within layer)
24
+
25
+ - Services/DTOs: MCP scaffold_extension
26
+ - Controllers: use /controller skill for complex, MCP scaffold_extension for simple
27
+ - Important: All GetAll endpoints must support `?search=` query parameter (enables EntityLookup on frontend)
28
+ - Guard: DTO mapping in services MUST use inline construction (`new ResponseDto(...)`) inside IQueryable `.Select()`. Never use helper methods (MapToDto, ToDto) inside `.Select()` — EF Core cannot translate them. Helper methods are allowed only after materialization (ToListAsync, FirstAsync).
29
+
30
+ ### Code Generation Service Registration (per entity)
31
+
32
+ ```
33
+ For each entity where {code_patterns} defines strategy != "manual":
34
+ 1. Verify DI registration in DependencyInjection.cs:
35
+ → services.AddScoped<ICodeGenerator<{Entity}>>(sp => new CodeGenerator<{Entity}>(...))
36
+ → Use CodePatternConfig matching {code_patterns[entity]} values
37
+ → See references/code-generation.md "DI Registration Pattern"
38
+ → Guard: Do NOT duplicate if ICodeGenerator<{Entity}> is already registered
39
+ 2. Verify service injection:
40
+ → {Entity}Service constructor receives ICodeGenerator<{Entity}>
41
+ → CreateAsync uses _codeGenerator.NextCodeAsync(ct) instead of dto.Code
42
+ → See references/code-generation.md "Service Integration Pattern"
43
+ 3. Verify CreateDto:
44
+ → Code property MUST NOT be in Create{Entity}Dto
45
+ → Code property MUST be in {Entity}ResponseDto
46
+ → See references/code-generation.md "CreateDto Changes"
47
+ 4. Verify Validator:
48
+ → Create{Entity}Validator has NO Code rule (auto-generated)
49
+ → Update{Entity}Validator has Code rule with regex ^[a-z0-9_-]+$ (if Code is mutable)
50
+ ```
51
+ - FK inter-entity pattern: When an entity has FK to another business entity (e.g., Absence → Employee), use navigation properties directly inside `.Select()` (e.g., `x.Employee.Code`, `x.Employee.User!.LastName`). EF Core translates navigation access to SQL JOINs automatically. Do NOT use `.Include()` with `.Select()` — it is ignored. See `references/smartstack-api.md` "Service Pattern — Entity with FK to another business entity" for the full pattern.
52
+
53
+ ### Skill Delegation
54
+
55
+ | Skill | When | Context to provide |
56
+ |-------|------|--------------------|
57
+ | /controller | Custom routes, complex auth, file upload | entity, CRUD actions, permissions, routes |
58
+ | /application | Full app/module from scratch | app, module names |
59
+ | /ui-components | Complex pages (tables, grids, dashboards) | entity, fields, page type |
60
+ | /efcore | Complex EF configs, inheritance | relationships, indexes |
61
+ | /notification | In-app or email notifications | trigger, recipients, template |
62
+ | /workflow | Automated workflows | trigger, steps, conditions |
63
+
64
+ ### If NOT economy_mode AND multiple entities: Parallel Agents (within layer)
65
+
66
+ > **Protocol:** See `references/parallel-execution.md`
67
+
68
+ ```
69
+ IF NOT economy_mode AND entities.length > 1:
70
+ For each entity, launch in parallel (single message):
71
+ Agent(subagent_type='Snipper', model='opus',
72
+ prompt='Execute Layer 2 backend for {EntityName}:
73
+ - Application service/DTO: MCP scaffold_extension
74
+ - Controller: /controller skill or MCP scaffold_extension
75
+ - IMPORTANT: GetAll endpoint MUST support ?search= parameter
76
+ - Validators: FluentValidation + DI registration
77
+ - CODE GENERATION: {code_patterns[EntityName] summary — e.g., "strategy: sequential, prefix: emp, digits: 5" or "manual"}
78
+ If strategy != "manual": read references/code-generation.md, then:
79
+ → Register ICodeGenerator<{EntityName}> in DI (DependencyInjection.cs) with CodePatternConfig matching {code_patterns}
80
+ → Inject ICodeGenerator<{EntityName}> in {EntityName}Service, use _codeGenerator.NextCodeAsync(ct) in CreateAsync
81
+ → Remove Code from Create{EntityName}Dto (auto-generated, not user-provided)
82
+ → Keep Code in {EntityName}ResponseDto
83
+ → Create{EntityName}Validator: NO Code rule. Update{EntityName}Validator: Code rule with regex ^[a-z0-9_-]+$
84
+ - Your task ID is {task_id}. Call TaskUpdate(status: "in_progress") before starting.
85
+ - Call TaskUpdate(status: "completed", metadata: { files_created: [...] }) when done.')
86
+ # All agents launched in parallel
87
+
88
+ ELSE:
89
+ # Agent principal handles all entities sequentially
90
+ ```
91
+
92
+ ### Parallel Agents + TaskCreate Integration
93
+
94
+ When launching agents for multi-entity layers:
95
+ - Each agent receives its task ID and metadata context in the prompt
96
+ - Agent must call TaskUpdate(status: "in_progress") before starting
97
+ - Agent must call TaskUpdate(status: "completed", metadata: { files_created: [...] }) when done
98
+ - Agent principal monitors via TaskList() after all agents complete
99
+ - Agent principal updates activeForm after each entity completion:
100
+ `TaskUpdate(taskId: layer2_task_id, activeForm: "Building {EntityName} backend (2/5 entities)")`
101
+
102
+ ### Controller NavRoute Attribute (MANDATORY)
103
+
104
+ After controller generation, verify `[NavRoute]` attribute is present on every controller:
105
+ - Expected: `[NavRoute("{app_name}.{module_code}.{section_code}")]` on the controller class
106
+ - If missing: Add it manually above `[Authorize]`
107
+ - When calling `scaffold_extension(type: "controller")`, always pass `navRoute` in options
108
+ - This is REQUIRED for `scaffold_routes` to auto-detect routes in Layer 3
109
+
110
+ ### Guard: NavRoute Uniqueness and Segment Count (MANDATORY)
111
+
112
+ **BEFORE proceeding past Layer 2**, verify for EACH controller:
113
+
114
+ 1. **Unique NavRoute:** No two controllers may share the same `[NavRoute("...")]` value. Duplicate NavRoutes cause routing conflicts → 404s on one of the controllers.
115
+
116
+ 2. **Segment count matches hierarchy:** Count the dots in the NavRoute value:
117
+ - 1 dot = 2 segments (module-level, e.g., `human-resources.employees`) — controller is at `Controllers/{App}/`
118
+ - 2 dots = 3 segments (section-level, e.g., `human-resources.employees.contracts`) — controller is at `Controllers/{App}/{Module}/` or in a section subfolder
119
+ - **If a controller is in a section subfolder** (e.g., `Controllers/{App}/Employees/ContractsController.cs`) **but has only 2 segments** → the API route will be wrong → 404. It MUST have 3 segments.
120
+ - 0 dots = INVALID → BLOCK
121
+
122
+ ```bash
123
+ # Quick validation
124
+ CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
125
+ for f in $CTRL_FILES; do
126
+ NAVROUTE=$(grep -oP '\[NavRoute\("\K[^"]+' "$f")
127
+ if [ -n "$NAVROUTE" ]; then
128
+ DOTS=$(echo "$NAVROUTE" | tr -cd '.' | wc -c)
129
+ if [ "$DOTS" -eq 0 ]; then
130
+ echo "BLOCKING: NavRoute '$NAVROUTE' has only 1 segment (need minimum 2): $f"
131
+ exit 1
132
+ fi
133
+ # Check if controller is in a section subfolder but NavRoute has only 2 segments
134
+ DEPTH=$(echo "$f" | grep -oP 'Controllers/[^/]+/[^/]+/' | wc -l)
135
+ if [ "$DEPTH" -gt 0 ] && [ "$DOTS" -eq 1 ]; then
136
+ echo "WARNING: Controller in section subfolder but NavRoute has only 2 segments: $f"
137
+ echo " NavRoute: $NAVROUTE — expected 3 segments (app.module.section)"
138
+ fi
139
+ fi
140
+ done
141
+ ```
142
+
143
+ ```bash
144
+ # Quick check: all controllers must have [NavRoute] (not just [Route])
145
+ CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
146
+ for f in $CTRL_FILES; do
147
+ if ! grep -q "\[NavRoute" "$f" && grep -q "\[Route" "$f"; then
148
+ echo "WARNING: $f has [Route] but no [NavRoute] — add [NavRoute] for route auto-detection"
149
+ fi
150
+ done
151
+ ```
152
+
153
+ ### Layer 2 Build Gate — NavRoute Verification
154
+
155
+ > Fail-fast check: detect MCP generation errors BEFORE Layer 3.
156
+ > Does NOT auto-fix — flags as BLOCKING for manual correction.
157
+ > Full validation in step-04 POST-CHECK C43 + C56.
158
+
159
+ After all controllers are generated and build passes:
160
+
161
+ ```bash
162
+ # Check only controllers generated in this run (match against {entities})
163
+ for ENTITY in $ENTITIES; do
164
+ CTRL=$(find src/ -path "*/Controllers/*" -name "${ENTITY}*Controller.cs" 2>/dev/null | head -1)
165
+ [ -z "$CTRL" ] && continue
166
+
167
+ HAS_NAVROUTE=$(grep -c "\[NavRoute" "$CTRL")
168
+ HAS_ROUTE=$(grep -cP "^\s*\[Route\(" "$CTRL") # class-level only
169
+
170
+ if [ "$HAS_NAVROUTE" -eq 0 ] && [ "$HAS_ROUTE" -gt 0 ]; then
171
+ echo "BLOCKING: $CTRL has [Route] but NO [NavRoute]"
172
+ echo "MCP scaffold_extension generated [Route] instead of [NavRoute]"
173
+ echo "Fix: Replace [Route(\"api/...\")] with [NavRoute(\"{app}.{module}.{section}\")]"
174
+ echo " NavRoute value: derive from naming rules (section 4f)"
175
+ echo " Add: using SmartStack.Api.Routing;"
176
+ fi
177
+
178
+ if [ "$HAS_NAVROUTE" -eq 0 ] && [ "$HAS_ROUTE" -eq 0 ]; then
179
+ echo "BLOCKING: $CTRL has NO route attribute at all"
180
+ echo "Fix: Add [NavRoute(\"{app}.{module}.{section}\")] from naming rules"
181
+ fi
182
+ done
183
+ ```
184
+
185
+ > IF any BLOCKING found: fix the controller(s) BEFORE proceeding to Layer 3.
186
+ > The fix is: remove [Route], add [NavRoute] with the correct dot-separated value,
187
+ > add `using SmartStack.Api.Routing;`.
188
+
189
+ ### Post-Layer 2 Build Gate
190
+
191
+ ```bash
192
+ dotnet build
193
+ ```
194
+
195
+ Must pass before backend tests.
196
+
197
+ TaskUpdate(taskId: layer2_task_id, status: "completed",
198
+ metadata: { build_gate: "pass" })
199
+ TaskUpdate(taskId: progress_tracker_id,
200
+ activeForm: "Running build gate (Layer 2)")
201
+
202
+ ### Backend Tests Inline
203
+
204
+ > **Tests are scaffolded and run WITHIN Layer 2, not deferred to step-07.**
205
+
206
+ ```
207
+ 1. Scaffold backend tests:
208
+ → MCP scaffold_tests (target_layer: "domain", module: "{module_code}", test_type: "unit")
209
+ → MCP scaffold_tests (target_layer: "application", module: "{module_code}", test_type: "unit")
210
+ → MCP scaffold_tests (target_layer: "api", module: "{module_code}", test_type: "integration")
211
+
212
+ 2. Run tests:
213
+ dotnet test --no-build --verbosity normal
214
+
215
+ 3. Fix loop (max 3 iterations):
216
+ IF tests fail:
217
+ → Identify root cause (ALWAYS code bug, not test bug)
218
+ → Fix production CODE via appropriate skill/MCP
219
+ → dotnet build --no-restore
220
+ → dotnet test --no-build
221
+ → Repeat until pass or max 3
222
+
223
+ 4. If still failing after 3 iterations: note failures, continue to Layer 3.
224
+ Step-07 "Final Test Sweep" will handle remaining failures.
225
+ ```
226
+
227
+ ### Layer 2 Commits
228
+
229
+ ```
230
+ feat({module}): [app+api] {short description}
231
+ test({module}): backend unit and integration tests
232
+ ```
233
+
234
+ > **Context release:** `references/smartstack-api.md` entity patterns and `references/smartstack-layers.md` Layer 2 rules have been consumed. Layer 3 only needs their frontend sections (already covered by `smartstack-frontend.md`).
235
+
236
+ ---
237
+
238
+ ## NEXT SUB-STEP
239
+
240
+ Load `steps/step-03d-layer3-frontend.md`