@atlashub/smartstack-cli 4.74.0 → 4.76.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 (121) hide show
  1. package/dist/index.js +152 -31
  2. package/dist/index.js.map +1 -1
  3. package/dist/mcp-entry.mjs +14 -3
  4. package/dist/mcp-entry.mjs.map +1 -1
  5. package/package.json +1 -1
  6. package/templates/agents/ba-reader.md +17 -15
  7. package/templates/agents/ba-writer.md +49 -51
  8. package/templates/skills/apex/SKILL.md +2 -2
  9. package/templates/skills/apex/_shared.md +1 -1
  10. package/templates/skills/apex/references/checks/backend-checks.sh +21 -7
  11. package/templates/skills/apex/references/checks/frontend-checks.sh +26 -0
  12. package/templates/skills/apex/references/checks/infrastructure-checks.sh +47 -10
  13. package/templates/skills/apex/references/checks/seed-checks.sh +47 -7
  14. package/templates/skills/apex/references/core-seed-data.md +20 -18
  15. package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +3 -0
  16. package/templates/skills/apex/references/post-checks.md +23 -3
  17. package/templates/skills/apex/references/smartstack-api.md +4 -4
  18. package/templates/skills/apex/references/smartstack-frontend.md +54 -8
  19. package/templates/skills/apex/references/smartstack-layers.md +6 -6
  20. package/templates/skills/apex/steps/step-00-init.md +75 -1
  21. package/templates/skills/apex/steps/step-03-execute.md +16 -4
  22. package/templates/skills/apex/steps/step-03b-layer1-seed.md +65 -6
  23. package/templates/skills/apex/steps/step-03c-layer2-backend.md +50 -5
  24. package/templates/skills/apex/steps/step-03d-layer3-frontend.md +226 -4
  25. package/templates/skills/apex/steps/step-04-examine.md +163 -0
  26. package/templates/skills/apex-verify/SKILL.md +110 -0
  27. package/templates/skills/apex-verify/references/audit-rules.md +50 -0
  28. package/templates/skills/apex-verify/steps/step-00-init.md +119 -0
  29. package/templates/skills/apex-verify/steps/step-01-nav-audit.md +92 -0
  30. package/templates/skills/apex-verify/steps/step-02-crud-audit.md +127 -0
  31. package/templates/skills/apex-verify/steps/step-03-perm-audit.md +119 -0
  32. package/templates/skills/apex-verify/steps/step-04-route-audit.md +98 -0
  33. package/templates/skills/apex-verify/steps/step-05-report.md +110 -0
  34. package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +3 -0
  35. package/templates/skills/application/templates-frontend.md +2 -2
  36. package/templates/skills/business-analyse/SKILL.md +17 -3
  37. package/templates/skills/business-analyse/_shared.md +64 -0
  38. package/templates/skills/business-analyse/patterns/suggestion-catalog.md +34 -26
  39. package/templates/skills/business-analyse/questionnaire/01-context.md +13 -9
  40. package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +20 -27
  41. package/templates/skills/business-analyse/questionnaire.md +86 -9
  42. package/templates/skills/business-analyse/references/03-json-schemas.md +221 -0
  43. package/templates/skills/business-analyse/references/03-post-check-validation.md +208 -0
  44. package/templates/skills/business-analyse/references/03-smartstack-entity-guards.md +32 -0
  45. package/templates/skills/business-analyse/references/04-cross-module-validation.md +95 -0
  46. package/templates/skills/business-analyse/references/04-file-allocation.md +162 -0
  47. package/templates/skills/business-analyse/references/04-naming-audit-checks.md +174 -0
  48. package/templates/skills/business-analyse/references/04-semantic-validation-matrix.md +118 -0
  49. package/templates/skills/business-analyse/references/canonical-json-formats.md +7 -3
  50. package/templates/skills/business-analyse/references/domain-research-playbook.md +234 -0
  51. package/templates/skills/business-analyse/references/entity-sourcing-presentation.md +166 -0
  52. package/templates/skills/business-analyse/references/init-resume-logic.md +70 -0
  53. package/templates/skills/business-analyse/references/module-completeness-challenge.md +174 -0
  54. package/templates/skills/business-analyse/references/multi-app-detection.md +149 -0
  55. package/templates/skills/business-analyse/references/portal-classification.md +52 -0
  56. package/templates/skills/business-analyse/references/robustness-checks.md +1 -1
  57. package/templates/skills/business-analyse/references/validation-checklist.md +35 -6
  58. package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +50 -6
  59. package/templates/skills/business-analyse/steps/step-00-init.md +22 -190
  60. package/templates/skills/business-analyse/steps/step-01-cadrage.md +365 -269
  61. package/templates/skills/business-analyse/steps/step-02-structure.md +98 -20
  62. package/templates/skills/business-analyse/steps/step-03-specify.md +810 -229
  63. package/templates/skills/business-analyse/steps/step-04-consolidate.md +509 -278
  64. package/templates/skills/business-analyse-design/SKILL.md +10 -0
  65. package/templates/skills/business-analyse-design/references/screens-post-check.md +221 -0
  66. package/templates/skills/business-analyse-design/references/screens-type-mapping.md +138 -0
  67. package/templates/skills/business-analyse-design/references/smartcomponents-templates.md +225 -0
  68. package/templates/skills/{business-analyse → business-analyse-design}/references/spec-auto-inference.md +117 -117
  69. package/templates/skills/business-analyse-design/steps/step-01-screens.md +36 -162
  70. package/templates/skills/business-analyse-design/steps/step-02-wireframes.md +8 -7
  71. package/templates/skills/business-analyse-design/steps/step-03-navigation.md +89 -42
  72. package/templates/skills/business-analyse-develop/references/compact-loop.md +9 -0
  73. package/templates/skills/business-analyse-develop/references/handoff-quality-gate.md +132 -0
  74. package/templates/skills/business-analyse-develop/references/prd-v3-transformation.md +326 -0
  75. package/templates/skills/business-analyse-develop/references/report-reconciliation.md +140 -0
  76. package/templates/skills/business-analyse-develop/references/report-template.md +142 -0
  77. package/templates/skills/business-analyse-develop/steps/step-01-task.md +5 -177
  78. package/templates/skills/business-analyse-develop/steps/step-02-execute.md +17 -4
  79. package/templates/skills/business-analyse-develop/steps/step-03-commit.md +6 -2
  80. package/templates/skills/business-analyse-develop/steps/step-04-check.md +6 -0
  81. package/templates/skills/business-analyse-develop/steps/step-05-report.md +3 -269
  82. package/templates/skills/business-analyse-handoff/SKILL.md +10 -0
  83. package/templates/skills/business-analyse-handoff/references/agent-handoff-transform-prompt.md +211 -0
  84. package/templates/skills/business-analyse-handoff/references/context-isolation-pattern.md +47 -0
  85. package/templates/skills/business-analyse-handoff/references/handoff-file-inventory.md +49 -0
  86. package/templates/skills/business-analyse-handoff/references/handoff-global-validation.md +142 -0
  87. package/templates/skills/business-analyse-handoff/references/prd-validation-checks.md +125 -0
  88. package/templates/skills/business-analyse-handoff/references/project-index-update.md +98 -0
  89. package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +9 -160
  90. package/templates/skills/business-analyse-handoff/steps/step-02-export.md +10 -99
  91. package/templates/skills/business-analyse-html/SKILL.md +10 -0
  92. package/templates/skills/business-analyse-html/html/ba-interactive.html +504 -97
  93. package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +79 -2
  94. package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +6 -46
  95. package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +80 -11
  96. package/templates/skills/business-analyse-html/html/src/scripts/06-render-consolidation.js +2 -2
  97. package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +94 -36
  98. package/templates/skills/business-analyse-html/html/src/scripts/12-render-diagrams.js +162 -0
  99. package/templates/skills/business-analyse-html/html/src/styles/10-diagrams.css +73 -0
  100. package/templates/skills/business-analyse-html/html/src/template.html +2 -0
  101. package/templates/skills/business-analyse-html/references/02-embedded-artifacts-building.md +144 -0
  102. package/templates/skills/business-analyse-html/references/02-feature-data-building.md +143 -0
  103. package/templates/skills/business-analyse-html/references/02-mapping-tables.md +442 -0
  104. package/templates/skills/business-analyse-html/references/02-normalization-helpers.md +139 -0
  105. package/templates/skills/business-analyse-html/references/02-screen-format-detection.md +283 -0
  106. package/templates/skills/business-analyse-html/references/02-self-check-validation.md +199 -0
  107. package/templates/skills/business-analyse-html/references/data-build.md +24 -1
  108. package/templates/skills/business-analyse-html/references/data-mapping.md +119 -17
  109. package/templates/skills/business-analyse-html/steps/step-02-build-data.md +18 -555
  110. package/templates/skills/business-analyse-html/steps/step-04-verify.md +92 -3
  111. package/templates/skills/business-analyse-quick/SKILL.md +807 -0
  112. package/templates/skills/{sketch → business-analyse-quick}/references/domain-heuristics.md +59 -3
  113. package/templates/skills/business-analyse-quick/references/prd-schema.md +268 -0
  114. package/templates/skills/business-analyse-review/SKILL.md +10 -0
  115. package/templates/skills/business-analyse-review/references/review-data-mapping.md +6 -0
  116. package/templates/skills/business-analyse-status/SKILL.md +8 -0
  117. package/templates/skills/dev-start/SKILL.md +143 -307
  118. package/templates/skills/efcore/SKILL.md +13 -0
  119. package/templates/skills/sketch/SKILL.md +15 -153
  120. package/templates/skills/ui-components/SKILL.md +1 -1
  121. package/templates/skills/ui-components/patterns/data-table.md +1 -1
