@atlashub/smartstack-cli 4.13.0 → 4.16.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlashub/smartstack-cli",
3
- "version": "4.13.0",
3
+ "version": "4.16.1",
4
4
  "description": "SmartStack Claude Code automation toolkit - GitFlow, EF Core migrations, prompts and more",
5
5
  "author": {
6
6
  "name": "SmartStack",
@@ -1,3 +1,4 @@
1
+ {{!-- DEPRECATED: Ce template n'est plus utilisé. scaffold_api_client génère le code inline. --}}
1
2
  {{!-- SmartStack API Client Template --}}
2
3
  {{!-- Generates type-safe API client with NavRoute integration --}}
3
4
 
@@ -43,13 +43,36 @@ Task:
43
43
 
44
44
  ## Task List Coordination (T10)
45
45
 
46
- Team lead manages the task list:
46
+ ### Task Creation (by team lead, BEFORE spawning teammates)
47
+
48
+ Tasks MUST be created upfront for the full layer scope:
49
+
50
+ ```
51
+ FOR EACH entity in layer:
52
+ TaskCreate(
53
+ subject: "Layer {N}: {Entity} {layer_type}",
54
+ description: "{detailed scope: files, skills, MCP tools}",
55
+ activeForm: "{Building/Creating} {Entity} {layer_type}"
56
+ )
57
+ ```
58
+
59
+ ### Task Assignment (by team lead, WHEN spawning)
60
+
61
+ Include task ID and metadata context in teammate prompt:
62
+
63
+ ```
64
+ "Your assigned task ID is {task_id}.
65
+ Your metadata context: entities={entities}, layer={layer}, tools={tools}.
66
+ Call TaskUpdate(taskId: '{task_id}', status: 'in_progress') before starting.
67
+ Call TaskUpdate(taskId: '{task_id}', status: 'completed', metadata: { files_created: [...] }) after ENTITY_COMPLETE message."
68
+ ```
69
+
70
+ ### Task Monitoring (by team lead)
47
71
 
48
72
  ```
49
- 1. TaskCreate: create task for each work item, assign owner
50
- 2. Teammate: TaskUpdate(status: "in_progress") before starting
51
- 3. Teammate: TaskUpdate(status: "completed") after finishing
52
- 4. Lead: TaskList to monitor progress
73
+ 1. TaskList() check progress after each teammate message
74
+ 2. All tasks completed proceed to build gate
75
+ 3. Any task stuck investigate, reassign if needed
53
76
  ```
54
77
 
55
78
  ---
@@ -24,6 +24,23 @@ const {EntityName}Page = lazy(() => import('@/pages/{Application}/{Module}/{Enti
24
24
 
25
25
  ---
26
26
 
27
+ ## Step 4a.5: Import Generated Route Extensions (if scaffold_routes was used)
28
+
29
+ If `scaffold_routes` generated `applicationRoutes.generated.tsx`, import and spread:
30
+
31
+ ```tsx
32
+ import { applicationRouteExtensions } from '@/routes/applicationRoutes.generated';
33
+
34
+ const applicationRoutes: ApplicationRouteExtensions = {
35
+ ...applicationRouteExtensions,
36
+ // additional manual routes if needed...
37
+ };
38
+ ```
39
+
40
+ If no generated file exists, add routes directly to the existing `applicationRoutes` object.
41
+
42
+ ---
43
+
27
44
  ## Step 4b: Detect App.tsx Routing Pattern
28
45
 
29
46
  Read App.tsx and detect which pattern is used:
@@ -81,6 +98,27 @@ Find `<Route path="/t/:slug">` and add the **same route entries** there.
81
98
 
82
99
  ---
83
100
 
101
+ ## Step 4b.5: Verify mergeRoutes() Call (BLOCKING)
102
+
103
+ **BEFORE modifying routes, READ App.tsx and verify the `mergeRoutes()` call has 2 parameters.**
104
+
105
+ ✅ Correct:
106
+ ```tsx
107
+ const routes = mergeRoutes(clientRoutes, applicationRoutes);
108
+ ```
109
+
110
+ ❌ If you see only 1 parameter:
111
+ ```tsx
112
+ const routes = mergeRoutes(clientRoutes);
113
+ ```
114
+
115
+ → Add the `applicationRoutes` object and pass it as 2nd parameter.
116
+ Without it, ALL application routes are silently ignored → blank page or /login redirect.
117
+
118
+ **NEVER remove the `applicationRoutes` parameter or the `ApplicationRouteExtensions` import.**
119
+
120
+ ---
121
+
84
122
  ## Step 4c: Application-to-Layout Mapping
85
123
 
86
124
  | Application prefix | Layout Component | Route path |
@@ -136,6 +174,23 @@ The `to` prop is resolved relative to the **parent route** (`/{application}`), s
136
174
  - Adding application routes to `clientRoutes[]` with absolute paths — `clientRoutes` is ONLY for routes outside SmartStack applications (e.g., `/about`, `/pricing`)
137
175
  - Adding routes OUTSIDE the Layout wrapper (shell will not render)
138
176
  - Using `createBrowserRouter` (SmartStack uses `useRoutes()` + `mergeRoutes()`)
177
+ - Adding custom application routes to `clientRoutes[]` with absolute paths:
178
+ ```tsx
179
+ // ❌ WRONG — bypasses RouteGuard + TenantLayout + AppLayout → /login redirect
180
+ const clientRoutes: RouteConfig[] = [
181
+ { path: '/human-resources/employees/management', element: <EmployeePage /> },
182
+ ];
183
+ ```
184
+ Custom application routes MUST go in `applicationRoutes` with RELATIVE paths:
185
+ ```tsx
186
+ // ✅ CORRECT
187
+ const applicationRoutes: ApplicationRouteExtensions = {
188
+ 'human-resources': [
189
+ { path: 'employees/management', element: <EmployeePage /> },
190
+ ],
191
+ };
192
+ ```
193
+ - Removing the `applicationRoutes` 2nd parameter from `mergeRoutes()` — this silently breaks ALL custom routes
139
194
 
140
195
  ---
141
196
 
@@ -155,6 +155,138 @@ Write to `{output_dir}/02-plan.md` with the complete plan.
155
155
 
156
156
  ---
157
157
 
158
+ ## 8. Create Task List (MANDATORY)
159
+
160
+ > **Visibility:** TaskCreate generates the grouped progress UI with checkboxes.
161
+ > This makes APEX execution trackable and predictable for the user.
162
+
163
+ After plan is finalized (auto_mode or user approved):
164
+
165
+ ### Task Creation Rules
166
+
167
+ 1. Create ONE task per layer (Layer 0-4)
168
+ 2. For multi-entity layers (2, 3): create ONE sub-task per entity within the layer
169
+ 3. Add build/test gate tasks after each layer
170
+ 4. Set dependencies via `addBlockedBy` to enforce layer ordering
171
+
172
+ ### Metadata Schema
173
+
174
+ > **All APEX tasks use this metadata schema for context recovery after compression:**
175
+
176
+ ```typescript
177
+ // Schema for ALL APEX tasks
178
+ {
179
+ layer?: number, // 0-4, absent for meta/examine/finding tasks
180
+ apex_step?: string, // "02-plan", "03-execute", etc (meta task only)
181
+ entities?: string[], // entities concerned
182
+ tools?: string[], // MCP tools/skills used
183
+ build_gate?: "pending" | "pass" | "fail",
184
+ files_created?: string[], // updated via TaskUpdate after creation
185
+ module?: string, // module code (meta task only)
186
+ app?: string, // app name (meta task only)
187
+ flags?: object // APEX flags (meta task only)
188
+ }
189
+ ```
190
+
191
+ ### Task Template
192
+
193
+ ```
194
+ # APEX Progress Tracker (recovery anchor)
195
+ TaskCreate(subject: "APEX Progress",
196
+ description: "Module: {module_code}, App: {app_name}, Entities: {entities list}. Current: step-02 (Plan)",
197
+ activeForm: "Planning execution",
198
+ metadata: {
199
+ apex_step: "02-plan",
200
+ module: "{module_code}",
201
+ app: "{app_name}",
202
+ entities: ["{entity1}", "{entity2}"],
203
+ flags: { auto: {auto_mode}, economy: {economy_mode}, examine: {examine_mode} }
204
+ })
205
+
206
+ # Layer 0 — Domain + Infrastructure
207
+ TaskCreate(subject: "Layer 0: Domain + Infrastructure",
208
+ description: "Entities: {entity1} ({tenantMode}), {entity2} ({tenantMode}).
209
+ Files: Domain/Entities/*.cs, Infrastructure/Persistence/Configs/*.cs, Migration.
210
+ Tools: MCP scaffold_extension (type: entity, configuration). MCP suggest_migration.
211
+ Gate: dotnet build --no-restore. ACs: {relevant ACs}.",
212
+ activeForm: "Creating domain entities",
213
+ metadata: { layer: 0, entities: [...], tools: ["scaffold_extension", "suggest_migration"], build_gate: "pending", files_created: [] })
214
+
215
+ # Layer 1 — Seed Data
216
+ TaskCreate(subject: "Layer 1: Seed Data",
217
+ description: "Navigation, permissions, roles, provider for {module_code}.
218
+ Files: Seeding/Data/{Module}/*.cs, {App}SeedDataProvider.cs.
219
+ Tools: MCP generate_permissions. Ref: core-seed-data.md.
220
+ Gate: dotnet build. ACs: {relevant ACs}.",
221
+ activeForm: "Generating seed data",
222
+ metadata: { layer: 1, entities: [...], tools: ["generate_permissions"], build_gate: "pending", files_created: [] })
223
+ TaskUpdate(taskId: layer1_id, addBlockedBy: [layer0_id])
224
+
225
+ # Layer 2 — Backend (1 task per entity if multi-entity, 1 task if single)
226
+ IF multi-entity:
227
+ FOR EACH entity:
228
+ TaskCreate(subject: "Layer 2: {Entity} backend",
229
+ description: "Service + DTO + Controller + Validator for {Entity}.
230
+ Files: Application/Services/{Entity}Service.cs, Application/DTOs/{Entity}*.cs, Api/Controllers/{Entity}Controller.cs.
231
+ Tools: MCP scaffold_extension, /controller skill. Gate: dotnet build.
232
+ ACs: {relevant ACs for this entity}.",
233
+ activeForm: "Building {Entity} backend",
234
+ metadata: { layer: 2, entities: ["{Entity}"], tools: ["scaffold_extension", "controller"], build_gate: "pending", files_created: [] })
235
+ TaskUpdate(taskId: entity_task_id, addBlockedBy: [layer1_id])
236
+
237
+ # Layer 2 Tests
238
+ TaskCreate(subject: "Layer 2: Backend tests",
239
+ description: "Unit + integration tests for all entities.
240
+ Tools: MCP scaffold_tests (unit + integration). Gate: dotnet test.",
241
+ activeForm: "Running backend tests",
242
+ metadata: { layer: 2, tools: ["scaffold_tests"], build_gate: "pending" })
243
+
244
+ # Layer 3 — Frontend (1 task per entity if multi-entity)
245
+ IF multi-entity:
246
+ FOR EACH entity:
247
+ TaskCreate(subject: "Layer 3: {Entity} frontend",
248
+ description: "API client, pages (List/Detail/Create/Edit), i18n (4 langs), routes for {Entity}.
249
+ Files: src/pages/{App}/{Module}/{Entity}*.tsx, src/i18n/locales/*/{module}.json.
250
+ Tools: MCP scaffold_api_client, MCP scaffold_routes, /ui-components skill.
251
+ Gate: npm run typecheck + 5 compliance gates. ACs: {relevant ACs}.",
252
+ activeForm: "Building {Entity} frontend",
253
+ metadata: { layer: 3, entities: ["{Entity}"], tools: ["scaffold_api_client", "scaffold_routes", "ui-components"], build_gate: "pending", files_created: [] })
254
+ TaskUpdate(taskId: entity_task_id, addBlockedBy: [layer2_tests_id])
255
+
256
+ # Layer 3 Tests + Compliance
257
+ TaskCreate(subject: "Layer 3: Frontend tests + compliance",
258
+ description: "Form tests (Create/Edit .test.tsx), typecheck, 5 compliance gates.
259
+ Tools: Vitest + React Testing Library. Gate: npm run test + typecheck.",
260
+ activeForm: "Running frontend tests",
261
+ metadata: { layer: 3, tools: ["vitest"], build_gate: "pending" })
262
+
263
+ # Layer 4 (if applicable)
264
+ IF NOT foundation_mode AND devdata needed:
265
+ TaskCreate(subject: "Layer 4: DevData",
266
+ description: "Development test data seeder.
267
+ Files: Infrastructure/Persistence/Seeding/DevData/{Module}DevDataSeeder.cs.
268
+ Gate: dotnet build.",
269
+ activeForm: "Creating dev data",
270
+ metadata: { layer: 4, tools: [], build_gate: "pending", files_created: [] })
271
+
272
+ # Post-execution
273
+ TaskCreate(subject: "eXamine: Validation + POST-CHECKs",
274
+ description: "MCP validate_conventions, build, 50 POST-CHECKs, acceptance criteria.
275
+ Tools: MCP validate_conventions, validate_security, validate_frontend_routes.",
276
+ activeForm: "Validating conventions",
277
+ metadata: { tools: ["validate_conventions", "validate_security", "validate_frontend_routes"] })
278
+ ```
279
+
280
+ ### Economy Mode
281
+
282
+ IF economy_mode: Create the SAME tasks (for visibility), but no Agent Teams — agent principal executes sequentially.
283
+
284
+ ### Delegate Mode
285
+
286
+ IF delegate_mode: Create tasks from PRD task list, mapped to layers.
287
+
288
+ ---
289
+
158
290
  ## NEXT STEP
159
291
 
160
292
  Load `steps/step-03-execute.md`
@@ -47,6 +47,12 @@ Execute ALL layers normally (Layer 0 → Layer 1 → Layer 2 → Layer 3 → Lay
47
47
 
48
48
  ## Layer 0 — Domain + Infrastructure (sequential, agent principal)
49
49
 
50
+ ### Task Progress
51
+ TaskUpdate(taskId: layer0_task_id, status: "in_progress")
52
+ TaskUpdate(taskId: progress_tracker_id,
53
+ description: "Module: {module_code}. Current: step-03 (Execute), Layer 0",
54
+ activeForm: "Executing Layer 0")
55
+
50
56
  ### Domain Entities
51
57
 
52
58
  ```
@@ -108,6 +114,9 @@ dotnet build
108
114
 
109
115
  **MUST PASS before Layer 1. If NuGet error, run `dotnet restore` first. If file lock (MSB3021), use `--output /tmp/{project}_build`.**
110
116
 
117
+ TaskUpdate(taskId: layer0_task_id, status: "completed",
118
+ metadata: { build_gate: "pass" })
119
+
111
120
  ### Layer 0 Commit
112
121
 
113
122
  ```
@@ -118,6 +127,12 @@ feat({module}): [domain+infra] {short description}
118
127
 
119
128
  ## Layer 1 — Seed Data (DEDICATED LAYER — sequential, agent principal)
120
129
 
130
+ ### Task Progress
131
+ TaskUpdate(taskId: layer1_task_id, status: "in_progress")
132
+ TaskUpdate(taskId: progress_tracker_id,
133
+ description: "Module: {module_code}. Current: step-03 (Execute), Layer 1",
134
+ activeForm: "Executing Layer 1")
135
+
121
136
  > **This layer is DEDICATED and MANDATORY.** Seed data makes modules visible in the UI.
122
137
  > Without seed data, the module exists in code but is invisible to users.
123
138
  > Reference: `references/core-seed-data.md` (loaded above) for complete C# templates.
@@ -181,6 +196,9 @@ dotnet build
181
196
 
182
197
  **MUST PASS before Layer 2.**
183
198
 
199
+ TaskUpdate(taskId: layer1_task_id, status: "completed",
200
+ metadata: { build_gate: "pass" })
201
+
184
202
  ### Layer 1 Commit
185
203
 
186
204
  ```
@@ -191,6 +209,12 @@ feat({module}): [seed] navigation, permissions, roles
191
209
 
192
210
  ## Layer 2 — Backend (Services + Controllers)
193
211
 
212
+ ### Task Progress
213
+ TaskUpdate(taskId: layer2_task_id, status: "in_progress")
214
+ TaskUpdate(taskId: progress_tracker_id,
215
+ description: "Module: {module_code}. Current: step-03 (Execute), Layer 2",
216
+ activeForm: "Executing Layer 2")
217
+
194
218
  > **Layer 2 rules** are in `references/smartstack-layers.md` (already in context from step-02):
195
219
  > - NavRoute and permission kebab-case (Layer 2 - API section)
196
220
  > - Controller route attributes (FORBIDDEN: [Route] alongside [NavRoute])
@@ -238,6 +262,18 @@ Wait for all teammates to report completion.
238
262
  shutdown_request → shutdown_response → TeamDelete("apex-layer2")
239
263
  ```
240
264
 
265
+ ### Agent Teams + TaskCreate Integration
266
+
267
+ When spawning teammates for multi-entity layers:
268
+ - Each teammate receives its task ID and metadata context in the prompt
269
+ - Teammate MUST call TaskUpdate(status: "in_progress") before starting
270
+ - Teammate MUST call TaskUpdate(status: "completed", metadata: { files_created: [...] }) after SendMessage("ENTITY_COMPLETE")
271
+ - Lead monitors via TaskList() between teammate completions
272
+ - Lead updates activeForm after each entity completion:
273
+ `TaskUpdate(taskId: layer2_task_id, activeForm: "Building {EntityName} backend (2/5 entities)")`
274
+ - Lead updates metadata after each MCP scaffold:
275
+ `TaskUpdate(taskId: layer_task_id, metadata: { files_created: [...previous, "new_file.cs"] })`
276
+
241
277
  ### Post-Layer 2 Build Gate
242
278
 
243
279
  ```bash
@@ -246,6 +282,11 @@ dotnet build
246
282
 
247
283
  **MUST PASS before backend tests.**
248
284
 
285
+ TaskUpdate(taskId: layer2_task_id, status: "completed",
286
+ metadata: { build_gate: "pass" })
287
+ TaskUpdate(taskId: progress_tracker_id,
288
+ activeForm: "Running build gate (Layer 2)")
289
+
249
290
  ### Backend Tests Inline
250
291
 
251
292
  > **Tests are scaffolded and run WITHIN Layer 2, not deferred to step-07.**
@@ -282,6 +323,12 @@ test({module}): backend unit and integration tests
282
323
 
283
324
  ## Layer 3 — Frontend (Pages + I18n + Documentation)
284
325
 
326
+ ### Task Progress
327
+ TaskUpdate(taskId: layer3_task_id, status: "in_progress")
328
+ TaskUpdate(taskId: progress_tracker_id,
329
+ description: "Module: {module_code}. Current: step-03 (Execute), Layer 3",
330
+ activeForm: "Executing Layer 3")
331
+
285
332
  > **Frontend patterns** are in `references/smartstack-frontend.md` (already loaded above):
286
333
  > - API client generation (MCP scaffold_api_client)
287
334
  > - Route scaffolding (MCP scaffold_routes) — section 1 + 3b
@@ -399,6 +446,18 @@ Wait for all teammates to report completion.
399
446
  shutdown_request → shutdown_response → TeamDelete("apex-layer3")
400
447
  ```
401
448
 
449
+ ### Agent Teams + TaskCreate Integration
450
+
451
+ When spawning teammates for multi-entity layers:
452
+ - Each teammate receives its task ID and metadata context in the prompt
453
+ - Teammate MUST call TaskUpdate(status: "in_progress") before starting
454
+ - Teammate MUST call TaskUpdate(status: "completed", metadata: { files_created: [...] }) after SendMessage("ENTITY_COMPLETE")
455
+ - Lead monitors via TaskList() between teammate completions
456
+ - Lead updates activeForm after each entity completion:
457
+ `TaskUpdate(taskId: layer3_task_id, activeForm: "Building {EntityName} frontend (2/5 entities)")`
458
+ - Lead updates metadata after each MCP scaffold:
459
+ `TaskUpdate(taskId: layer_task_id, metadata: { files_created: [...previous, "NewPage.tsx"] })`
460
+
402
461
  ### FRONTEND COMPLIANCE GATE (MANDATORY before commit)
403
462
 
404
463
  > **Reference:** See `references/smartstack-frontend.md` section 9 "Compliance Gates" for all 5 mandatory checks:
@@ -453,6 +512,9 @@ npm run typecheck
453
512
 
454
513
  **MUST PASS before commit.**
455
514
 
515
+ TaskUpdate(taskId: layer3_task_id, status: "completed",
516
+ metadata: { build_gate: "pass" })
517
+
456
518
  ### Layer 3 Commits
457
519
 
458
520
  ```
@@ -464,6 +526,12 @@ test({module}): frontend form tests
464
526
 
465
527
  ## Layer 4 — DevData (optional)
466
528
 
529
+ ### Task Progress
530
+ IF layer4 task exists: TaskUpdate(taskId: layer4_task_id, status: "in_progress")
531
+ IF layer4 task exists: TaskUpdate(taskId: progress_tracker_id,
532
+ description: "Module: {module_code}. Current: step-03 (Execute), Layer 4",
533
+ activeForm: "Executing Layer 4")
534
+
467
535
  > **Business test data for development/demo environments.**
468
536
  > Skip this layer if no meaningful test data is needed.
469
537
 
@@ -477,6 +545,9 @@ test({module}): frontend form tests
477
545
  dotnet build → MUST PASS
478
546
  ```
479
547
 
548
+ IF layer4 task exists: TaskUpdate(taskId: layer4_task_id, status: "completed",
549
+ metadata: { build_gate: "pass" })
550
+
480
551
  ### Layer 4 Commit (if applicable)
481
552
 
482
553
  ```
@@ -14,6 +14,22 @@ next_step: steps/step-05-deep-review.md
14
14
 
15
15
  ---
16
16
 
17
+ ## 0. Task Progress
18
+
19
+ ### Progress Tracker Update
20
+ ```
21
+ TaskUpdate(taskId: progress_tracker_id,
22
+ description: "Module: {module_code}. Current: step-04 (eXamine)",
23
+ activeForm: "Validating conventions")
24
+ ```
25
+
26
+ ### eXamine Task Lifecycle
27
+ ```
28
+ TaskUpdate(taskId: examine_task_id, status: "in_progress")
29
+ ```
30
+
31
+ ---
32
+
17
33
  ## 1. MCP Convention Validation
18
34
 
19
35
  ```
@@ -284,6 +300,11 @@ ELSE:
284
300
  **BLOCKING RULE:** The APEX workflow is NOT complete until steps 07-08 execute.
285
301
  The success criteria require: "Tests: 100% pass, >= 80% coverage" — step-07 verifies coverage and adds security tests.
286
302
 
303
+ ### eXamine Task Lifecycle — Completion
304
+ ```
305
+ TaskUpdate(taskId: examine_task_id, status: "completed")
306
+ ```
307
+
287
308
  **NEXT ACTION:** Load `steps/step-07-tests.md` now.
288
309
 
289
310
  ---
@@ -12,6 +12,17 @@ next_step: steps/step-06-resolve.md
12
12
 
13
13
  ---
14
14
 
15
+ ## 0. Task Progress
16
+
17
+ ### Progress Tracker Update
18
+ ```
19
+ TaskUpdate(taskId: progress_tracker_id,
20
+ description: "Module: {module_code}. Current: step-05 (Deep Review)",
21
+ activeForm: "Reviewing code")
22
+ ```
23
+
24
+ ---
25
+
15
26
  ## 1. Gather Changed Files
16
27
 
17
28
  ```bash
@@ -12,15 +12,34 @@ next_step: steps/step-07-tests.md
12
12
 
13
13
  ---
14
14
 
15
- ## 1. Process BLOCKING Findings
15
+ ## 0. Task Progress
16
+
17
+ ### Progress Tracker Update
18
+ ```
19
+ TaskUpdate(taskId: progress_tracker_id,
20
+ description: "Module: {module_code}. Current: step-06 (Resolve)",
21
+ activeForm: "Fixing findings")
22
+ ```
23
+
24
+ ---
25
+
26
+ ## 1. Create Finding Tasks
16
27
 
17
28
  For each BLOCKING finding from step-05:
18
29
 
19
30
  ```
20
- Finding: {F01, F02, ...}
21
- File: {path}
22
- Issue: {description}
23
- Fix approach: {use appropriate skill/MCP tool}
31
+ TaskCreate(subject: "Fix: {F01} {short description}",
32
+ description: "File: {path}:{line}\nIssue: {description}\nFix: {approach}",
33
+ activeForm: "Fixing {F01}",
34
+ metadata: { finding_id: "F01", severity: "BLOCKING", source_file: "{path}" })
35
+ ```
36
+
37
+ Then process each finding by updating task status:
38
+
39
+ ```
40
+ TaskUpdate(taskId: finding_task_id, status: "in_progress")
41
+ ... apply fix ...
42
+ TaskUpdate(taskId: finding_task_id, status: "completed")
24
43
  ```
25
44
 
26
45
  **Fixing rules:**
@@ -16,6 +16,17 @@ next_step: steps/step-08-run-tests.md
16
16
 
17
17
  ---
18
18
 
19
+ ## Task Progress
20
+
21
+ ### Progress Tracker Update
22
+ ```
23
+ TaskUpdate(taskId: progress_tracker_id,
24
+ description: "Module: {module_code}. Current: step-07 (Final Test Sweep)",
25
+ activeForm: "Running test sweep")
26
+ ```
27
+
28
+ ---
29
+
19
30
  ## 0. Ensure Test Infrastructure Exists
20
31
 
21
32
  ### 0a. Frontend Test Tooling (if frontend was generated)
@@ -24,6 +24,23 @@ const {EntityName}Page = lazy(() => import('@/pages/{Application}/{Module}/{Enti
24
24
 
25
25
  ---
26
26
 
27
+ ## Step 4a.5: Import Generated Route Extensions (if scaffold_routes was used)
28
+
29
+ If `scaffold_routes` generated `applicationRoutes.generated.tsx`, import and spread:
30
+
31
+ ```tsx
32
+ import { applicationRouteExtensions } from '@/routes/applicationRoutes.generated';
33
+
34
+ const applicationRoutes: ApplicationRouteExtensions = {
35
+ ...applicationRouteExtensions,
36
+ // additional manual routes if needed...
37
+ };
38
+ ```
39
+
40
+ If no generated file exists, add routes directly to the existing `applicationRoutes` object.
41
+
42
+ ---
43
+
27
44
  ## Step 4b: Detect App.tsx Routing Pattern
28
45
 
29
46
  Read App.tsx and detect which pattern is used:
@@ -38,10 +55,14 @@ Read App.tsx and detect which pattern is used:
38
55
  const applicationRoutes: ApplicationRouteExtensions = {
39
56
  'human-resources': [
40
57
  // existing routes...
41
- { path: '{module_kebab}', element: <{EntityName}ListPage /> },
42
- { path: '{module_kebab}/new', element: <Create{EntityName}Page /> },
43
- { path: '{module_kebab}/:id', element: <{EntityName}DetailPage /> },
44
- { path: '{module_kebab}/:id/edit', element: <Create{EntityName}Page /> },
58
+ { path: '{module_kebab}/{section_kebab}', element: <{EntityName}ListPage /> },
59
+ { path: '{module_kebab}/{section_kebab}/new', element: <Create{EntityName}Page /> },
60
+ { path: '{module_kebab}/{section_kebab}/:id', element: <{EntityName}DetailPage /> },
61
+ { path: '{module_kebab}/{section_kebab}/:id/edit', element: <Create{EntityName}Page /> },
62
+
63
+ // Parent redirect routes (MANDATORY — prevents /login redirect on parent navigation)
64
+ { path: '{module_kebab}', element: <Navigate to="{module_kebab}/{first_section_kebab}" replace /> },
65
+ { path: '', element: <Navigate to="{first_module_kebab}/{first_section_kebab}" replace /> },
45
66
  ],
46
67
  };
47
68
  ```
@@ -77,6 +98,27 @@ Find `<Route path="/t/:slug">` and add the **same route entries** there.
77
98
 
78
99
  ---
79
100
 
101
+ ## Step 4b.5: Verify mergeRoutes() Call (BLOCKING)
102
+
103
+ **BEFORE modifying routes, READ App.tsx and verify the `mergeRoutes()` call has 2 parameters.**
104
+
105
+ ✅ Correct:
106
+ ```tsx
107
+ const routes = mergeRoutes(clientRoutes, applicationRoutes);
108
+ ```
109
+
110
+ ❌ If you see only 1 parameter:
111
+ ```tsx
112
+ const routes = mergeRoutes(clientRoutes);
113
+ ```
114
+
115
+ → Add the `applicationRoutes` object and pass it as 2nd parameter.
116
+ Without it, ALL application routes are silently ignored → blank page or /login redirect.
117
+
118
+ **NEVER remove the `applicationRoutes` parameter or the `ApplicationRouteExtensions` import.**
119
+
120
+ ---
121
+
80
122
  ## Step 4c: Application-to-Layout Mapping
81
123
 
82
124
  | Application prefix | Layout Component | Route path |
@@ -99,11 +141,56 @@ If `appWiring.issues` is not empty, fix the wiring before proceeding.
99
141
 
100
142
  ---
101
143
 
144
+ ## Step 4e: Parent Redirect Routes (MANDATORY)
145
+
146
+ **CRITICAL:** Without parent redirects, navigating to an application or module URL (e.g., `/human-resources` or `/human-resources/employees`) will cause a redirect to `/login` because no route matches.
147
+
148
+ For each application, you MUST add:
149
+
150
+ 1. **Application root redirect** — redirects `/{application}` to the first module/section:
151
+ ```tsx
152
+ { path: '', element: <Navigate to="{first_module}/{first_section}" replace /> }
153
+ ```
154
+
155
+ 2. **Module redirect** (if modules have sections) — redirects `/{application}/{module}` to first section:
156
+ ```tsx
157
+ { path: '{module}', element: <Navigate to="{module}/{first_section}" replace /> }
158
+ ```
159
+
160
+ **Example:** For NavRoutes `human-resources.employees.management` and `human-resources.employees.departments`:
161
+ ```tsx
162
+ { path: 'employees', element: <Navigate to="employees/management" replace /> },
163
+ { path: '', element: <Navigate to="employees/management" replace /> },
164
+ ```
165
+
166
+ The `to` prop is resolved relative to the **parent route** (`/{application}`), so always use the full path from the application root.
167
+
168
+ > Note: `scaffold_routes` with `outputFormat: "applicationRoutes"` generates these redirects automatically.
169
+
170
+ ---
171
+
102
172
  ## Forbidden Patterns (BOTH patterns)
103
173
 
104
174
  - Adding application routes to `clientRoutes[]` with absolute paths — `clientRoutes` is ONLY for routes outside SmartStack applications (e.g., `/about`, `/pricing`)
105
175
  - Adding routes OUTSIDE the Layout wrapper (shell will not render)
106
176
  - Using `createBrowserRouter` (SmartStack uses `useRoutes()` + `mergeRoutes()`)
177
+ - Adding custom application routes to `clientRoutes[]` with absolute paths:
178
+ ```tsx
179
+ // ❌ WRONG — bypasses RouteGuard + TenantLayout + AppLayout → /login redirect
180
+ const clientRoutes: RouteConfig[] = [
181
+ { path: '/human-resources/employees/management', element: <EmployeePage /> },
182
+ ];
183
+ ```
184
+ Custom application routes MUST go in `applicationRoutes` with RELATIVE paths:
185
+ ```tsx
186
+ // ✅ CORRECT
187
+ const applicationRoutes: ApplicationRouteExtensions = {
188
+ 'human-resources': [
189
+ { path: 'employees/management', element: <EmployeePage /> },
190
+ ],
191
+ };
192
+ ```
193
+ - Removing the `applicationRoutes` 2nd parameter from `mergeRoutes()` — this silently breaks ALL custom routes
107
194
 
108
195
  ---
109
196