@atlashub/smartstack-cli 4.28.0 → 4.30.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 (44) hide show
  1. package/.documentation/business-analyse.html +217 -0
  2. package/package.json +1 -1
  3. package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +29 -7
  4. package/templates/skills/apex/references/post-checks.md +42 -0
  5. package/templates/skills/apex/references/smartstack-frontend.md +23 -8
  6. package/templates/skills/apex/references/smartstack-layers.md +35 -19
  7. package/templates/skills/apex/steps/step-03-execute.md +10 -1
  8. package/templates/skills/apex/steps/step-04-examine.md +4 -0
  9. package/templates/skills/ba-generate-html/html/ba-interactive.html +207 -199
  10. package/templates/skills/ba-generate-html/html/src/partials/cadrage-context.html +9 -9
  11. package/templates/skills/ba-generate-html/html/src/partials/cadrage-scope.html +15 -15
  12. package/templates/skills/ba-generate-html/html/src/partials/cadrage-stakeholders.html +7 -7
  13. package/templates/skills/ba-generate-html/html/src/partials/cadrage-success.html +13 -13
  14. package/templates/skills/ba-generate-html/html/src/partials/consol-datamodel.html +4 -4
  15. package/templates/skills/ba-generate-html/html/src/partials/consol-flows.html +5 -5
  16. package/templates/skills/ba-generate-html/html/src/partials/consol-interactions.html +2 -2
  17. package/templates/skills/ba-generate-html/html/src/partials/consol-permissions.html +4 -4
  18. package/templates/skills/ba-generate-html/html/src/partials/decomp-dependencies.html +11 -11
  19. package/templates/skills/ba-generate-html/html/src/partials/decomp-modules.html +9 -9
  20. package/templates/skills/ba-generate-html/html/src/partials/handoff-summary.html +5 -5
  21. package/templates/skills/ba-generate-html/html/src/scripts/01-data-init.js +10 -2
  22. package/templates/skills/ba-generate-html/html/src/scripts/02-navigation.js +10 -10
  23. package/templates/skills/ba-generate-html/html/src/scripts/03-render-cadrage.js +1 -1
  24. package/templates/skills/ba-generate-html/html/src/scripts/04-render-modules.js +4 -4
  25. package/templates/skills/ba-generate-html/html/src/scripts/05-render-specs.js +57 -57
  26. package/templates/skills/ba-generate-html/html/src/scripts/06-render-consolidation.js +4 -4
  27. package/templates/skills/ba-generate-html/html/src/scripts/06-render-mockups.js +5 -5
  28. package/templates/skills/ba-generate-html/html/src/scripts/07-render-handoff.js +8 -8
  29. package/templates/skills/ba-generate-html/html/src/scripts/08-editing.js +3 -3
  30. package/templates/skills/ba-generate-html/html/src/scripts/09-export.js +2 -2
  31. package/templates/skills/ba-generate-html/html/src/scripts/10-comments.js +2 -2
  32. package/templates/skills/ba-generate-html/html/src/scripts/11-review-panel.js +8 -8
  33. package/templates/skills/ba-generate-html/html/src/styles/03-navigation.css +1 -1
  34. package/templates/skills/ba-generate-html/html/src/template.html +92 -92
  35. package/templates/skills/ba-generate-html/steps/step-02-build-data.md +5 -1
  36. package/templates/skills/business-analyse/questionnaire/01-context.md +12 -12
  37. package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +45 -45
  38. package/templates/skills/business-analyse/questionnaire/03-data-ui.md +39 -39
  39. package/templates/skills/business-analyse/questionnaire/05-cross-module.md +32 -32
  40. package/templates/skills/business-analyse/questionnaire.md +11 -11
  41. package/templates/skills/business-analyse/steps/step-00-init.md +2 -2
  42. package/templates/skills/business-analyse/steps/step-01-cadrage.md +3 -3
  43. package/templates/skills/business-analyse/steps/step-02-structure.md +2 -2
  44. package/templates/skills/business-analyse/steps/step-03-specify.md +15 -15
@@ -122,6 +122,11 @@
122
122
  <a href="#step-03" class="sidebar-toc-link">03. Specify (Per-Module)</a>
123
123
  <a href="#step-04" class="sidebar-toc-link">04. Consolidation</a>
124
124
  <a href="#step-05" class="sidebar-toc-link">05. Handoff</a>
125
+ <a href="#step-06" class="sidebar-toc-link">06. Extract</a>
126
+ <a href="#companion-skills" class="sidebar-toc-link">
127
+ <span data-lang="fr">Skills complementaires</span>
128
+ <span data-lang="en">Companion Skills</span>
129
+ </a>
125
130
  <a href="#schemas" class="sidebar-toc-link">Schemas</a>
126
131
  <a href="#agents" class="sidebar-toc-link">Agents</a>
127
132
  <a href="#ids-refs" class="sidebar-toc-link">
@@ -904,6 +909,31 @@ Exemple:
904
909
  At the handoff step, an interactive HTML document (<code>ba-interactive.html</code>) is deployed to the project directory. This document allows the client to review, edit and enrich the business analysis directly in their browser, without a server. Modifications can be re-imported via <code>/business-analyse -x &lt;json-path&gt;</code>.
905
910
  </p>
906
911
 