@@ -404,12 +404,11 @@ public static readonly Guid {ResourcePascal}ResourceId = Guid.NewGuid();
404
404
 
405
405
  ### Section Methods (add to {ModulePascal}NavigationSeedData.cs)
406
406
 
407
- > **ROUTE SPECIAL CASES (list and detail):**
408
- > The `list` and `detail` sections are view modes of the module, NOT functional sub-areas.
409
- > - `list` section route = module route (e.g., `/human-resources/employees`) — NO `/list` suffix
410
- > - `detail` section route = module route + `/:id` (e.g., `/human-resources/employees/:id`) — NOT `/detail/:id`
411
- > - Do not use: `/{module}/list`, `/{module}/detail/:id`
412
- > - Other sections (dashboard, approve, import) = module route + `/{section-kebab}` (normal)
407
+ > **ROUTE CONVENTION:**
408
+ > ALL sections use a UNIFORM route pattern: module route + `/{section-code}`.
409
+ > - `list` section route = module route + `/list` (e.g., `/human-resources/employees/list`)
410
+ > - `detail` section route = module route + `/:id` (e.g., `/human-resources/employees/:id`) — NOT `/detail/:id` (detail is an implicit route, not a section)
411
+ > - Other sections (dashboard, approve, import) = module route + `/{section-kebab}` (same rule)
413
412
 
