@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.
- package/.documentation/business-analyse.html +217 -0
- package/package.json +1 -1
- package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +29 -7
- package/templates/skills/apex/references/post-checks.md +42 -0
- package/templates/skills/apex/references/smartstack-frontend.md +23 -8
- package/templates/skills/apex/references/smartstack-layers.md +35 -19
- package/templates/skills/apex/steps/step-03-execute.md +10 -1
- package/templates/skills/apex/steps/step-04-examine.md +4 -0
- package/templates/skills/ba-generate-html/html/ba-interactive.html +207 -199
- package/templates/skills/ba-generate-html/html/src/partials/cadrage-context.html +9 -9
- package/templates/skills/ba-generate-html/html/src/partials/cadrage-scope.html +15 -15
- package/templates/skills/ba-generate-html/html/src/partials/cadrage-stakeholders.html +7 -7
- package/templates/skills/ba-generate-html/html/src/partials/cadrage-success.html +13 -13
- package/templates/skills/ba-generate-html/html/src/partials/consol-datamodel.html +4 -4
- package/templates/skills/ba-generate-html/html/src/partials/consol-flows.html +5 -5
- package/templates/skills/ba-generate-html/html/src/partials/consol-interactions.html +2 -2
- package/templates/skills/ba-generate-html/html/src/partials/consol-permissions.html +4 -4
- package/templates/skills/ba-generate-html/html/src/partials/decomp-dependencies.html +11 -11
- package/templates/skills/ba-generate-html/html/src/partials/decomp-modules.html +9 -9
- package/templates/skills/ba-generate-html/html/src/partials/handoff-summary.html +5 -5
- package/templates/skills/ba-generate-html/html/src/scripts/01-data-init.js +10 -2
- package/templates/skills/ba-generate-html/html/src/scripts/02-navigation.js +10 -10
- package/templates/skills/ba-generate-html/html/src/scripts/03-render-cadrage.js +1 -1
- package/templates/skills/ba-generate-html/html/src/scripts/04-render-modules.js +4 -4
- package/templates/skills/ba-generate-html/html/src/scripts/05-render-specs.js +57 -57
- package/templates/skills/ba-generate-html/html/src/scripts/06-render-consolidation.js +4 -4
- package/templates/skills/ba-generate-html/html/src/scripts/06-render-mockups.js +5 -5
- package/templates/skills/ba-generate-html/html/src/scripts/07-render-handoff.js +8 -8
- package/templates/skills/ba-generate-html/html/src/scripts/08-editing.js +3 -3
- package/templates/skills/ba-generate-html/html/src/scripts/09-export.js +2 -2
- package/templates/skills/ba-generate-html/html/src/scripts/10-comments.js +2 -2
- package/templates/skills/ba-generate-html/html/src/scripts/11-review-panel.js +8 -8
- package/templates/skills/ba-generate-html/html/src/styles/03-navigation.css +1 -1
- package/templates/skills/ba-generate-html/html/src/template.html +92 -92
- package/templates/skills/ba-generate-html/steps/step-02-build-data.md +5 -1
- package/templates/skills/business-analyse/questionnaire/01-context.md +12 -12
- package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +45 -45
- package/templates/skills/business-analyse/questionnaire/03-data-ui.md +39 -39
- package/templates/skills/business-analyse/questionnaire/05-cross-module.md +32 -32
- package/templates/skills/business-analyse/questionnaire.md +11 -11
- package/templates/skills/business-analyse/steps/step-00-init.md +2 -2
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +3 -3
- package/templates/skills/business-analyse/steps/step-02-structure.md +2 -2
- 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 <json-path></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;">⚠
|
|
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 <json-path></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 <json-path></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 > 100KB, sections, coherence)</span><span data-lang="en">Verification (size > 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;">⚠
|
|
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
|
@@ -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: <
|
|
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
|
|
187
|
+
**Example:** For NavRoutes `human-resources.employee-management.employees` and `human-resources.employee-management.absences`:
|
|
166
188
|
```tsx
|
|
167
|
-
{ path: '
|
|
168
|
-
{ path: '', element: <Navigate to="employees
|
|
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
|
|
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 —
|
|
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: `'
|
|
319
|
-
2. Create route (`'{section}/create'`)
|
|
320
|
-
3. Static sections (`'{
|
|
321
|
-
4. Dynamic routes (`'{section}/:id'`, `'{section}/:id/edit'`)
|
|
322
|
-
5.
|
|
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
|
|
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
|
-
//
|
|
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
|
-
|
|
348
|
-
{ path: '{section-kebab}
|
|
349
|
-
{ path: '{section-kebab}
|
|
350
|
-
{ path: '{section-kebab}/:id
|
|
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
|
|
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 |
|