912
+ <div class="warning-block" style="background:rgba(255,170,0,0.1);border-left:4px solid #ffaa00;padding:1rem 1.2rem;border-radius:6px;margin:1rem 0;">
913
+ <strong style="color:#ffaa00;">&#9888;
914
+ <span data-lang="fr">Important : Source de verite</span>
915
+ <span data-lang="en">Important: Source of Truth</span>
916
+ </strong>
917
+ <p data-lang="fr" style="margin:0.5rem 0 0;">
918
+ Le HTML interactif est un <strong>livrable genere</strong>, pas une source de donnees. La source de verite est constituee par les fichiers JSON (<code>index.json</code>, <code>cadrage.json</code>, <code>entities.json</code>, etc.). Toute modification faite directement dans le HTML sera <strong>ecrasee</strong> a la prochaine regeneration via <code>/ba-generate-html</code>.
919
+ </p>
920
+ <p data-lang="en" style="margin:0.5rem 0 0;">
921
+ The interactive HTML is a <strong>generated deliverable</strong>, not a data source. The source of truth is the JSON files (<code>index.json</code>, <code>cadrage.json</code>, <code>entities.json</code>, etc.). Any modification made directly in the HTML will be <strong>overwritten</strong> on the next regeneration via <code>/ba-generate-html</code>.
922
+ </p>
923
+ <p data-lang="fr" style="margin:0.5rem 0 0;">
924
+ <strong>Pour conserver vos modifications :</strong><br>
925
+ 1. Exporter le JSON depuis le HTML (bouton d'export)<br>
926
+ 2. Re-importer avec <code>/business-analyse -x &lt;json-path&gt;</code> (met a jour les fichiers JSON sources)<br>
927
+ 3. Regenerer le HTML avec <code>/ba-generate-html</code>
928
+ </p>
929
+ <p data-lang="en" style="margin:0.5rem 0 0;">
930
+ <strong>To preserve your modifications:</strong><br>
931
+ 1. Export JSON from the HTML (export button)<br>
932
+ 2. Re-import with <code>/business-analyse -x &lt;json-path&gt;</code> (updates source JSON files)<br>
933
+ 3. Regenerate the HTML with <code>/ba-generate-html</code>
934
+ </p>
935
+ </div>
936
+
907
937
  <h4 data-lang="fr">Verification post-handoff</h4>
908
938
  <h4 data-lang="en">Post-Handoff Verification</h4>
909
939
 
@@ -952,6 +982,193 @@ Exemple:
952
982
  </div>
953
983
  </section>
954
984
 
985
+ <!-- ============================================ -->
986
+ <!-- COMPANION SKILLS -->
987
+ <!-- ============================================ -->
988
+ <section id="companion-skills">
989
+ <h2>
990
+ <span data-lang="fr">Skills complementaires</span>
991
+ <span data-lang="en">Companion Skills</span>
992
+ </h2>
993
+
994
+ <p data-lang="fr">
995
+ Deux skills independants completent le workflow de business analyse pour la gestion du document HTML interactif.
996
+ </p>
997
+ <p data-lang="en">
998
+ Two independent skills complement the business analysis workflow for managing the interactive HTML document.
999
+ </p>
1000
+
1001
+ <!-- /ba-generate-html -->
1002
+ <h3><code>/ba-generate-html</code></h3>
1003
+
1004
+ <p data-lang="fr">
1005
+ Genere (ou regenere) le document HTML interactif a partir des fichiers JSON d'analyse. Ce skill lit les sources JSON (<code>index.json</code>, <code>cadrage.json</code>, fichiers modules) et produit un fichier <code>ba-interactive.html</code> autonome.
1006
+ </p>
1007
+ <p data-lang="en">
1008
+ Generates (or regenerates) the interactive HTML document from the analysis JSON files. This skill reads the JSON sources (<code>index.json</code>, <code>cadrage.json</code>, module files) and produces a standalone <code>ba-interactive.html</code> file.
1009
+ </p>
1010
+
1011
+ <div class="code-block">
1012
+ <button class="copy-btn">Copy</button>
1013
+ <pre><code>/ba-generate-html FEAT-001
1014
+ /ba-generate-html FEAT-001 --force</code></pre>
1015
+ </div>
1016
+
1017
+ <div class="table-container">
1018
+ <table class="reference-table">
1019
+ <thead>
1020
+ <tr>
1021
+ <th>Flag</th>
1022
+ <th><span data-lang="fr">Effet</span><span data-lang="en">Effect</span></th>
1023
+ </tr>
1024
+ </thead>
1025
+ <tbody>
1026
+ <tr>
1027
+ <td><code>--force</code></td>
1028
+ <td><span data-lang="fr">Regenerer meme si le HTML existe deja</span><span data-lang="en">Regenerate even if HTML already exists</span></td>
1029
+ </tr>
1030
+ </tbody>
1031
+ </table>
1032
+ </div>
1033
+
1034
+ <h4><span data-lang="fr">Etapes internes</span><span data-lang="en">Internal Steps</span></h4>
1035
+ <div class="table-container">
1036
+ <table class="reference-table">
1037
+ <thead>
1038
+ <tr>
1039
+ <th>Step</th>
1040
+ <th><span data-lang="fr">Role</span><span data-lang="en">Role</span></th>
1041
+ </tr>
1042
+ </thead>
1043
+ <tbody>
1044
+ <tr>
1045
+ <td>01</td>
1046
+ <td><span data-lang="fr">Lire les sources JSON (index, cadrage, modules, consolidation)</span><span data-lang="en">Read JSON sources (index, cadrage, modules, consolidation)</span></td>
1047
+ </tr>
1048
+ <tr>
1049
+ <td>02</td>
1050
+ <td><span data-lang="fr">Construire FEATURE_DATA + EMBEDDED_ARTIFACTS</span><span data-lang="en">Build FEATURE_DATA + EMBEDDED_ARTIFACTS</span></td>
1051
+ </tr>
1052
+ <tr>
1053
+ <td>03</td>
1054
+ <td><span data-lang="fr">Injecter dans le template ba-interactive.html</span><span data-lang="en">Inject into ba-interactive.html template</span></td>
1055
+ </tr>
1056
+ <tr>
1057
+ <td>04</td>
1058
+ <td><span data-lang="fr">Verification (taille &gt; 100KB, sections, coherence)</span><span data-lang="en">Verification (size &gt; 100KB, sections, coherence)</span></td>
1059
+ </tr>
1060
+ </tbody>
1061
+ </table>
1062
+ </div>
1063
+
1064
+ <div class="warning-block" style="background:rgba(255,170,0,0.1);border-left:4px solid #ffaa00;padding:1rem 1.2rem;border-radius:6px;margin:1rem 0;">
1065
+ <strong style="color:#ffaa00;">&#9888;
1066
+ <span data-lang="fr">Regeneration = ecrasement</span>
1067
+ <span data-lang="en">Regeneration = overwrite</span>
1068
+ </strong>
1069
+ <p data-lang="fr" style="margin:0.5rem 0 0;">
1070
+ <code>/ba-generate-html</code> ecrase le HTML existant. Si vous avez fait des modifications dans le HTML interactif, exportez d'abord le JSON puis re-importez avec <code>/business-analyse -x</code> avant de regenerer.
1071
+ </p>
1072
+ <p data-lang="en" style="margin:0.5rem 0 0;">
1073
+ <code>/ba-generate-html</code> overwrites the existing HTML. If you made modifications in the interactive HTML, first export the JSON then re-import with <code>/business-analyse -x</code> before regenerating.
1074
+ </p>
1075
+ </div>
1076
+
1077
+ <!-- /ba-review -->
1078
+ <h3><code>/ba-review</code></h3>
1079
+
1080
+ <p data-lang="fr">
1081
+ Applique les corrections client exportees depuis le HTML interactif et regenere le document. Ce skill attend un fichier <code>ba-review.json</code> contenant les modifications structurees.
1082
+ </p>
1083
+ <p data-lang="en">
1084
+ Applies client corrections exported from the interactive HTML and regenerates the document. This skill expects a <code>ba-review.json</code> file containing structured modifications.
1085
+ </p>
1086
+
1087
+ <div class="code-block">
1088
+ <button class="copy-btn">Copy</button>
1089
+ <pre><code>/ba-review</code></pre>
1090
+ </div>
1091
+
1092
+ <h4><span data-lang="fr">Workflow</span><span data-lang="en">Workflow</span></h4>
1093
+ <ol>
1094
+ <li data-lang="fr">Lire <code>ba-review.json</code> (exporte depuis le HTML interactif)</li>
1095
+ <li data-lang="en">Read <code>ba-review.json</code> (exported from interactive HTML)</li>
1096
+ <li data-lang="fr">Lire le master <code>index.json</code> existant</li>
1097
+ <li data-lang="en">Read the existing master <code>index.json</code></li>
1098
+ <li data-lang="fr">Creer une nouvelle version</li>
1099
+ <li data-lang="en">Create a new version</li>
1100
+ <li data-lang="fr">Appliquer les corrections (cadrage, modules, consolidation)</li>
1101
+ <li data-lang="en">Apply corrections (cadrage, modules, consolidation)</li>
1102
+ <li data-lang="fr">Regenerer le HTML via <code>/ba-generate-html</code></li>
1103
+ <li data-lang="en">Regenerate HTML via <code>/ba-generate-html</code></li>
1104
+ </ol>
1105
+
1106
+ <h4><span data-lang="fr">Routage des corrections</span><span data-lang="en">Correction Routing</span></h4>
1107
+ <div class="table-container">
1108
+ <table class="reference-table">
1109
+ <thead>
1110
+ <tr>
1111
+ <th><span data-lang="fr">Type de modification</span><span data-lang="en">Modification Type</span></th>
1112
+ <th><span data-lang="fr">Action declenchee</span><span data-lang="en">Triggered Action</span></th>
1113
+ </tr>
1114
+ </thead>
1115
+ <tbody>
1116
+ <tr>
1117
+ <td><span data-lang="fr">Entites / regles / UC / permissions</span><span data-lang="en">Entities / rules / UC / permissions</span></td>
1118
+ <td><span data-lang="fr">Re-execution <code>/business-analyse</code> step-03</span><span data-lang="en">Re-run <code>/business-analyse</code> step-03</span></td>
1119
+ </tr>
1120
+ <tr>
1121
+ <td><span data-lang="fr">Ecrans / wireframes / navigation</span><span data-lang="en">Screens / wireframes / navigation</span></td>
1122
+ <td><span data-lang="fr">Re-execution <code>/ba-design-ui</code></span><span data-lang="en">Re-run <code>/ba-design-ui</code></span></td>
1123
+ </tr>
1124
+ <tr>
1125
+ <td><span data-lang="fr">Les deux</span><span data-lang="en">Both</span></td>
1126
+ <td><span data-lang="fr">Re-specification complete</span><span data-lang="en">Full re-specification</span></td>
1127
+ </tr>
1128
+ <tr>
1129
+ <td><span data-lang="fr">Cadrage uniquement</span><span data-lang="en">Cadrage only</span></td>
1130
+ <td><span data-lang="fr">Regeneration HTML uniquement</span><span data-lang="en">HTML regeneration only</span></td>
1131
+ </tr>
1132
+ <tr>
1133
+ <td><span data-lang="fr">Client approuve</span><span data-lang="en">Client approves</span></td>
1134
+ <td><code>/derive-prd</code></td>
1135
+ </tr>
1136
+ </tbody>
1137
+ </table>
1138
+ </div>
1139
+
1140
+ <!-- Workflow recap -->
1141
+ <h3><span data-lang="fr">Cycle de vie complet</span><span data-lang="en">Complete Lifecycle</span></h3>
1142
+
1143
+ <div class="code-block">
1144
+ <pre><code><span data-lang="fr"># 1. Analyse initiale (genere les JSON + HTML)
1145
+ /business-analyse My Application Description
1146
+
1147
+ # 2. Client consulte le HTML, fait des modifications, exporte le JSON
1148
+
1149
+ # 3a. Re-import des modifications client dans les JSON sources
1150
+ /business-analyse -x ./docs/business/MyApp/ba-export.json
1151
+
1152
+ # 3b. OU appliquer des corrections structurees
1153
+ /ba-review
1154
+
1155
+ # 4. Regenerer le HTML apres modifications des JSON
1156
+ /ba-generate-html FEAT-001</span><span data-lang="en"># 1. Initial analysis (generates JSON + HTML)
1157
+ /business-analyse My Application Description
1158
+
1159
+ # 2. Client reviews the HTML, makes modifications, exports JSON
1160
+
1161
+ # 3a. Re-import client modifications into source JSONs
1162
+ /business-analyse -x ./docs/business/MyApp/ba-export.json
1163
+
1164
+ # 3b. OR apply structured corrections
1165
+ /ba-review
1166
+
1167
+ # 4. Regenerate HTML after JSON modifications
1168
+ /ba-generate-html FEAT-001</span></code></pre>
1169
+ </div>
1170
+ </section>
1171
+
955
1172
  <!-- ============================================ -->
956
1173
  <!-- SCHEMAS -->
957
1174
  <!-- ============================================ -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlashub/smartstack-cli",
3
- "version": "4.28.0",
3
+ "version": "4.30.0",
4
4
  "description": "SmartStack Claude Code automation toolkit - GitFlow, EF Core migrations, prompts and more",
5
5
  "author": {
6
6
  "name": "SmartStack",
@@ -56,20 +56,42 @@ Read App.tsx and detect which pattern is used:
56
56
 
57
57
  → Add routes to `applicationRoutes.{application}[]` with **RELATIVE** paths (no leading `/`)
58
58
 
59
+ > **CRITICAL — Include Module Segment:** Paths are relative to `/{application}/`.
60
+ > For a 3-level hierarchy (app → module → sections), paths MUST be `{module_kebab}/{section_kebab}`.
61
+ > Using just `{section_kebab}` omits the module segment → route resolves to `/{app}/{section}` instead
62
+ > of `/{app}/{module}/{section}` → mismatch with backend navigation seed data → 404.
63
+
59
64
  ```tsx
60
65
  const applicationRoutes: ApplicationRouteExtensions = {
61
66
  'human-resources': [
62
67
  // existing routes...
68
+ // Paths include module segment: employee-management/employees (NOT just employees)
63
69
  { path: '{module_kebab}/{section_kebab}', element: <{EntityName}ListPage /> },
64
70
  { path: '{module_kebab}/{section_kebab}/create', element: <Create{EntityName}Page /> },
65
71
  { path: '{module_kebab}/{section_kebab}/:id', element: <{EntityName}DetailPage /> },
66
- { path: '{module_kebab}/{section_kebab}/:id/edit', element: <Create{EntityName}Page /> },
72
+ { path: '{module_kebab}/{section_kebab}/:id/edit', element: <Edit{EntityName}Page /> },
67
73
 
68
74
  // Parent redirect routes (MANDATORY — prevents /login redirect on parent navigation)
69
75
  { path: '{module_kebab}', element: <Navigate to="{module_kebab}/{first_section_kebab}" replace /> },
70
76
  { path: '', element: <Navigate to="{first_module_kebab}/{first_section_kebab}" replace /> },
71
77
  ],
72
78
  };
79
+
80
+ // Concrete example: app=human-resources, module=employee-management, sections=employees,absences
81
+ const applicationRoutes: ApplicationRouteExtensions = {
82
+ 'human-resources': [
83
+ { path: 'employee-management/employees', element: <EmployeesPage /> }, // ✅
84
+ { path: 'employee-management/employees/create', element: <CreateEmployeePage /> }, // ✅
85
+ { path: 'employee-management/employees/:id', element: <EmployeeDetailPage /> }, // ✅
86
+ // ...absences...
87
+ { path: 'employee-management', element: <Navigate to="employee-management/employees" replace /> },
88
+ { path: '', element: <Navigate to="employee-management/employees" replace /> },
89
+ ],
90
+ };
91
+
92
+ // ❌ WRONG — missing module segment:
93
+ // { path: 'employees', ... } → resolves to /human-resources/employees (backend expects /human-resources/employee-management/employees)
94
+ ```
73
95
  ```
74
96
 
75
97
  Routes are automatically injected into BOTH standard (`/{application}/...`) and tenant-prefixed (`/t/:slug/{application}/...`) route trees by `mergeRoutes()`. No manual duplication needed.
@@ -162,10 +184,10 @@ For each application, add:
162
184
  { path: '{module}', element: <Navigate to="{module}/{first_section}" replace /> }
163
185
  ```
164
186
 
165
- **Example:** For NavRoutes `human-resources.employees.management` and `human-resources.employees.departments`:
187
+ **Example:** For NavRoutes `human-resources.employee-management.employees` and `human-resources.employee-management.absences`:
166
188
  ```tsx
167
- { path: 'employees', element: <Navigate to="employees/management" replace /> },
168
- { path: '', element: <Navigate to="employees/management" replace /> },
189
+ { path: 'employee-management', element: <Navigate to="employee-management/employees" replace /> },
190
+ { path: '', element: <Navigate to="employee-management/employees" replace /> },
169
191
  ```
170
192
 
171
193
  The `to` prop is resolved relative to the **parent route** (`/{application}`), so always use the full path from the application root.
@@ -186,12 +208,12 @@ The `to` prop is resolved relative to the **parent route** (`/{application}`), s
186
208
  { path: '/human-resources/employees/management', element: <EmployeePage /> },
187
209
  ];
188
210
  ```
189
- Custom application routes go in `applicationRoutes` with RELATIVE paths:
211
+ Custom application routes go in `applicationRoutes` with RELATIVE paths (including module segment):
190
212
  ```tsx
191
- // ✅ CORRECT
213
+ // ✅ CORRECT — module segment included
192
214
  const applicationRoutes: ApplicationRouteExtensions = {
193
215
  'human-resources': [
194
- { path: 'employees/management', element: <EmployeePage /> },
216
+ { path: 'employee-management/employees', element: <EmployeesPage /> },
195
217
  ],
196
218
  };
197
219
  ```
@@ -1884,6 +1884,48 @@ if [ -n "$CTRL_FILES" ]; then
1884
1884
  fi
1885
1885
  ```
1886
1886
 
1887
+ ### POST-CHECK C52: Frontend route paths must include module segment (BLOCKING)
1888
+
1889
+ > **Source:** APEX regression — frontend routes used `employees` instead of `employee-management/employees`,
1890
+ > causing mismatch with backend navigation seed data routes (`/human-resources/employee-management/employees`).
1891
+ > Nav links produced 404 because React Router had no matching route for the full path.
1892
+
1893
+ ```bash
1894
+ # Compare frontend route paths in App.tsx against backend navigation seed data routes
1895
+ APP_TSX=$(find . -path "*/src/App.tsx" -not -path "*/node_modules/*" 2>/dev/null | head -1)
1896
+ if [ -n "$APP_TSX" ]; then
1897
+ # Extract all route paths from applicationRoutes
1898
+ ROUTE_PATHS=$(grep -oP "path:\s*'[^']+'" "$APP_TSX" | grep -v "^path: ''" | grep -v ":id" | grep -v "create" | grep -v "edit" | sed "s/path: '//;s/'//")
1899
+
1900
+ # Find navigation seed data files to get backend routes
1901
+ NAV_SEED_FILES=$(find src/ -name "*NavigationSeedData.cs" -o -name "*NavigationModuleSeedData.cs" 2>/dev/null)
1902
+ if [ -n "$NAV_SEED_FILES" ]; then
1903
+ # Extract module codes from seed data
1904
+ MODULE_CODES=$(grep -oP 'Code\s*=\s*"\K[^"]+' $NAV_SEED_FILES 2>/dev/null | sort -u)
1905
+
1906
+ for route in $ROUTE_PATHS; do
1907
+ # Skip redirect paths (empty or just module)
1908
+ if [ -z "$route" ]; then continue; fi
1909
+
1910
+ # Check if route contains a slash (module/section pattern)
1911
+ if ! echo "$route" | grep -q "/"; then
1912
+ # Single segment route — check if it matches a section code (not a module code)
1913
+ IS_MODULE=false
1914
+ for mod in $MODULE_CODES; do
1915
+ if [ "$route" = "$mod" ]; then IS_MODULE=true; break; fi
1916
+ done
1917
+ if [ "$IS_MODULE" = false ]; then
1918
+ echo "BLOCKING: Frontend route '$route' is missing module segment"
1919
+ echo " Expected: '{module}/{route}' (e.g., 'employee-management/$route')"
1920
+ echo " Backend navigation seed data defines routes with full hierarchy: /app/module/section"
1921
+ echo " Frontend routes must match: module/section (relative to app root)"
1922
+ fi
1923
+ fi
1924
+ done
1925
+ fi
1926
+ fi
1927
+ ```
1928
+
1887
1929
  ---
1888
1930
 
1889
1931
  ## Architecture — Clean Architecture Layer Isolation
@@ -14,8 +14,9 @@
14
14
 
15
15
  ```tsx
16
16
  // Named exports — use .then() to wrap
17
+ // Path: @/pages/{App}/{Module}/{Section}/{Page}
17
18
  const EmployeesPage = lazy(() =>
18
- import('@/pages/HumanResources/Employees/EmployeesPage')
19
+ import('@/pages/HumanResources/EmployeeManagement/Employees/EmployeesPage')
19
20
  .then(m => ({ default: m.EmployeesPage }))
20
21
  );
21
22
 
@@ -49,7 +50,7 @@ element: (
49
50
  **Incorrect patterns:**
50
51
  ```tsx
51
52
  // WRONG: static import in route file
52
- import { EmployeesPage } from '@/pages/HumanResources/Employees/EmployeesPage';
53
+ import { EmployeesPage } from '@/pages/HumanResources/EmployeeManagement/Employees/EmployeesPage';
53
54
 
54
55
  // WRONG: no Suspense wrapper
55
56
  element: <EmployeesPage />
@@ -64,8 +65,9 @@ In the client `App.tsx` (where application routes are defined), all page imports
64
65
 
65
66
  **Correct — Lazy imports in client App.tsx:**
66
67
  ```tsx
68
+ // Path includes module level: {App}/{Module}/{Section}/{Page}
67
69
  const ClientsListPage = lazy(() =>
68
- import('@/pages/HumanResources/Clients/ClientsListPage')
70
+ import('@/pages/HumanResources/ClientManagement/Clients/ClientsListPage')
69
71
  .then(m => ({ default: m.ClientsListPage }))
70
72
  );
71
73
  ```
@@ -73,7 +75,7 @@ const ClientsListPage = lazy(() =>
73
75
  **Do not use — Static imports in client App.tsx:**
74
76
  ```tsx
75
77
  // WRONG: Static import kills code splitting
76
- import { ClientsListPage } from '@/pages/HumanResources/Clients/ClientsListPage';
78
+ import { ClientsListPage } from '@/pages/HumanResources/ClientManagement/Clients/ClientsListPage';
77
79
  ```
78
80
 
79
81
  > **Note:** The `smartstackRoutes.tsx` from the npm package may use static imports internally — this is acceptable for the package. But client `App.tsx` code MUST always use lazy imports for business pages.
@@ -698,18 +700,19 @@ export function EntityEditPage() {
698
700
 
699
701
  ```tsx
700
702
  // In route files — form pages are also lazy-loaded
703
+ // Path: @/pages/{App}/{Module}/{Section}/{Page}
701
704
  const EntityCreatePage = lazy(() =>
702
- import('@/pages/HumanResources/Employees/EntityCreatePage')
705
+ import('@/pages/HumanResources/EmployeeManagement/Employees/EntityCreatePage')
703
706
  .then(m => ({ default: m.EntityCreatePage }))
704
707
  );
705
708
  const EntityEditPage = lazy(() =>
706
- import('@/pages/HumanResources/Employees/EntityEditPage')
709
+ import('@/pages/HumanResources/EmployeeManagement/Employees/EntityEditPage')
707
710
  .then(m => ({ default: m.EntityEditPage }))
708
711
  );
709
712
 
710
- // Route registration — form pages have their own routes
713
+ // Route registration — Pattern B (JSX nested children):
711
714
  {
712
- path: 'employees',
715
+ path: 'employee-management/employees',
713
716
  children: [
714
717
  { index: true, element: <Suspense fallback={<PageLoader />}><EmployeesPage /></Suspense> },
715
718
  { path: 'create', element: <Suspense fallback={<PageLoader />}><EntityCreatePage /></Suspense> },
@@ -718,6 +721,18 @@ const EntityEditPage = lazy(() =>
718
721
  ]
719
722
  }
720
723
 
724
+ // Route registration — Pattern A (applicationRoutes flat paths):
725
+ // CRITICAL: paths are RELATIVE to /{app}/ and MUST include the module segment
726
+ const applicationRoutes: ApplicationRouteExtensions = {
727
+ 'human-resources': [
728
+ { path: 'employee-management/employees', element: <EmployeesPage /> }, // ✅ includes module
729
+ { path: 'employee-management/employees/create', element: <CreateEmployeePage /> }, // ✅
730
+ { path: 'employee-management/employees/:id', element: <EmployeeDetailPage /> }, // ✅
731
+ { path: 'employee-management/employees/:id/edit', element: <EditEmployeePage /> }, // ✅
732
+ // ❌ WRONG: { path: 'employees', ... } — missing module segment → 404 on nav click
733
+ ],
734
+ };
735
+
721
736
  // Section-level routes — children of the module route (when module has sections)
722
737
  //
723
738
  // > **IMPORTANT:** The `list` and `detail` sections do NOT generate additional route entries.
@@ -315,39 +315,55 @@ const [loading, setLoading] = useState(true);
315
315
 
316
316
  **Order (MANDATORY):**
317
317
 
318
- 1. Index/list route (path: `''` or `'{section}'`)
319
- 2. Create route (`'{section}/create'`)
320
- 3. Static sections (`'{section}/dashboard'`, `'{section}/departments'`, etc.)
321
- 4. Dynamic routes (`'{section}/:id'`, `'{section}/:id/edit'`)
322
- 5. Redirect routes (`Navigate`) ALWAYS LAST
318
+ 1. Index/list route (path: `'{module}/{section}'`)
319
+ 2. Create route (`'{module}/{section}/create'`)
320
+ 3. Static sections (`'{module}/{section}/dashboard'`, etc.)
321
+ 4. Dynamic routes (`'{module}/{section}/:id'`, `'{module}/{section}/:id/edit'`)
322
+ 5. Module redirect (`'{module}'` `'{module}/{first_section}'`)
323
+ 6. Application redirect (`''` → `'{first_module}/{first_section}'`) — ALWAYS LAST
323
324
 
324
325
  ```tsx
325
- // ✅ CORRECT — static before dynamic
326
+ // ✅ CORRECT — module segment included, static before dynamic
327
+ // (inside applicationRoutes['human-resources'], paths are relative to /human-resources/)
328
+ { path: 'employee-management/employees', element: <EmployeesPage /> },
329
+ { path: 'employee-management/employees/create', element: <CreateEmployeePage /> },
330
+ { path: 'employee-management/employees/dashboard', element: <EmployeeDashboardPage /> },
331
+ { path: 'employee-management/employees/:id', element: <EmployeeDetailPage /> },
332
+ { path: 'employee-management/employees/:id/edit', element: <EditEmployeePage /> },
333
+ { path: 'employee-management', element: <Navigate to="employee-management/employees" replace /> },
334
+ { path: '', element: <Navigate to="employee-management/employees" replace /> },
335
+
336
+ // ❌ WRONG — missing module segment (resolves to /human-resources/employees instead of /human-resources/employee-management/employees)
326
337
  { path: 'employees', element: <EmployeesPage /> },
327
- { path: 'employees/create', element: <CreateEmployeePage /> },
328
- { path: 'employees/dashboard', element: <EmployeeDashboardPage /> },
329
- { path: 'employees/:id', element: <EmployeeDetailPage /> },
330
- { path: 'employees/:id/edit', element: <EditEmployeePage /> },
331
- { path: '', element: <Navigate to="employees" replace /> },
332
338
 
333
339
  // ❌ WRONG — :id before dashboard → dashboard is unreachable (matched as id="dashboard")
334
- { path: 'employees/:id', element: <EmployeeDetailPage /> },
335
- { path: 'employees/dashboard', element: <EmployeeDashboardPage /> }, // NEVER REACHED
340
+ { path: 'employee-management/employees/:id', element: <EmployeeDetailPage /> },
341
+ { path: 'employee-management/employees/dashboard', element: <EmployeeDashboardPage /> }, // NEVER REACHED
336
342
  ```
337
343
 
338
344
  POST-CHECK C49 detects this anti-pattern and BLOCKS.
339
345
 
340
346
  ### Section Routes (when module has sections)
341
347
 
342
- If the module defines `{sections}`, generate frontend routes for EACH section as children of the module route:
348
+ If the module defines `{sections}`, generate frontend routes for EACH section as children of the application route.
349
+
350
+ > **CRITICAL — Module Segment Required:** Route paths in `applicationRoutes['{app}']` are RELATIVE to the application root.
351
+ > They MUST include the module segment: `{module-kebab}/{section-kebab}`, NOT just `{section-kebab}`.
352
+ > Without the module segment, the route resolves to `/{app}/{section}` instead of `/{app}/{module}/{section}`,
353
+ > causing a mismatch with backend navigation seed data routes → nav links produce 404s.
343
354
 
344
355
  ```tsx
345
- // Section routes are nested inside the module's children array
356
+ // Routes in applicationRoutes['human-resources'] RELATIVE paths include module segment
346
357
  // IMPORTANT: static routes BEFORE dynamic routes (see Route Ordering rule above)
347
- { path: '{section-kebab}', element: <Suspense fallback={<PageLoader />}><{Section}Page /></Suspense> },
348
- { path: '{section-kebab}/create', element: <Suspense fallback={<PageLoader />}><Create{Section}Page /></Suspense> },
349
- { path: '{section-kebab}/:id', element: <Suspense fallback={<PageLoader />}><{Section}DetailPage /></Suspense> },
350
- { path: '{section-kebab}/:id/edit', element: <Suspense fallback={<PageLoader />}><Edit{Section}Page /></Suspense> },
358
+ // Example: app=human-resources, module=employee-management, section=employees
359
+ { path: '{module-kebab}/{section-kebab}', element: <Suspense fallback={<PageLoader />}><{Section}Page /></Suspense> },
360
+ { path: '{module-kebab}/{section-kebab}/create', element: <Suspense fallback={<PageLoader />}><Create{Section}Page /></Suspense> },
361
+ { path: '{module-kebab}/{section-kebab}/:id', element: <Suspense fallback={<PageLoader />}><{Section}DetailPage /></Suspense> },
362
+ { path: '{module-kebab}/{section-kebab}/:id/edit', element: <Suspense fallback={<PageLoader />}><Edit{Section}Page /></Suspense> },
363
+
364
+ // Concrete example:
365
+ // { path: 'employee-management/employees', element: ... }, → /human-resources/employee-management/employees ✅
366
+ // { path: 'employees', element: ... }, → /human-resources/employees ❌ WRONG (missing module)
351
367
  ```
352
368
 
353
369
  Section pages live in `src/pages/{AppPascal}/{Module}/{Section}/`.
@@ -427,6 +427,11 @@ For each module:
427
427
  → Read App.tsx and detect the routing pattern
428
428
  → Pattern A (`applicationRoutes: ApplicationRouteExtensions`): add routes to `applicationRoutes['{application_kebab}'][]` with RELATIVE paths
429
429
  → Pattern B (JSX `<Route>`): nest routes inside `<Route path="/{application}" element={<AppLayout />}>` + duplicate in tenant block
430
+ → **CRITICAL — Module Segment Required:** Route paths MUST include the module segment.
431
+ For a 3-level hierarchy (app → module → sections), paths are `{module_kebab}/{section_kebab}`.
432
+ Example: `employee-management/employees` NOT just `employees`.
433
+ Without the module segment, routes resolve to `/{app}/{section}` instead of `/{app}/{module}/{section}`,
434
+ causing mismatch with backend navigation seed data → nav links produce 404s.
430
435
  → **BEFORE wiring:** Verify route ordering — static routes (`create`, `dashboard`, `departments`) MUST come BEFORE dynamic routes (`:id`, `:id/edit`). Redirect routes (`Navigate`) MUST be LAST. See `references/smartstack-layers.md` "RULE — Frontend Route Ordering".
431
436
  → Do not add business routes to `clientRoutes[]` — it is only for non-app routes (`/about`, `/pricing`)
432
437
  → All business applications use `<AppLayout />` as layout wrapper
@@ -482,7 +487,9 @@ For each module:
482
487
  5. Verify: `grep -q "{module_namespace}" src/**/i18n/config.ts` → must match
483
488
  - Permissions: Call MCP generate_permissions for the module permission root (2 segments: {app}.{module}),
484
489
  then also call MCP generate_permissions for each section (3 segments: {app}.{module}.{section}).
485
- - Section routes: Add section child routes to the module's children array.
490
+ - Section routes: Add section child routes to `applicationRoutes['{app_kebab}']`.
491
+ Route paths MUST include the module segment: `{module_kebab}/{section_kebab}` (e.g., `employee-management/employees`).
492
+ Do NOT use just `{section_kebab}` (e.g., `employees`) — this omits the module level and causes 404s.
486
493
  Wire PermissionGuard for section routes with section-level permissions.
487
494
  - MUST use src/pages/{App}/{Module}/ hierarchy (NOT flat)
488
495
 
@@ -519,6 +526,7 @@ IF NOT economy_mode AND entities.length > 1:
519
526
  - API client: MCP scaffold_api_client
520
527
  - Routes: MCP scaffold_routes (outputFormat: "applicationRoutes", dryRun: false) → MUST generate navRoutes.generated.ts
521
528
  - Wire Routes to App.tsx (BLOCKING): detect Pattern A/B, wire accordingly
529
+ → CRITICAL: Route paths MUST include module segment: {module_kebab}/{section_kebab} (e.g., employee-management/employees, NOT just employees)
522
530
  → See references/frontend-route-wiring-app-tsx.md for full patterns
523
531
  → Verify: mcp__smartstack__validate_frontend_routes (scope: "routes")
524
532
  - Pages: /ui-components skill (ALL 4 types: List, Detail, Create, Edit)
@@ -539,6 +547,7 @@ ELSE:
539
547
  1. MCP scaffold_api_client
540
548
  2. MCP scaffold_routes (outputFormat: 'applicationRoutes')
541
549
  3. Wire routes to App.tsx (Pattern A/B — see references/frontend-route-wiring-app-tsx.md)
550
+ CRITICAL: paths MUST include module segment: {module_kebab}/{section_kebab} (e.g., employee-management/employees)
542
551
  4. **INVOKE Skill("ui-components")** — pass entity context:
543
552
  - Entity: {EntityName}, Module: {ModuleName}, App: {AppName}
544
553
  - Page types: List, Detail, Create, Edit (+ Dashboard if applicable)
@@ -65,6 +65,9 @@ Verify:
65
65
  - Routes nested inside correct Layout wrapper
66
66
  - Route paths match controller patterns
67
67
  - No orphan routes
68
+ - Route paths include module segment (e.g., 'employee-management/employees', NOT just 'employees')
69
+ → Compare frontend route paths in App.tsx against backend NavigationSeedData routes
70
+ → If backend defines route /app/module/section, frontend must use module/section (relative)
68
71
  ```
69
72
 
70
73
  ### 3b. Frontend Page Completeness
@@ -196,6 +199,7 @@ AC2: {criterion} → PASS / FAIL (evidence: {file:line or test})
196
199
  | I18n registration | Namespaces registered in i18n config (POST-CHECK C39) | PASS / N/A |
197
200
  | Validators DI | FluentValidation registered in DI (POST-CHECK C40) | PASS / N/A |
198
201
  | Route/NavRoute conflict | No [Route] alongside [NavRoute] on controllers (POST-CHECK C43) | PASS / N/A |
202
+ | Route module segment | Frontend routes include module segment matching seed data (POST-CHECK C52) | PASS / N/A |
199
203
  | Role-permission matrix | Admin=wildcard, Manager=CRU, Contributor=CR, Viewer=R (POST-CHECK C44) | PASS / N/A |
200
204
  | PermissionAction enum | No Enum.Parse, only typed enum values 0-10 (POST-CHECK C45) | PASS / N/A |
201
205
  | Navigation translations | 4 langs per level, section/resource translations present (POST-CHECK C46) | PASS / N/A |