414
413
  ```csharp
415
414
  // --- Add AFTER GetTranslationEntries() in {ModulePascal}NavigationSeedData.cs ---
@@ -434,14 +433,18 @@ public static IEnumerable<NavigationSectionSeedEntry> GetSectionEntries(Guid mod
434
433
  Description = "{section1_desc_en}",
435
434
  Icon = "{section1_icon}",
436
435
  IconType = IconType.Lucide,
437
- // ROUTE CONVENTION:
438
- // - "list" section → same as module route (no extra segment)
439
- // - "detail" section → module route + "/:id"
440
- // - Other sections module route + "/{section-kebab}"
441
- // Do not use: "/employees/list", "/employees/detail/:id"
436
+ // ROUTE CONVENTION: ALL sections use module route + "/{section-code}" (uniform rule)
437
+ // - "list" section → module route + "/list" (e.g., /human-resources/employees/list)
438
+ // - Other sections → module route + "/{section-kebab}" (same rule)
439
+ // Implicit routes (detail, create, edit) are NOT sections registered by DynamicRouter convention
442
440
  Route = "{section_route}", // From seedDataCore.navigationSections[].route
443
441
  DisplayOrder = {section1_sort},
444
- IsActive = true
442
+ // VISIBILITY RULE (MANDATORY):
443
+ // Reserved codes ("detail", "create", "edit") and codes containing "-detail"
444
+ // are internal route targets, NOT sidebar menu items.
445
+ // → IsActive = false for these codes (DynamicRouter resolves them by convention)
446
+ // → IsActive = true for all other sections (visible in sidebar menu)
447
+ IsActive = true // Set to FALSE if section code is "detail", "create", "edit", or "*-detail"
445
448
  }
446
449
  // Repeat for each section...
447
450
  };
@@ -522,15 +525,14 @@ public static IEnumerable<NavigationResourceSeedEntry> GetResourceEntries(Guid s
522
525
  {
523
526
  // RESOURCE ROUTE CONVENTION:
524
527
  // Resources inherit their parent section's resolved route as base:
525
- // - Under "list" section → base = module route (no /list)
526
- // - Under "detail" section → base = module route (no /detail, resource routes don't include /:id)
528
+ // - Under "list" section → base = module route + /list
527
529
  // - Under other sections → base = module route + /{section-kebab}
528
530
  // Then append: /{resource-kebab}
529
531
  //
530
532
  // Example: resource "export" under section "dashboard":
531
533
  // Route = /human-resources/employees/dashboard/export
532
534
  // Example: resource "employees-grid" under section "list":
533
- // Route = /human-resources/employees/employees-grid (NOT /employees/list/employees-grid)
535
+ // Route = /human-resources/employees/list/employees-grid
534
536
  new NavigationResourceSeedEntry
535
537
  {
536
538
  Id = {Resource1Pascal}ResourceId,
@@ -539,7 +541,7 @@ public static IEnumerable<NavigationResourceSeedEntry> GetResourceEntries(Guid s
539
541
  Label = "{resource1_label_en}",
540
542
  EntityType = "{resource1_entity}",
541
543
  // Use parent section's resolved route + /{resource-kebab}
542
- // For "list"/"detail" sections, the section route = module route (no /list or /detail segment)
544
+ // For "list" sections, route = module route + /list. "detail" is implicit (not a section).
543
545
  Route = "{resource_route}", // From seedDataCore: parent section route + /{resource-kebab}
544
546
  DisplayOrder = 1
545
547
  }
@@ -591,10 +593,10 @@ public class NavigationResourceSeedEntry
591
593
  | `{section_label_xx}` | `specification.navigation.entries[]` where `level == "section"` → `labels.xx` |
592
594
  | `{section_icon}` | `seedDataCore.navigationSections[].icon` |
593
595
  | `{section_sort}` | `seedDataCore.navigationSections[].sort` |
594
- | `{section_route}` | `seedDataCore.navigationSections[].route` — **SPECIAL CASES:** `list` module route (no `/list`), `detail` → module route + `/:id` (no `/detail/:id`), others module route + `/{section-kebab}` |
596
+ | `{section_route}` | `seedDataCore.navigationSections[].route` — ALL sections use uniform rule: module route + `/{section-code}` (`list` → module route + `/list`). `detail` is implicit (not a section): module route + `/:id`. |
595
597
  | `{resourceCode}` | `seedDataCore.navigationResources[].code` |
596
598
  | `{resource_entity}` | `seedDataCore.navigationResources[].entity` |
597
- | `{resource_route}` | Computed from parent section route + `/{resource-kebab}`. **SPECIAL CASES:** if parent section is `list` → module route + `/{resource-kebab}` (no `/list/`), if parent is `detail` → module route + `/{resource-kebab}` (no `/detail/`). |
599
+ | `{resource_route}` | Computed from parent section route + `/{resource-kebab}`. For `list` parent → module route + `/list/{resource-kebab}`. For other parents → module route + `/{section-kebab}/{resource-kebab}`. |
598
600
  | `{parentSectionCode}` | `seedDataCore.navigationResources[].parentCode` |
599
601
 
600
602
  ---
@@ -48,6 +48,9 @@ import './extensions/componentRegistry.generated';
48
48
 
49
49
  ## For Client SDK Pages
50
50
 
51
+ > **CRITICAL:** Keys use DOT notation (`rh.employes.list`), NEVER hyphens (`rh-employes-list`).
52
+ > Dots are hierarchy separators matching `NavigationService.ComponentKey` computation at runtime.
53
+
51
54
  Clients register their own pages directly:
52
55
 
53
56
  ```tsx
@@ -39,7 +39,7 @@ bash references/checks/infrastructure-checks.sh
39
39
  | S8 | BLOCKING | Write endpoints must NOT use Read permissions | security-checks.sh |
40
40
  | S9 | BLOCKING | FK relationships must enforce tenant isolation | security-checks.sh |
41
41
 
42
- ### Backend — Entity, Service & Controller Checks (V1-V2, C8, C12, C14, C28-C31, C54)
42
+ ### Backend — Entity, Service & Controller Checks (V1-V2, C8, C12, C14, C28-C31, C54, C62)
43
43
 
44
44
  | ID | Severity | Description | Script |
45
45
  |----|----------|-------------|--------|
@@ -53,6 +53,7 @@ bash references/checks/infrastructure-checks.sh
53
53
  | C30 | BLOCKING | Code regex must support hyphens | backend-checks.sh |
54
54
  | C31 | WARNING | CreateDto must NOT have Code field when service uses ICodeGenerator | backend-checks.sh |
55
55
  | C54 | BLOCKING | No helper method calls inside .Select() on IQueryable | backend-checks.sh |
56
+ | C62 | WARNING | Services must use TenantContextRequiredException for tenant check, NOT InvalidOperationException | backend-checks.sh |
56
57
 
57
58
  ### Frontend — CSS, Forms, Components, I18n (C3a, C3-C7, C9, C11, C24-C27, C36-C37, C49, C52)
58
59
 
@@ -74,6 +75,7 @@ bash references/checks/infrastructure-checks.sh
74
75
  | C37 | CRITICAL | Detail page tabs must NOT navigate() — content switches locally | frontend-checks.sh |
75
76
  | C49 | BLOCKING | Route Ordering in App.tsx — static before dynamic | frontend-checks.sh |
76
77
  | C52 | BLOCKING | Frontend route paths must include module segment | frontend-checks.sh |
78
+ | C64 | BLOCKING | ListPages must have Create/New button (navigate to create route) | frontend-checks.sh |
77
79
 
78
80
  ### Seed Data — Navigation, Roles, Permissions (C1-C2, C10, C15-C23, C32-C35, C44-C48, C53)
79
81
 
@@ -88,7 +90,7 @@ bash references/checks/infrastructure-checks.sh
88
90
  | C18 | BLOCKING | Permissions.cs static constants must exist | seed-checks.sh |
89
91
  | C19 | BLOCKING | ApplicationRolesSeedData.cs must exist | seed-checks.sh |
90
92
  | C20 | WARNING | Section route completeness (NavigationSection → frontend route + permissions) | seed-checks.sh |
91
- | C21 | WARNING | FORBIDDEN route patterns — /list and /detail/:id | seed-checks.sh |
93
+ | C21 | WARNING | FORBIDDEN route patterns — /detail/:id | seed-checks.sh |
92
94
  | C22 | WARNING | Permission path segment count (2-4 dots expected) | seed-checks.sh |
93
95
  | C23 | BLOCKING | IClientSeedDataProvider must have 4 methods with real implementation (not stubs) + DI registration | seed-checks.sh |
94
96
  | C32 | CRITICAL | Translation seed data must have idempotency guard | seed-checks.sh |
@@ -103,6 +105,7 @@ bash references/checks/infrastructure-checks.sh
103
105
  | C53 | BLOCKING | Enum serialization — JsonStringEnumConverter required | seed-checks.sh |
104
106
  | C57 | BLOCKING | SeedDataProvider Seed*Async methods must NOT be `return Task.CompletedTask` or empty body — stubs cause empty menu | seed-checks.sh |
105
107
  | C58 | BLOCKING | File paths in filesToCreate must be valid C# identifiers — no spaces, apostrophes, or accents | seed-checks.sh |
108
+ | C63 | BLOCKING | Reserved section codes (detail/create/edit/*-detail) must NOT be seeded as menu items | seed-checks.sh |
106
109
 
107
110
  ### Architecture — Clean Architecture Layer Isolation (A1-A8)
108
111
 
@@ -117,7 +120,7 @@ bash references/checks/infrastructure-checks.sh
117
120
  | A7 | WARNING | No direct repository usage in controllers | architecture-checks.sh |
118
121
  | A8 | BLOCKING | API endpoints must match handoff apiEndpointSummary | architecture-checks.sh |
119
122
 
120
- ### Infrastructure — Migration & Build (C13, C38-C43, C50-C51, C56)
123
+ ### Infrastructure — Migration & Build (C13, C38-C43, C50-C51, C56, C60-C61)
121
124
 
122
125
  | ID | Severity | Description | Script |
123
126
  |----|----------|-------------|--------|
@@ -131,6 +134,23 @@ bash references/checks/infrastructure-checks.sh
131
134
  | C50 | BLOCKING | NavRoute Uniqueness — no duplicate NavRoute values | infrastructure-checks.sh |
132
135
  | C51 | WARNING | NavRoute Segments vs Controller Hierarchy (depth matching) | infrastructure-checks.sh |
133
136
  | C56 | BLOCKING | Hierarchy Artifact Completeness — current run only (entities + sections) | infrastructure-checks.sh |
137
+ | C60 | BLOCKING | Controllers must inject ISender _mediator, NOT direct business services | infrastructure-checks.sh |
138
+ | C61 | BLOCKING | Controllers with [NavRoute] must have [Authorize] attribute | infrastructure-checks.sh |
139
+
140
+ ### PRD Compliance — Delegate Mode Only (PC-1 to PC-6)
141
+
142
+ > **These checks run ONLY in delegate mode** (when `/apex -d` is used with companion spec files).
143
+ > They validate that generated code matches the PRD specifications from `.ralph/` companion files.
144
+ > Implemented in `step-04-examine.md` section 6d — no separate .sh script needed.
145
+
146
+ | ID | Severity | Description | Source |
147
+ |----|----------|-------------|--------|
148
+ | PC-1 | BLOCKING | All columns from screens.json SmartTable resources must exist in generated ListPage | step-04 §6d |
149
+ | PC-2 | BLOCKING | All actions from screens.json (create, edit, delete, approve, reject, export) must have handlers in pages | step-04 §6d |
150
+ | PC-3 | WARNING | I18n labels must have correct UTF-8 accents (FR: Employés not Employes, DE: Übersicht not Ubersicht) | step-04 §6d |
151
+ | PC-4 | BLOCKING | All permissionPaths from permissions.json must exist in PermissionsSeedData.cs and Permissions.cs | step-04 §6d |
152
+ | PC-5 | WARNING | Every primary/functional section in screens.json must have a corresponding page file | step-04 §6d |
153
+ | PC-6 | WARNING | Module i18n namespace must be registered in i18n config (prevents raw key display) | step-04 §6d |
134
154
 
135
155
  ---
136
156
 
@@ -343,10 +343,10 @@ public class {Name}Controller : ControllerBase
343
343
  | Module | `/{app-kebab}/{module-kebab}` | `/human-resources/employees` |
344
344
  | Section | `/{app-kebab}/{module-kebab}/{section-kebab}` | `/human-resources/employees/departments` |
345
345
 
346
- **Route special cases:** `list` and `detail` sections are view modes, NOT sub-areas:
347
- - `list` route = module route (e.g., `/human-resources/employees`)
348
- - `detail` route = module route + `/:id`
349
- - Do NOT use: `/employees/list`, `/employees/detail/:id`
346
+ **Route convention:** ALL sections use uniform route = module route + `/{section-code}`:
347
+ - `list` route = module route + `/list` (e.g., `/human-resources/employees/list`)
348
+ - `detail` is an implicit route (not a section): module route + `/:id`
349
+ - Do NOT use: `/employees/detail/:id` (detail is implicit)
350
350
 
351
351
  **Rules:**
352
352
  - Routes ALWAYS start with `/`, include full hierarchy, use kebab-case
@@ -121,24 +121,67 @@ t('employees:messages.created', '{{entity}} created', { entity: 'Employee' }) //
121
121
  t('common:actions.save', 'Save') // Cross-namespace
122
122
  ```
123
123
 
124
- ### Namespace Registration (CRITICAL — POST-CHECK C39)
124
+ ### Namespace Registration (CRITICAL — POST-CHECK C39 + GATE PG-4)
125
125
 
126
- After creating i18n JSON files, register each namespace in `src/i18n/config.ts`:
126
+ After creating i18n JSON files, register each namespace in `src/i18n/config.ts` or `index.ts`:
127
127
 
128
128
  ```typescript
129
- import employees from './locales/fr/employees.json';
130
- // In resources: fr: { employees, common, navigation, ... }
131
- // OR in ns array: ns: ['common', 'navigation', 'employees'],
129
+ // CORRECT Full i18n config with module namespaces registered
130
+ import i18n from 'i18next';
131
+ import { initReactI18next } from 'react-i18next';
132
+ import LanguageDetector from 'i18next-browser-languagedetector';
133
+
134
+ // Import ALL module translation files for each language
135
+ import frEmployes from './locales/fr/employes.json';
136
+ import enEmployes from './locales/en/employes.json';
137
+ import itEmployes from './locales/it/employes.json';
138
+ import deEmployes from './locales/de/employes.json';
139
+ import frAbsences from './locales/fr/absences.json';
140
+ import enAbsences from './locales/en/absences.json';
141
+ import itAbsences from './locales/it/absences.json';
142
+ import deAbsences from './locales/de/absences.json';
143
+ // ... repeat for each module
144
+
145
+ i18n
146
+ .use(LanguageDetector)
147
+ .use(initReactI18next)
148
+ .init({
149
+ fallbackLng: 'fr',
150
+ ns: ['employes', 'absences'], // List ALL namespaces
151
+ defaultNS: 'employes',
152
+ interpolation: { escapeValue: false },
153
+ resources: {
154
+ fr: { employes: frEmployes, absences: frAbsences },
155
+ en: { employes: enEmployes, absences: enAbsences },
156
+ it: { employes: itEmployes, absences: itAbsences },
157
+ de: { employes: deEmployes, absences: deAbsences },
158
+ },
159
+ });
160
+
161
+ export default i18n;
132
162
  ```
133
163
 
134
- Root cause (test-apex-007): JSON files existed but namespaces were not registered → `useTranslation(['module'])` returned empty strings.
164
+ ```typescript
165
+ // WRONG — Missing namespace imports (keys show as raw strings like "list.title")
166
+ i18n.init({
167
+ resources: {
168
+ en: { translation: { welcome: 'Welcome' } },
169
+ fr: { translation: { welcome: 'Bienvenue' } },
170
+ },
171
+ });
172
+ // ❌ Module JSON files exist on disk but are NEVER loaded → useTranslation('employes') returns empty
173
+ ```
174
+
175
+ Root cause (test-apex-007, test-ba-010): JSON files existed but namespaces were not registered → `useTranslation(['module'])` returned empty strings. All t() calls displayed raw keys like `list.title`, `form.department` instead of translated text.
135
176
 
136
177
  **Rules:**
137
- - Provide fallback value as 2nd argument to `t()`
178
+ - Provide fallback value as 2nd argument to `t()`: `t('employes:list.title', 'Liste des employés')`
138
179
  - Use namespace prefix: `t('namespace:key')` — never `t('key')` without namespace
139
180
  - Generate 4 language files (fr, en, it, de) with identical key structures
140
181
  - Register new namespaces in i18n config file after creating JSON files
141
182
  - Do not hardcode user-facing strings in JSX
183
+ - **After writing i18n JSON files:** IMMEDIATELY update i18n config with imports + resources registration
184
+ - **Verify:** `grep -q "{namespace}" src/**/i18n/index.ts` MUST match for EVERY module namespace
142
185
 
143
186
  ---
144
187
 
@@ -213,7 +256,7 @@ const applicationRoutes: ApplicationRouteExtensions = {
213
256
  };
214
257
  ```
215
258
 
216
- **Section-level routes:** `list` and `detail` do NOT add path segments (handled by `index: true` and `:id`). Only other sections (dashboard, approve, import) add `{section-kebab}` child routes.
259
+ **Section-level routes:** ALL sections add their code as path segment (`list` `/list`, `dashboard` → `/dashboard`, `approve` `/approve`). `detail`/`create`/`edit` are implicit routes (`/:id`, `/create`, `/:id/edit`), NOT sections.
217
260
 
218
261
  **PermissionGuard for sections:**
219
262
  ```tsx
@@ -285,9 +328,12 @@ Do NOT use: `bg-white`, `border-gray-200`, `text-gray-900`, hardcoded hex/rgb.
285
328
  - Do not use raw `<table>` — use `DataTable`
286
329
  - Do not create custom spinners — use `Loader2` from lucide-react
287
330
  - Do not import axios directly — use `@/services/api/apiClient`
331
+ - **Do not use raw `fetch()` — use `apiClient` from `@/services/api`** (handles auth, token refresh, tenant isolation)
288
332
  - Use `PageLoader` as Suspense fallback
289
333
  - Use `EntityLookup` for FK Guid fields (not `<select>` or `<input>` for GUIDs)
290
334
 
335
+ > **API access rule:** ALL API calls in hooks and pages MUST use `apiClient` (or the typed API service generated by MCP `scaffold_api_client`). Using raw `fetch()` bypasses authentication, token refresh, and tenant isolation — the page will fail silently when the user is logged in. This applies to custom hooks in `src/hooks/` as well as inline API calls in pages.
336
+
291
337
  ---
292
338
 
293
339
  ## 6. Foreign Key Fields & Entity Lookup
@@ -175,12 +175,12 @@ var sectionRoute = $"{moduleRoute}/{ToKebabCase(sectionCode)}";
175
175
  // → "/human-resources/employees/departments"
176
176
  ```
177
177
 
178
- **Route special cases (list and detail sections):**
179
- > `list` and `detail` are view modes of the module, NOT functional sub-areas.
180
- > - `list` section route = module route (e.g., `/human-resources/employees`) — NO `/list` suffix
181
- > - `detail` section route = module route + `/:id` (e.g., `/human-resources/employees/:id`) — NOT `/detail/:id`
182
- > - Do not use: `/employees/list`, `/employees/detail/:id`
183
- > - Other sections (dashboard, approve, import) = module route + `/{section-kebab}` (normal)
178
+ **Route convention:**
179
+ > ALL sections use a UNIFORM route pattern: module route + `/{section-code}`.
180
+ > - `list` section route = module route + `/list` (e.g., `/human-resources/employees/list`)
181
+ > - `detail` is an implicit route (not a section): module route + `/:id` (e.g., `/human-resources/employees/:id`)
182
+ > - Other sections (dashboard, approve, import) = module route + `/{section-kebab}` (same rule)
183
+ > - Do NOT use: `/employees/detail/:id` (detail is implicit, not a section code)
184
184
 
185
185
  **Do not:**
186
186
  - Use deterministic/sequential/fixed GUIDs — always use `Guid.NewGuid()`
@@ -164,7 +164,7 @@ IF precision_score < 2:
164
164
  ║ Your request looks more like a discovery/design task. ║
165
165
  ║ ║
166
166
  ║ Suggestions: ║
167
- ║ 1. Use /sketch to quickly design your module (~2 min)
167
+ ║ 1. Use /business-analyse-quick to design your module
168
168
  ║ 2. Use /business-analyse for full analysis (40+ questions) ║
169
169
  ║ 3. Rewrite your prompt with entities and fields, e.g.: ║
170
170
  ║ /apex add employees section with Employee entity ║
@@ -224,6 +224,79 @@ All naming variants are derived from {app_name}, {module_code}, {sections}. Do N
224
224
 
225
225
  Call `mcp__smartstack__validate_conventions` after computing derivations. Fix any errors BEFORE step-01.
226
226
 
227
+ ### 4g. Entity-Section Mapping (DETERMINISTIC)
228
+
229
+ > Each entity MUST be mapped to a hierarchy level. This determines the entity's NavRoute segment count
230
+ > (2 vs 3 segments) and whether section-level permissions are needed.
231
+ > **This mapping is consumed by:** step-03b (permissions), step-03c (controllers), step-04 (validation).
232
+
233
+ **Rules:**
234
+
235
+ 1. The entity whose name derives from `{module_code}` is the **module-level entity**.
236
+ It gets `NavRoute = {app}.{module}` (2 segments). Its permissions are module-level.
237
+
238
+ 2. Every other entity that matches a section from `{sections}` is a **section-level entity**.
239
+ It gets `NavRoute = {app}.{module}.{section_code}` (3 segments). Its permissions are section-level.
240
+
241
+ 3. Entities that match NO section stay **module-level** (share the module's NavRoute).
242
+ This is the case for true sub-resources without their own navigation entry (e.g., InvoiceLine).
243
+
244
+ **Matching algorithm:**
245
+
246
+ ```
247
+ FOR EACH entity in {entities}:
248
+ entity_kebab = kebab(pluralize(entity.name)) // "Contact" → "contacts", "Department" → "departments"
249
+
250
+ IF entity_kebab == {module_code} OR singularize(entity_kebab) == singularize({module_code}):
251
+ entity.level = "module"
252
+ entity.navRoute = "{app_name_kebab}.{module_code}"
253
+ entity.section_code = null
254
+
255
+ ELSE:
256
+ matched = {sections}.find(s =>
257
+ s.code == entity_kebab // exact: "contacts" == "contacts"
258
+ OR s.code == singularize(entity_kebab) // singular: "types" for "AbsenceType"
259
+ OR s.code.endsWith(entity_kebab) // suffix: "absence-types" ends with "types"
260
+ OR entity_kebab.endsWith(s.code) // reverse: "project-members" ends with "members"
261
+ )
262
+
263
+ IF matched:
264
+ entity.level = "section"
265
+ entity.navRoute = "{app_name_kebab}.{module_code}.{matched.code}"
266
+ entity.section_code = matched.code
267
+ ELSE:
268
+ entity.level = "module"
269
+ entity.navRoute = "{app_name_kebab}.{module_code}"
270
+ entity.section_code = null
271
+ ```
272
+
273
+ **Delegate mode override:** When `permissionPaths` companion includes section-level paths
274
+ (3+ dot segments like `app.module.section.action`), use those paths as authoritative source
275
+ to derive entity-section mapping instead of name heuristics.
276
+
277
+ **Storage:**
278
+
279
+ ```
280
+ {entity_section_map}: [
281
+ { entity: "Employee", level: "module", navRoute: "rh.employes", section_code: null },
282
+ { entity: "Department", level: "section", navRoute: "rh.employes.departments", section_code: "departments" }
283
+ ]
284
+ ```
285
+
286
+ Propagated to: step-03b (permissions), step-03c (controllers), step-03-execute (state), step-04 (validation).
287
+
288
+ **Post-mapping validation:**
289
+
290
+ ```
291
+ # No duplicate NavRoutes among section-level entities
292
+ section_navroutes = {entity_section_map}.filter(e => e.level == "section").map(e => e.navRoute)
293
+ IF duplicates(section_navroutes) → BLOCKING: two entities mapped to same section
294
+
295
+ # All section_codes exist in {sections}
296
+ FOR EACH entry in {entity_section_map} WHERE section_code != null:
297
+ IF {sections}.find(s => s.code == entry.section_code) == null → BLOCKING: orphan section_code
298
+ ```
299
+
227
300
  ---
228
301
 
229
302
  ## 5. Collect Technical Parameters
@@ -323,6 +396,7 @@ APEX INIT COMPLETE — v{{SMARTSTACK_VERSION}}
323
396
  Task: {task_description}
324
397
  Hierarchy: {app_name} → {module_code} → {sections[].code}
325
398
  Entities: {entities} | Complexity: {module_complexity} | Deps: {has_dependencies}
399
+ Entity Map: {entity_section_map.map(e => `${e.entity}→${e.navRoute}`).join(', ')}
326
400
  Code: {code_patterns summary} | PRD: {prd_path||none} | Feature: {feature_path||none}
327
401
  Flags: {active_flags} | MCP: {available|degraded} | Needs: {migration/seed/workflow/notification}
328
402
  Specs: {specification_loading_plan ? 'companion files available (layer-specific loading)' : 'none'}
@@ -45,7 +45,7 @@ Execute all layers (Layer 0 → Layer 1 → Layer 2 → Layer 3 → Layer 4).
45
45
  ```
46
46
  BEFORE starting Layer N:
47
47
  Verify these variables are still accessible:
48
- {app_name}, {module_code}, {sections}, {entities}, {code_patterns}
48
+ {app_name}, {module_code}, {sections}, {entities}, {code_patterns}, {entity_section_map}
49
49
  IF delegate_mode: also verify {delegate_prd_path}, {specification_loading_plan}
50
50
 
51
51
  IF any variable is missing or empty:
@@ -71,7 +71,12 @@ BEFORE starting Layer N:
71
71
  - {entities}: Glob("src/**/Domain/Entities/{module_code}/*.cs") → entity names
72
72
  - {sections}: Glob("src/**/Seeding/Data/{module_code}/*NavigationSeedData.cs") → parse
73
73
  - {code_patterns}: Read state.json or re-derive from DependencyInjection.cs
74
- 4. IF recovered: verify consistency with naming derivation rules (step-00 §4f)
74
+ - {entity_section_map}: IF state.json has it use directly. ELSE re-derive:
75
+ For each entity, check controllers for [NavRoute] value:
76
+ Grep("\[NavRoute\(\"", "src/**/Controllers/**/{Entity}*Controller.cs")
77
+ → extract navRoute segments → determine level (2 seg = module, 3 seg = section)
78
+ Fallback: re-apply step-00 §4g matching algorithm with {entities} and {sections}
79
+ 4. IF recovered: verify consistency with naming derivation rules (step-00 §4f, §4g)
75
80
  5. IF Layer N-1 already completed: skip to Layer N directly
76
81
 
77
82
  Cost: ~5-8 tool calls. Only triggered if context was compressed.
@@ -160,14 +165,21 @@ After each layer's build gate passes, write state to `.claude/output/apex/{task_
160
165
  "app_name": "HumanResources",
161
166
  "module_code": "employee-management",
162
167
  "sections": ["employees", "departments"],
163
- "entities": ["Employee", "Department"]
168
+ "entities": ["Employee", "Department"],
169
+ "entity_section_map": [
170
+ { "entity": "Employee", "level": "module", "navRoute": "human-resources.employee-management", "section_code": null },
171
+ { "entity": "Department", "level": "section", "navRoute": "human-resources.employee-management.departments", "section_code": "departments" }
172
+ ]
164
173
  }
165
174
  ```
166
175
 
167
- > **Fields `delegate_mode`, `delegate_prd_path`, `app_name`, `module_code`, `sections`, `entities`**
176
+ > **Fields `delegate_mode`, `delegate_prd_path`, `app_name`, `module_code`, `sections`, `entities`, `entity_section_map`**
168
177
  > are persisted so that Context Recovery Protocol (above) can restore the full execution context
169
178
  > after context compression or resume (`-r`). The `specification_loading_plan` is rebuilt from the
170
179
  > PRD file at `delegate_prd_path` — no need to serialize it directly.
180
+ > The `entity_section_map` is critical for Layers 2-3: it determines per-entity NavRoute and
181
+ > section-level permission generation. If lost, it can be re-derived from controller [NavRoute] attributes
182
+ > or by re-applying step-00 §4g matching algorithm.
171
183
 
172
184
  ---
173
185
 
@@ -100,6 +100,32 @@ IF existing_seed_files is NOT EMPTY:
100
100
 
101
101
  ---
102
102
 
103
+ ### Reserved Section Code Guard (MANDATORY — runs before ANY section seeding)
104
+
105
+ > **CRITICAL RULE:** Reserved section codes must NOT be seeded as menu-visible sections.
106
+
107
+ ```
108
+ RESERVED_SECTION_CODES = ["detail", "create", "edit"]
109
+
110
+ For each section in {sections} (from PRD or entity_section_map):
111
+ IF section.code IN RESERVED_SECTION_CODES OR section.code contains "-detail":
112
+ → Do NOT seed this section in NavigationSeedData at all
113
+ → "detail" is the /:id route of its parent list section (DynamicRouter convention)
114
+ → "create" is the /create route (DynamicRouter convention)
115
+ → "edit" is the /:id/edit route (DynamicRouter convention)
116
+ → "*-detail" (e.g., "department-detail") is the /:id route of its parent section
117
+ → Set permissionMode = "inherit" (no dedicated permissions)
118
+ → LOG: "Skipped reserved section '{section.code}' — resolved by DynamicRouter convention"
119
+
120
+ ELSE:
121
+ → Seed normally with IsActive = true
122
+
123
+ In delegate mode (-d): PRD data may contain reserved codes that were not challenged.
124
+ This guard catches them regardless of mode.
125
+ ```
126
+
127
+ ---
128
+
103
129
  ### Per-Module Seed Data (CREATE or UPDATE)
104
130
 
105
131
  #### If SEED_MODE = "CREATE"
@@ -113,19 +139,45 @@ Generate all files from scratch using `references/core-seed-data.md` templates:
113
139
  → If resources defined: GetResourceEntries() + resource translations
114
140
  → Query actual parent from DB for FK (NOT deterministic GUID)
115
141
 
116
- 4. Permissions.cs
142
+ 4. Permissions.cs — MODULE-LEVEL
117
143
  → MCP generate_permissions (PRIMARY tool)
118
144
  → Static constants: public static class {Module} { public const string Read = "..."; }
119
145
  → Permission paths MUST use kebab-case matching NavRoute codes
120
146
 
121
- 5. PermissionsSeedData.cs
147
+ 4b. Permissions.cs — SECTION-LEVEL (for each entity in {entity_section_map} where level == "section")
148
+ → Add nested class per section inside the module class:
149
+ public static class {SectionPascal} {
150
+ public const string View = "{navRoute}.{section_code}.read";
151
+ public const string Create = "{navRoute}.{section_code}.create";
152
+ ...
153
+ }
154
+ → Apply permissionMode inference (core-seed-data.md Step C2):
155
+ - section code == "detail" → inherit (SKIP — no section permissions)
156
+ - section code == "dashboard" → read-only (read permission only)
157
+ - section code == "list" or "kanban" or "calendar" or "weekly" → inherit (SKIP — view of module entity)
158
+ - otherwise → crud (wildcard + read + create + update + delete)
159
+ → Reference: core-seed-data.md lines 736-799 for full template
160
+
161
+ 5. PermissionsSeedData.cs — MODULE-LEVEL
122
162
  → MCP generate_permissions first, fallback template
123
163
  → Paths match Permissions.cs, wildcard + CRUD
124
164
 
125
- 6. RolesSeedData.cs
165
+ 5b. PermissionsSeedData.cs — SECTION-LEVEL (for each entity where level == "section" AND permissionMode != "inherit")
166
+ → Add CreateSectionPermissions(Guid {sectionCode}SectionId) method
167
+ → Section-level entries: wildcard + CRUD matching Permissions.cs nested class
168
+ → Reference: core-seed-data.md Step C2 lines 758-779 for template
169
+
170
+ 6. RolesSeedData.cs — MODULE-LEVEL
126
171
  → Admin=wildcard(*), Manager=CRU, Contributor=CR, Viewer=R
127
172
  → Code-based role mapping (not deterministic GUIDs for roles)
128
173
  → Look up roles by Code at runtime
174
+
175
+ 6b. RolesSeedData.cs — SECTION-LEVEL (for each entity where level == "section" AND permissionMode != "inherit")
176
+ → Add section-level mappings in GetRolePermissionMappings():
177
+ Admin: section wildcard ({navRoute}.{section_code}.*)
178
+ Manager: read + create + update for section
179
+ Contributor: read + create for section
180
+ Viewer: read for section
129
181
  ```
130
182
 
131
183
  #### If SEED_MODE = "UPDATE"
@@ -241,9 +293,16 @@ ELSE IF Program.cs ONLY calls `MigrateAsync()` without seed data execution:
241
293
  For each section in {sections} from step-00:
242
294
  ✓ NavigationModuleSeedData has section entry + translations (4 langs)
243
295
  ✓ NavigationModuleSeedData has route: /{app}/{module}/{section}
244
- ✓ Permissions.cs has constants for this section (Read/Create/Update/Delete/Wildcard)
245
- PermissionsSeedData has HasData() for each permission
246
- RolesSeedData maps all 4 roles to section permissions
296
+
297
+ For each entity in {entity_section_map} where level == "section" AND permissionMode != "inherit":
298
+ Permissions.cs has SECTION-LEVEL nested class {SectionPascal} with constants
299
+ ✓ PermissionsSeedData has CreateSectionPermissions(Guid {section}SectionId) method
300
+ ✓ RolesSeedData.GetRolePermissionMappings() includes section-level role mappings
301
+
302
+ Module-level (always):
303
+ ✓ Permissions.cs has MODULE-LEVEL constants (Read/Create/Update/Delete/Wildcard)
304
+ ✓ PermissionsSeedData has module-level HasData() for each permission
305
+ ✓ RolesSeedData maps all 4 roles to module permissions
247
306
  ✓ {App}SeedDataProvider references all seed data classes
248
307
  ✓ Program.cs executes seed data providers after MigrateAsync()
249
308
  ✓ DI registers: services.AddScoped<IClientSeedDataProvider, {App}SeedDataProvider>()