@atlashub/smartstack-cli 3.37.0 → 3.39.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/dist/index.js +16 -24
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +235 -265
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/scripts/extract-api-endpoints.ts +5 -5
- package/scripts/generate-doc-with-mock-ui.ts +10 -17
- package/templates/agents/ba-reader.md +9 -9
- package/templates/agents/ba-writer.md +12 -15
- package/templates/agents/code-reviewer.md +1 -1
- package/templates/agents/docs-context-reader.md +1 -1
- package/templates/agents/efcore/scan.md +3 -1
- package/templates/agents/gitflow/commit.md +74 -0
- package/templates/agents/gitflow/finish.md +5 -2
- package/templates/agents/gitflow/init-clone.md +3 -3
- package/templates/agents/gitflow/init-validate.md +3 -2
- package/templates/agents/gitflow/merge.md +5 -4
- package/templates/agents/gitflow/pr.md +5 -4
- package/templates/agents/gitflow/start.md +37 -5
- package/templates/hooks/hooks.json +11 -0
- package/templates/hooks/wsl-dotnet-cleanup.sh +24 -0
- package/templates/mcp-scaffolding/frontend/nav-routes.ts.hbs +20 -20
- package/templates/mcp-scaffolding/frontend/routes.tsx.hbs +16 -24
- package/templates/mcp-scaffolding/migrations/seed-roles.cs.hbs +2 -2
- package/templates/skills/_resources/mcp-validate-documentation-spec.md +3 -3
- package/templates/skills/_shared.md +15 -17
- package/templates/skills/ai-prompt/SKILL.md +1 -1
- package/templates/skills/ai-prompt/steps/step-00-init.md +47 -0
- package/templates/skills/apex/SKILL.md +3 -4
- package/templates/skills/apex/_shared.md +10 -20
- package/templates/skills/apex/references/analysis-methods.md +141 -0
- package/templates/skills/apex/references/challenge-questions.md +1 -21
- package/templates/skills/apex/references/core-seed-data.md +35 -58
- package/templates/skills/apex/references/examine-build-validation.md +82 -0
- package/templates/skills/apex/references/execution-frontend-gates.md +177 -0
- package/templates/skills/apex/references/execution-frontend-patterns.md +105 -0
- package/templates/skills/apex/references/execution-layer1-rules.md +96 -0
- package/templates/skills/apex/references/initialization-challenge-flow.md +110 -0
- package/templates/skills/apex/references/planning-layer-mapping.md +151 -0
- package/templates/skills/apex/references/post-checks.md +145 -40
- package/templates/skills/apex/references/smartstack-api.md +35 -51
- package/templates/skills/apex/references/smartstack-frontend.md +18 -18
- package/templates/skills/apex/references/smartstack-layers.md +38 -62
- package/templates/skills/apex/steps/step-00-init.md +14 -26
- package/templates/skills/apex/steps/step-01-analyze.md +10 -143
- package/templates/skills/apex/steps/step-02-plan.md +10 -92
- package/templates/skills/apex/steps/step-03-execute.md +45 -252
- package/templates/skills/apex/steps/step-04-examine.md +14 -78
- package/templates/skills/apex/steps/step-05-deep-review.md +2 -2
- package/templates/skills/apex/steps/step-08-run-tests.md +1 -0
- package/templates/skills/application/SKILL.md +241 -242
- package/templates/skills/application/references/backend-controller-hierarchy.md +16 -16
- package/templates/skills/application/references/backend-seeding-and-dto-output.md +83 -0
- package/templates/skills/application/references/backend-table-prefix-mapping.md +79 -0
- package/templates/skills/application/references/backend-verification.md +1 -1
- package/templates/skills/application/references/frontend-i18n-and-output.md +67 -0
- package/templates/skills/application/references/frontend-route-naming.md +117 -0
- package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +107 -0
- package/templates/skills/application/references/frontend-verification.md +12 -12
- package/templates/skills/application/references/init-parameter-detection.md +121 -0
- package/templates/skills/application/references/migration-checklist-troubleshooting.md +100 -0
- package/templates/skills/application/references/nav-fallback-procedure.md +199 -200
- package/templates/skills/application/references/provider-template.md +2 -6
- package/templates/skills/application/references/roles-client-project-handling.md +55 -0
- package/templates/skills/application/references/roles-fallback-procedure.md +149 -0
- package/templates/skills/application/references/test-coverage-requirements.md +213 -0
- package/templates/skills/application/references/test-frontend.md +3 -3
- package/templates/skills/application/steps/step-00-init.md +130 -260
- package/templates/skills/application/steps/step-01-navigation.md +170 -170
- package/templates/skills/application/steps/step-02-permissions.md +196 -196
- package/templates/skills/application/steps/step-03-roles.md +182 -339
- package/templates/skills/application/steps/step-03b-provider.md +133 -134
- package/templates/skills/application/steps/step-04-backend.md +174 -265
- package/templates/skills/application/steps/step-05-frontend.md +18 -144
- package/templates/skills/application/steps/step-06-migration.md +12 -60
- package/templates/skills/application/steps/step-07-tests.md +9 -76
- package/templates/skills/application/templates-backend.md +29 -27
- package/templates/skills/application/templates-frontend.md +49 -49
- package/templates/skills/application/templates-seed.md +57 -131
- package/templates/skills/business-analyse/SKILL.md +27 -30
- package/templates/skills/business-analyse/_architecture.md +6 -6
- package/templates/skills/business-analyse/_shared.md +60 -88
- package/templates/skills/business-analyse/questionnaire/04-data.md +3 -3
- package/templates/skills/business-analyse/questionnaire/06-security.md +1 -1
- package/templates/skills/business-analyse/questionnaire/13-cross-module.md +1 -1
- package/templates/skills/business-analyse/react/application-viewer.md +12 -12
- package/templates/skills/business-analyse/react/components.md +8 -12
- package/templates/skills/business-analyse/react/schema.md +836 -836
- package/templates/skills/business-analyse/references/agent-module-prompt.md +2 -3
- package/templates/skills/business-analyse/references/analysis-semantic-checks.md +190 -0
- package/templates/skills/business-analyse/references/cache-warming-strategy.md +2 -2
- package/templates/skills/business-analyse/references/cadrage-challenge-patterns.md +41 -0
- package/templates/skills/business-analyse/references/cadrage-coverage-matrix.md +74 -0
- package/templates/skills/business-analyse/references/cadrage-shared-modules.md +69 -0
- package/templates/skills/business-analyse/references/cadrage-structure-cards.md +1 -1
- package/templates/skills/business-analyse/references/compilation-structure-cards.md +297 -0
- package/templates/skills/business-analyse/references/consolidation-structural-checks.md +2 -2
- package/templates/skills/business-analyse/references/deploy-modes.md +5 -5
- package/templates/skills/business-analyse/references/detection-strategies.md +7 -7
- package/templates/skills/business-analyse/references/handoff-file-templates.md +14 -22
- package/templates/skills/business-analyse/references/handoff-mappings.md +4 -4
- package/templates/skills/business-analyse/references/handoff-seeddata-generation.md +312 -0
- package/templates/skills/business-analyse/references/init-schema-deployment.md +3 -3
- package/templates/skills/business-analyse/references/naming-conventions.md +22 -24
- package/templates/skills/business-analyse/references/prd-generation.md +2 -2
- package/templates/skills/business-analyse/references/review-data-mapping.md +2 -2
- package/templates/skills/business-analyse/references/robustness-checks.md +1 -1
- package/templates/skills/business-analyse/references/spec-auto-inference.md +3 -3
- package/templates/skills/business-analyse/references/team-orchestration.md +49 -6
- package/templates/skills/business-analyse/references/ui-dashboard-spec.md +1 -1
- package/templates/skills/business-analyse/references/ui-resource-cards.md +18 -18
- package/templates/skills/business-analyse/references/validate-incremental-html.md +2 -2
- package/templates/skills/business-analyse/references/validation-checklist.md +2 -2
- package/templates/skills/business-analyse/schemas/application-schema.json +4 -5
- package/templates/skills/business-analyse/schemas/project-schema.json +1 -6
- package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +2 -3
- package/templates/skills/business-analyse/schemas/sections/specification-schema.json +4 -4
- package/templates/skills/business-analyse/steps/step-00-init.md +8 -17
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +35 -198
- package/templates/skills/business-analyse/steps/step-01b-applications.md +16 -20
- package/templates/skills/business-analyse/steps/step-02-decomposition.md +1 -1
- package/templates/skills/business-analyse/steps/step-03a1-setup.md +4 -4
- package/templates/skills/business-analyse/steps/step-03a2-analysis.md +1 -1
- package/templates/skills/business-analyse/steps/step-03b-ui.md +4 -4
- package/templates/skills/business-analyse/steps/step-03c-compile.md +66 -140
- package/templates/skills/business-analyse/steps/step-03d-validate.md +2 -2
- package/templates/skills/business-analyse/steps/step-04a-collect.md +2 -2
- package/templates/skills/business-analyse/steps/step-04b-analyze.md +42 -160
- package/templates/skills/business-analyse/steps/step-04c-decide.md +1 -1
- package/templates/skills/business-analyse/steps/step-05a-handoff.md +74 -104
- package/templates/skills/business-analyse/steps/step-05b-deploy.md +13 -11
- package/templates/skills/business-analyse/steps/step-06-review.md +3 -3
- package/templates/skills/business-analyse/templates/tpl-frd.md +13 -13
- package/templates/skills/business-analyse/templates/tpl-handoff.md +12 -12
- package/templates/skills/business-analyse/templates/tpl-progress.md +1 -1
- package/templates/skills/business-analyse/templates-frd.md +25 -25
- package/templates/skills/business-analyse/templates-react.md +15 -21
- package/templates/skills/controller/SKILL.md +1 -1
- package/templates/skills/controller/postman-templates.md +1 -1
- package/templates/skills/controller/references/controller-code-templates.md +2 -2
- package/templates/skills/controller/references/mcp-scaffold-workflow.md +209 -0
- package/templates/skills/controller/references/permission-sync-templates.md +13 -16
- package/templates/skills/controller/steps/step-00-init.md +11 -11
- package/templates/skills/controller/steps/step-03-generate.md +64 -103
- package/templates/skills/controller/templates.md +67 -71
- package/templates/skills/debug/SKILL.md +13 -218
- package/templates/skills/debug/steps/step-00-init.md +57 -0
- package/templates/skills/debug/steps/step-01-analyze.md +219 -0
- package/templates/skills/debug/steps/step-02-resolve.md +85 -0
- package/templates/skills/documentation/SKILL.md +49 -345
- package/templates/skills/documentation/data-schema.md +11 -8
- package/templates/skills/documentation/steps/step-00-init.md +70 -0
- package/templates/skills/documentation/steps/step-01-scan.md +113 -0
- package/templates/skills/documentation/steps/step-02-generate.md +231 -0
- package/templates/skills/documentation/steps/step-03-validate.md +238 -0
- package/templates/skills/documentation/templates.md +480 -322
- package/templates/skills/efcore/SKILL.md +1 -1
- package/templates/skills/efcore/references/both-contexts.md +32 -0
- package/templates/skills/efcore/references/database-operations.md +67 -0
- package/templates/skills/efcore/references/destructive-operations.md +38 -0
- package/templates/skills/efcore/references/reset-operations.md +81 -0
- package/templates/skills/efcore/references/seed-methods.md +86 -0
- package/templates/skills/efcore/references/shared-init-functions.md +250 -0
- package/templates/skills/efcore/references/sql-objects-injection.md +61 -0
- package/templates/skills/efcore/references/troubleshooting.md +81 -0
- package/templates/skills/efcore/steps/db/step-deploy.md +1 -32
- package/templates/skills/efcore/steps/db/step-reset.md +7 -103
- package/templates/skills/efcore/steps/db/step-seed.md +10 -132
- package/templates/skills/efcore/steps/db/step-status.md +5 -44
- package/templates/skills/efcore/steps/migration/step-02-create.md +1 -14
- package/templates/skills/efcore/steps/migration/step-03-validate.md +8 -62
- package/templates/skills/efcore/steps/rebase-snapshot/step-03-create.md +1 -57
- package/templates/skills/efcore/steps/shared/step-00-init.md +11 -254
- package/templates/skills/efcore/steps/squash/step-03-create.md +1 -58
- package/templates/skills/feature-full/SKILL.md +1 -1
- package/templates/skills/feature-full/steps/step-00-init.md +57 -0
- package/templates/skills/feature-full/steps/step-01-implementation.md +1 -1
- package/templates/skills/gitflow/SKILL.md +28 -5
- package/templates/skills/gitflow/_shared.md +109 -12
- package/templates/skills/gitflow/phases/abort.md +4 -0
- package/templates/skills/gitflow/phases/cleanup.md +4 -0
- package/templates/skills/gitflow/references/commit-message-generation.md +58 -0
- package/templates/skills/gitflow/references/commit-migration-validation.md +49 -0
- package/templates/skills/gitflow/references/finish-cleanup.md +55 -0
- package/templates/skills/gitflow/references/finish-version-bumping.md +45 -0
- package/templates/skills/gitflow/references/init-environment-detection.md +41 -0
- package/templates/skills/gitflow/references/init-questions.md +185 -0
- package/templates/skills/gitflow/references/init-structure-creation.md +75 -0
- package/templates/skills/gitflow/references/init-version-detection.md +21 -0
- package/templates/skills/gitflow/references/init-workspace-detection.md +43 -0
- package/templates/skills/gitflow/references/merge-ci-status.md +36 -0
- package/templates/skills/gitflow/references/merge-execution.md +62 -0
- package/templates/skills/gitflow/references/merge-pr-context.md +76 -0
- package/templates/skills/gitflow/references/pr-build-checks.md +60 -0
- package/templates/skills/gitflow/references/pr-generation.md +58 -0
- package/templates/skills/gitflow/references/start-branch-normalization.md +28 -0
- package/templates/skills/gitflow/references/start-worktree-creation.md +50 -0
- package/templates/skills/gitflow/references/sync-push-verify.md +44 -0
- package/templates/skills/gitflow/references/sync-rebase-conflicts.md +38 -0
- package/templates/skills/gitflow/steps/step-commit.md +12 -91
- package/templates/skills/gitflow/steps/step-finish.md +15 -159
- package/templates/skills/gitflow/steps/step-init.md +24 -326
- package/templates/skills/gitflow/steps/step-merge.md +17 -176
- package/templates/skills/gitflow/steps/step-pr.md +10 -116
- package/templates/skills/gitflow/steps/step-start.md +16 -109
- package/templates/skills/gitflow/steps/step-sync.md +6 -69
- package/templates/skills/ralph-loop/SKILL.md +6 -0
- package/templates/skills/ralph-loop/references/category-completeness.md +185 -0
- package/templates/skills/ralph-loop/references/compact-loop.md +1 -1
- package/templates/skills/ralph-loop/references/init-resume-recovery.md +127 -0
- package/templates/skills/ralph-loop/references/module-transition.md +151 -0
- package/templates/skills/ralph-loop/references/multi-module-queue.md +171 -0
- package/templates/skills/ralph-loop/references/parallel-execution.md +246 -0
- package/templates/skills/ralph-loop/references/task-transform-legacy.md +6 -9
- package/templates/skills/ralph-loop/references/team-orchestration.md +45 -3
- package/templates/skills/ralph-loop/steps/step-00-init.md +36 -109
- package/templates/skills/ralph-loop/steps/step-01-task.md +15 -163
- package/templates/skills/ralph-loop/steps/step-02-execute.md +8 -154
- package/templates/skills/ralph-loop/steps/step-04-check.md +20 -73
- package/templates/skills/review-code/references/owasp-api-top10.md +5 -5
- package/templates/skills/review-code/references/smartstack-conventions.md +568 -568
- package/templates/skills/validate-feature/references/api-smoke-tests.md +140 -0
- package/templates/skills/validate-feature/references/db-validation-checks.md +180 -0
- package/templates/skills/validate-feature/steps/step-01-compile.md +1 -3
- package/templates/skills/validate-feature/steps/step-04-api-smoke.md +34 -145
- package/templates/skills/validate-feature/steps/step-05-db-validation.md +74 -260
- package/templates/skills/workflow/SKILL.md +1 -1
- package/templates/skills/workflow/steps/step-00-init.md +57 -0
|
@@ -26,15 +26,14 @@ const permissions = coreSeedData.permissions || [];
|
|
|
26
26
|
const rolePerms = coreSeedData.rolePermissions || [];
|
|
27
27
|
|
|
28
28
|
// Derived context (from guardrail or PRD)
|
|
29
|
-
const navRoute = meta.navRoute; // e.g. "
|
|
30
|
-
const contextCode = meta.contextCode; // e.g. "business"
|
|
29
|
+
const navRoute = meta.navRoute; // e.g. "human-resources.projects"
|
|
31
30
|
const appCode = meta.appCode; // e.g. "human-resources"
|
|
32
31
|
const moduleCode = task.module; // e.g. "projects"
|
|
33
32
|
|
|
34
33
|
// If _seedDataMeta is absent, fallback to PRD source
|
|
35
34
|
if (!navRoute) {
|
|
36
35
|
const prd = readJSON('.ralph/prd.json');
|
|
37
|
-
const navRoute = `${prd.source?.
|
|
36
|
+
const navRoute = `${prd.source?.application || prd.metadata?.module}.${task.module}`;
|
|
38
37
|
}
|
|
39
38
|
```
|
|
40
39
|
|
|
@@ -42,8 +41,7 @@ if (!navRoute) {
|
|
|
42
41
|
|
|
43
42
|
| Variable | Example | Source |
|
|
44
43
|
|----------|---------|--------|
|
|
45
|
-
| `navRoute` | `
|
|
46
|
-
| `contextCode` | `business` | `_seedDataMeta.contextCode` |
|
|
44
|
+
| `navRoute` | `human-resources.projects` | `_seedDataMeta.navRoute` |
|
|
47
45
|
| `appCode` | `human-resources` | `_seedDataMeta.appCode` |
|
|
48
46
|
| `moduleCode` | `projects` | `task.module` |
|
|
49
47
|
| `navModules[]` | `[{code, label, icon, route, translations}]` | `coreSeedData.navigationModules` |
|
|
@@ -72,24 +70,15 @@ From `seedDataCore.navigationApplications[0]` in feature.json (generated by BA s
|
|
|
72
70
|
| `{appLabel_xx}` | `navigationApplications[0].labels.xx` (fr, en, it, de) |
|
|
73
71
|
| `{appDesc_xx}` | `navigationApplications[0].description.xx` |
|
|
74
72
|
| `{appIcon}` | `navigationApplications[0].icon` |
|
|
75
|
-
| `{contextCode}` | `navigationApplications[0].context` or `_seedDataMeta.contextCode` |
|
|
76
73
|
|
|
77
74
|
### GUID Generation Rule
|
|
78
75
|
|
|
79
|
-
> **CRITICAL — NavigationContext IDs are NEVER generated as deterministic GUIDs.**
|
|
80
|
-
> Contexts (`business`, `platform`, `personal`) are pre-seeded by SmartStack core with hardcoded GUIDs.
|
|
81
|
-
> The `contextId` parameter in `GetApplicationEntry(Guid contextId)` is resolved at runtime
|
|
82
|
-
> by querying `db.NavigationContexts.FirstOrDefaultAsync(c => c.Code == "business", ct)`.
|
|
83
|
-
> **FORBIDDEN:** `GenerateDeterministicGuid("nav:business")` or any ContextId constant in SeedConstants.
|
|
84
76
|
|
|
85
77
|
```csharp
|
|
86
|
-
// Deterministic GUID for APPLICATION
|
|
78
|
+
// Deterministic GUID for APPLICATION
|
|
87
79
|
public static readonly Guid ApplicationId =
|
|
88
|
-
GenerateDeterministicGuid("navigation-application-{
|
|
89
|
-
// Example: GenerateDeterministicGuid("navigation-application-
|
|
90
|
-
//
|
|
91
|
-
// FORBIDDEN — Context IDs must NOT be generated:
|
|
92
|
-
// public static readonly Guid BusinessContextId = GenerateDeterministicGuid("nav:business"); // WRONG!
|
|
80
|
+
GenerateDeterministicGuid("navigation-application-{appCode}");
|
|
81
|
+
// Example: GenerateDeterministicGuid("navigation-application-human-resources")
|
|
93
82
|
```
|
|
94
83
|
|
|
95
84
|
### Template
|
|
@@ -108,23 +97,22 @@ public static class NavigationApplicationSeedData
|
|
|
108
97
|
{
|
|
109
98
|
// Deterministic GUID for this application
|
|
110
99
|
public static readonly Guid ApplicationId =
|
|
111
|
-
GenerateDeterministicGuid("navigation-application-{
|
|
100
|
+
GenerateDeterministicGuid("navigation-application-{appCode}");
|
|
112
101
|
|
|
113
102
|
/// <summary>
|
|
114
103
|
/// Returns navigation application entry for seeding into core.nav_Applications.
|
|
115
104
|
/// </summary>
|
|
116
|
-
public static NavigationApplicationSeedEntry GetApplicationEntry(
|
|
105
|
+
public static NavigationApplicationSeedEntry GetApplicationEntry()
|
|
117
106
|
{
|
|
118
107
|
return new NavigationApplicationSeedEntry
|
|
119
108
|
{
|
|
120
109
|
Id = ApplicationId,
|
|
121
|
-
ContextId = contextId,
|
|
122
110
|
Code = "{appCode}",
|
|
123
111
|
Label = "{appLabel_en}",
|
|
124
112
|
Description = "{appDesc_en}",
|
|
125
113
|
Icon = "{appIcon}", // Lucide React icon name
|
|
126
114
|
IconType = IconType.Lucide,
|
|
127
|
-
Route = ToKebabCase("/{
|
|
115
|
+
Route = ToKebabCase("/{appCode}"),
|
|
128
116
|
DisplayOrder = 1,
|
|
129
117
|
IsActive = true
|
|
130
118
|
};
|
|
@@ -212,7 +200,6 @@ public static class NavigationApplicationSeedData
|
|
|
212
200
|
public class NavigationApplicationSeedEntry
|
|
213
201
|
{
|
|
214
202
|
public Guid Id { get; init; }
|
|
215
|
-
public Guid ContextId { get; init; }
|
|
216
203
|
public string Code { get; init; } = null!;
|
|
217
204
|
public string Label { get; init; } = null!;
|
|
218
205
|
public string? Description { get; init; }
|
|
@@ -245,7 +232,7 @@ private static Guid GenerateDeterministicGuid(string seed)
|
|
|
245
232
|
|
|
246
233
|
// Usage: GUIDs are derived from the navigation path
|
|
247
234
|
public static readonly Guid ModuleId = GenerateDeterministicGuid("navigation-module-{navRoute}");
|
|
248
|
-
// Example: GenerateDeterministicGuid("navigation-module-
|
|
235
|
+
// Example: GenerateDeterministicGuid("navigation-module-human-resources.projects")
|
|
249
236
|
```
|
|
250
237
|
|
|
251
238
|
### Template
|
|
@@ -279,7 +266,7 @@ public static class {ModulePascal}NavigationSeedData
|
|
|
279
266
|
Description = "{desc_en}",
|
|
280
267
|
Icon = "{icon}", // Lucide React icon name
|
|
281
268
|
IconType = IconType.Lucide,
|
|
282
|
-
Route = ToKebabCase($"/{
|
|
269
|
+
Route = ToKebabCase($"/{appCode}/{moduleCode}"),
|
|
283
270
|
DisplayOrder = {displayOrder},
|
|
284
271
|
IsActive = true
|
|
285
272
|
};
|
|
@@ -337,7 +324,7 @@ public static class {ModulePascal}NavigationSeedData
|
|
|
337
324
|
|
|
338
325
|
/// <summary>
|
|
339
326
|
/// Converts PascalCase route segments to kebab-case for web URLs.
|
|
340
|
-
/// Example: /
|
|
327
|
+
/// Example: /HumanResources/TimeManagement → /human-resources/time-management
|
|
341
328
|
/// </summary>
|
|
342
329
|
private static string ToKebabCase(string route)
|
|
343
330
|
{
|
|
@@ -406,20 +393,20 @@ public class NavigationTranslationSeedEntry
|
|
|
406
393
|
// Section GUID: deterministic from navRoute + section code
|
|
407
394
|
public static readonly Guid {SectionPascal}SectionId =
|
|
408
395
|
GenerateDeterministicGuid("navigation-section-{navRoute}.{sectionCode}");
|
|
409
|
-
// Example: GenerateDeterministicGuid("navigation-section-
|
|
396
|
+
// Example: GenerateDeterministicGuid("navigation-section-human-resources.employees.list")
|
|
410
397
|
|
|
411
398
|
// Resource GUID: deterministic from navRoute + section code + resource code
|
|
412
399
|
public static readonly Guid {ResourcePascal}ResourceId =
|
|
413
400
|
GenerateDeterministicGuid("navigation-resource-{navRoute}.{sectionCode}.{resourceCode}");
|
|
414
|
-
// Example: GenerateDeterministicGuid("navigation-resource-
|
|
401
|
+
// Example: GenerateDeterministicGuid("navigation-resource-human-resources.employees.list.employees-grid")
|
|
415
402
|
```
|
|
416
403
|
|
|
417
404
|
### Section Methods (add to {ModulePascal}NavigationSeedData.cs)
|
|
418
405
|
|
|
419
406
|
> **ROUTE SPECIAL CASES (list and detail):**
|
|
420
407
|
> The `list` and `detail` sections are view modes of the module, NOT functional sub-areas.
|
|
421
|
-
> - `list` section route = module route (e.g., `/
|
|
422
|
-
> - `detail` section route = module route + `/:id` (e.g., `/
|
|
408
|
+
> - `list` section route = module route (e.g., `/human-resources/employees`) — NO `/list` suffix
|
|
409
|
+
> - `detail` section route = module route + `/:id` (e.g., `/human-resources/employees/:id`) — NOT `/detail/:id`
|
|
423
410
|
> - FORBIDDEN: `/{module}/list`, `/{module}/detail/:id`
|
|
424
411
|
> - Other sections (dashboard, approve, import) = module route + `/{section-kebab}` (normal)
|
|
425
412
|
|
|
@@ -542,9 +529,9 @@ public static IEnumerable<NavigationResourceSeedEntry> GetResourceEntries(Guid s
|
|
|
542
529
|
// Then append: /{resource-kebab}
|
|
543
530
|
//
|
|
544
531
|
// Example: resource "export" under section "dashboard":
|
|
545
|
-
// Route = /
|
|
532
|
+
// Route = /human-resources/employees/dashboard/export
|
|
546
533
|
// Example: resource "employees-grid" under section "list":
|
|
547
|
-
// Route = /
|
|
534
|
+
// Route = /human-resources/employees/employees-grid (NOT /employees/list/employees-grid)
|
|
548
535
|
new NavigationResourceSeedEntry
|
|
549
536
|
{
|
|
550
537
|
Id = {Resource1Pascal}ResourceId,
|
|
@@ -678,22 +665,20 @@ MCP returns:
|
|
|
678
665
|
### Step B: Write Permissions.cs (Application layer)
|
|
679
666
|
|
|
680
667
|
> **CRITICAL — Permission paths use the SAME kebab-case as NavRoute codes.**
|
|
681
|
-
> `{navRoute}` is already kebab-case (e.g., `
|
|
668
|
+
> `{navRoute}` is already kebab-case (e.g., `human-resources.employees`).
|
|
682
669
|
> NEVER strip hyphens or derive codes from C# class names.
|
|
683
|
-
> FORBIDDEN: `
|
|
684
|
-
> SmartStack.app reference: `
|
|
670
|
+
> FORBIDDEN: `humanresources.employees.read` → CORRECT: `human-resources.employees.read`
|
|
671
|
+
> SmartStack.app reference: `support-client.my-tickets.read`
|
|
685
672
|
|
|
686
673
|
```csharp
|
|
687
674
|
// Add to Application/Common/Authorization/Permissions.cs
|
|
688
|
-
// IMPORTANT: {navRoute} uses kebab-case segments (e.g., "
|
|
675
|
+
// IMPORTANT: {navRoute} uses kebab-case segments (e.g., "human-resources.employees")
|
|
689
676
|
// Do NOT derive permission codes from C# identifiers — use navRoute directly
|
|
690
|
-
public static class {
|
|
677
|
+
public static class {AppPascal}
|
|
691
678
|
{
|
|
692
|
-
public const string Access = "{contextCode}.{appCode}";
|
|
693
|
-
|
|
694
679
|
public static class {ModulePascal}
|
|
695
680
|
{
|
|
696
|
-
public const string View = "{navRoute}.read"; // e.g., "
|
|
681
|
+
public const string View = "{navRoute}.read"; // e.g., "human-resources.employees.read"
|
|
697
682
|
public const string Create = "{navRoute}.create";
|
|
698
683
|
public const string Update = "{navRoute}.update";
|
|
699
684
|
public const string Delete = "{navRoute}.delete";
|
|
@@ -949,11 +934,9 @@ public class ApplicationRoleSeedEntry
|
|
|
949
934
|
|
|
950
935
|
### Context-Based Role Mapping
|
|
951
936
|
|
|
952
|
-
|
|
|
953
|
-
|
|
954
|
-
|
|
|
955
|
-
| `business.*` | CRUD | CRU | CR | R |
|
|
956
|
-
| `personal.*` | CRUD | CRU | CR | R |
|
|
937
|
+
| Application | Admin | Manager | Contributor | Viewer |
|
|
938
|
+
|-------------|-------|---------|-------------|--------|
|
|
939
|
+
| Any | CRUD | CRU | CR | R |
|
|
957
940
|
|
|
958
941
|
### Template
|
|
959
942
|
|
|
@@ -1059,7 +1042,7 @@ public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
|
|
|
1059
1042
|
// NOTE: Idempotence is at MODULE level (not application level).
|
|
1060
1043
|
// If the application already exists, we load it and continue to seed any missing modules.
|
|
1061
1044
|
// This allows adding Module 2+ to an existing application without re-running the full seed.
|
|
1062
|
-
var appEntry = NavigationApplicationSeedData.GetApplicationEntry(
|
|
1045
|
+
var appEntry = NavigationApplicationSeedData.GetApplicationEntry();
|
|
1063
1046
|
var existingApp = await context.NavigationApplications
|
|
1064
1047
|
.FirstOrDefaultAsync(a => a.Code == appEntry.Code, ct);
|
|
1065
1048
|
|
|
@@ -1070,13 +1053,8 @@ public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
|
|
|
1070
1053
|
}
|
|
1071
1054
|
else
|
|
1072
1055
|
{
|
|
1073
|
-
var parentContext = await context.NavigationContexts
|
|
1074
|
-
.FirstAsync(c => c.Code == "{contextCode}", ct);
|
|
1075
|
-
|
|
1076
|
-
// Re-get entry with resolved contextId
|
|
1077
|
-
appEntry = NavigationApplicationSeedData.GetApplicationEntry(parentContext.Id);
|
|
1078
1056
|
app = NavigationApplication.Create(
|
|
1079
|
-
appEntry.
|
|
1057
|
+
appEntry.Code, appEntry.Label,
|
|
1080
1058
|
appEntry.Description, appEntry.Icon, appEntry.IconType,
|
|
1081
1059
|
appEntry.Route, appEntry.DisplayOrder);
|
|
1082
1060
|
context.NavigationApplications.Add(app);
|
|
@@ -1218,12 +1196,12 @@ public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
|
|
|
1218
1196
|
public async Task SeedPermissionsAsync(ICoreDbContext context, CancellationToken ct)
|
|
1219
1197
|
{
|
|
1220
1198
|
var exists = await context.Permissions
|
|
1221
|
-
.AnyAsync(p => p.Path == "{
|
|
1199
|
+
.AnyAsync(p => p.Path == "{appCode}.*", ct);
|
|
1222
1200
|
if (exists) return;
|
|
1223
1201
|
|
|
1224
1202
|
// Application-level wildcard
|
|
1225
1203
|
var appWildcard = Permission.CreateWildcard(
|
|
1226
|
-
"{
|
|
1204
|
+
"{appCode}.*", PermissionLevel.Application,
|
|
1227
1205
|
"Full {appLabel_en} access");
|
|
1228
1206
|
context.Permissions.Add(appWildcard);
|
|
1229
1207
|
|
|
@@ -1245,7 +1223,7 @@ public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
|
|
|
1245
1223
|
public async Task SeedRolePermissionsAsync(ICoreDbContext context, CancellationToken ct)
|
|
1246
1224
|
{
|
|
1247
1225
|
var exists = await context.RolePermissions
|
|
1248
|
-
.AnyAsync(rp => rp.Permission!.Path.StartsWith("{
|
|
1226
|
+
.AnyAsync(rp => rp.Permission!.Path.StartsWith("{appCode}."), ct);
|
|
1249
1227
|
if (exists) return;
|
|
1250
1228
|
|
|
1251
1229
|
// CRITICAL: Resolve roles by Code from DB — NEVER use deterministic GUIDs.
|
|
@@ -1258,7 +1236,7 @@ public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
|
|
|
1258
1236
|
|
|
1259
1237
|
// Resolve permissions
|
|
1260
1238
|
var permissions = await context.Permissions
|
|
1261
|
-
.Where(p => p.Path.StartsWith("{
|
|
1239
|
+
.Where(p => p.Path.StartsWith("{appCode}."))
|
|
1262
1240
|
.ToListAsync(ct);
|
|
1263
1241
|
|
|
1264
1242
|
// Apply role-permission mappings from all modules
|
|
@@ -1349,9 +1327,8 @@ Before marking the task as completed, verify ALL:
|
|
|
1349
1327
|
|
|
1350
1328
|
**Application-Level (FIRST — before modules):**
|
|
1351
1329
|
- [ ] `NavigationApplicationSeedData.cs` created (once per application, at `Infrastructure/Persistence/Seeding/Data/`)
|
|
1352
|
-
- [ ] Application GUID is deterministic (SHA256 of `"navigation-application-{
|
|
1353
|
-
- [ ]
|
|
1354
|
-
- [ ] **SeedDataProvider queries context by code at runtime:** `db.NavigationContexts.FirstOrDefaultAsync(c => c.Code == "{contextCode}", ct)`
|
|
1330
|
+
- [ ] Application GUID is deterministic (SHA256 of `"navigation-application-{appCode}"`)
|
|
1331
|
+
- [ ] GetApplicationEntry() takes no parameters (no contextId)
|
|
1355
1332
|
- [ ] Application translations created (4 languages: fr, en, it, de, EntityType = Application)
|
|
1356
1333
|
- [ ] `IClientSeedDataProvider.SeedNavigationAsync()` uses `NavigationApplicationSeedData` (NO hardcoded `{appLabel_en}` / `{appIcon}` placeholders)
|
|
1357
1334
|
- [ ] `ApplicationRolesSeedData.ApplicationId` references `NavigationApplicationSeedData.ApplicationId` (NO `{ApplicationGuid}` placeholder)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Examine Build & Migration Validation
|
|
2
|
+
|
|
3
|
+
> **Loaded by:** step-04-examine.md (sections 4-5)
|
|
4
|
+
> **Purpose:** Build verification, migration validation, database testing procedures.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Build Verification
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# Backend
|
|
12
|
+
dotnet clean && dotnet restore && dotnet build
|
|
13
|
+
# Note: WSL bin\Debug cleanup handled by PostToolUse hook (wsl-dotnet-cleanup.sh)
|
|
14
|
+
|
|
15
|
+
# Frontend (if applicable)
|
|
16
|
+
npm run typecheck
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**BLOCKING:** Both must pass. If failure, classify error per `references/error-classification.md`:
|
|
20
|
+
- Category A (missing package) → `dotnet add package` → rebuild
|
|
21
|
+
- Category B (assembly conflict) → resolve version → rebuild
|
|
22
|
+
- Category C (DI missing) → fix DI registration → rebuild
|
|
23
|
+
- Category D (migration broken) → fix migration → rebuild
|
|
24
|
+
- Category E (config) → fix config → rebuild
|
|
25
|
+
- Category F (source code) → fix code → rebuild
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Migration Validation (if needs_migration)
|
|
30
|
+
|
|
31
|
+
### Pending Model Changes Check
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
INFRA_PROJECT=$(ls src/*Infrastructure*/*.csproj 2>/dev/null | head -1)
|
|
35
|
+
API_PROJECT=$(ls src/*Api*/*.csproj 2>/dev/null | head -1)
|
|
36
|
+
|
|
37
|
+
dotnet ef migrations has-pending-model-changes \
|
|
38
|
+
--project "$INFRA_PROJECT" \
|
|
39
|
+
--startup-project "$API_PROJECT"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**BLOCKING** if pending changes detected → migration is missing.
|
|
43
|
+
|
|
44
|
+
### Migration Application Test (SQL Server LocalDB)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
DB_NAME="SmartStack_Apex_Examine_$(date +%s)"
|
|
48
|
+
CONN_STRING="Server=(localdb)\\MSSQLLocalDB;Database=$DB_NAME;Integrated Security=true;TrustServerCertificate=true;Connect Timeout=120;"
|
|
49
|
+
|
|
50
|
+
dotnet ef database update \
|
|
51
|
+
--connection "$CONN_STRING" \
|
|
52
|
+
--project "$INFRA_PROJECT" \
|
|
53
|
+
--startup-project "$API_PROJECT"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**BLOCKING** if migration fails on SQL Server. Common issues:
|
|
57
|
+
- SQLite-only syntax in migrations (fix: regenerate migration)
|
|
58
|
+
- Column type mismatches (fix: update EF configuration)
|
|
59
|
+
- Missing foreign key targets (fix: reorder migrations)
|
|
60
|
+
|
|
61
|
+
### Integration Tests on Real SQL Server
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Integration tests use DatabaseFixture → real SQL Server LocalDB
|
|
65
|
+
# This validates: LINQ→SQL, multi-tenant isolation, soft delete, EF configs
|
|
66
|
+
INT_TEST_PROJECT=$(ls tests/*Tests.Integration*/*.csproj 2>/dev/null | head -1)
|
|
67
|
+
if [ -n "$INT_TEST_PROJECT" ]; then
|
|
68
|
+
dotnet test "$INT_TEST_PROJECT" --no-build --verbosity normal
|
|
69
|
+
fi
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Tests running against SQL Server catch issues that SQLite misses:
|
|
73
|
+
- Case sensitivity in string comparisons
|
|
74
|
+
- Date/time function differences
|
|
75
|
+
- IDENTITY vs AUTOINCREMENT behavior
|
|
76
|
+
- Global query filter translation to T-SQL
|
|
77
|
+
|
|
78
|
+
### Cleanup
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "IF DB_ID('$DB_NAME') IS NOT NULL BEGIN ALTER DATABASE [$DB_NAME] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [$DB_NAME]; END" 2>/dev/null
|
|
82
|
+
```
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Frontend Compliance Gate — 5 Mandatory Checks
|
|
2
|
+
|
|
3
|
+
> **Loaded by:** step-03-execute.md (FRONTEND COMPLIANCE GATE section)
|
|
4
|
+
> **Condition:** MANDATORY before any frontend commit
|
|
5
|
+
> **Purpose:** Automated checks that catch the most common failures in generated code.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Gate 1: CSS Variables (Theme System)
|
|
10
|
+
|
|
11
|
+
Check for hardcoded Tailwind colors — MUST use CSS variables.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
ALL_PAGES=$(find src/pages/ src/components/ -name "*.tsx" 2>/dev/null | grep -v node_modules | grep -v "\.test\.")
|
|
15
|
+
if [ -n "$ALL_PAGES" ]; then
|
|
16
|
+
HARDCODED=$(grep -Pn '(bg|text|border)-(?!\[)(red|blue|green|gray|white|black|slate|zinc|neutral|stone)-' $ALL_PAGES 2>/dev/null)
|
|
17
|
+
if [ -n "$HARDCODED" ]; then
|
|
18
|
+
echo "FAIL: Hardcoded Tailwind colors found — must use CSS variables"
|
|
19
|
+
echo "$HARDCODED"
|
|
20
|
+
else
|
|
21
|
+
echo "PASS: CSS variables"
|
|
22
|
+
fi
|
|
23
|
+
fi
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**If hardcoded colors found, replace BEFORE committing:**
|
|
27
|
+
|
|
28
|
+
| Old | New |
|
|
29
|
+
|-----|-----|
|
|
30
|
+
| `bg-white` | `bg-[var(--bg-card)]` |
|
|
31
|
+
| `bg-gray-50` | `bg-[var(--bg-primary)]` |
|
|
32
|
+
| `text-gray-900` | `text-[var(--text-primary)]` |
|
|
33
|
+
| `text-gray-500/600` | `text-[var(--text-secondary)]` |
|
|
34
|
+
| `border-gray-200` | `border-[var(--border-color)]` |
|
|
35
|
+
| `bg-blue-600` / `text-blue-600` | `bg-[var(--color-accent-500)]` / `text-[var(--color-accent-500)]` |
|
|
36
|
+
| `hover:bg-blue-700` | `hover:bg-[var(--color-accent-600)]` |
|
|
37
|
+
| `text-red-500` | `text-[var(--error-text)]` |
|
|
38
|
+
| `bg-green-500` | `bg-[var(--success-bg)]` |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Gate 2: Forms as Pages (ZERO Modals/Drawers/Slide-overs)
|
|
43
|
+
|
|
44
|
+
Check for modal/dialog/drawer/slide-over imports and inline form patterns — FORBIDDEN.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
PAGE_FILES=$(find src/pages/ -name "*.tsx" 2>/dev/null)
|
|
48
|
+
if [ -n "$PAGE_FILES" ]; then
|
|
49
|
+
FAIL=false
|
|
50
|
+
|
|
51
|
+
# 2a. Component imports
|
|
52
|
+
MODAL_IMPORTS=$(grep -Pn "import.*(?:Modal|Dialog|Drawer|Popup|Sheet|SlideOver|Overlay)" $PAGE_FILES 2>/dev/null)
|
|
53
|
+
if [ -n "$MODAL_IMPORTS" ]; then
|
|
54
|
+
echo "FAIL: Modal/Dialog/Drawer component imports — forms MUST be full pages"
|
|
55
|
+
echo "$MODAL_IMPORTS"
|
|
56
|
+
FAIL=true
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# 2b. State variables for inline forms (catches drawers/slide-overs without imports)
|
|
60
|
+
MODAL_STATE=$(grep -Pn "useState.*(?:isOpen|showModal|showDialog|showCreate|showEdit|showForm|isCreating|isEditing|showDrawer|showPanel|showSlideOver|selectedEntity|editingEntity)" $PAGE_FILES 2>/dev/null)
|
|
61
|
+
if [ -n "$MODAL_STATE" ]; then
|
|
62
|
+
echo "FAIL: Inline form state detected — forms MUST be separate page components with own routes"
|
|
63
|
+
echo "$MODAL_STATE"
|
|
64
|
+
FAIL=true
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
if [ "$FAIL" = true ]; then
|
|
68
|
+
echo "Fix: Create EntityCreatePage.tsx (route: /create) and EntityEditPage.tsx (route: /:id/edit)"
|
|
69
|
+
echo "See smartstack-frontend.md section 3b"
|
|
70
|
+
else
|
|
71
|
+
echo "PASS: No modals/drawers"
|
|
72
|
+
fi
|
|
73
|
+
fi
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**If modals/drawers found:** Replace with separate `EntityCreatePage.tsx` (route: `/{module}/create`) and `EntityEditPage.tsx` (route: `/{module}/:id/edit`). See `smartstack-frontend.md` section 3b.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Gate 3: I18n File Structure
|
|
81
|
+
|
|
82
|
+
Verify translation files exist as separate JSON per language.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
if [ ! -d "src/i18n/locales" ]; then
|
|
86
|
+
echo "FAIL: Missing src/i18n/locales/ directory — create it with 4 languages"
|
|
87
|
+
else
|
|
88
|
+
for LANG in fr en it de; do
|
|
89
|
+
JSON_FILES=$(find "src/i18n/locales/$LANG" -name "*.json" 2>/dev/null | wc -l)
|
|
90
|
+
if [ "$JSON_FILES" -eq 0 ]; then
|
|
91
|
+
echo "FAIL: No JSON files in src/i18n/locales/$LANG/"
|
|
92
|
+
else
|
|
93
|
+
echo "PASS: $LANG ($JSON_FILES files)"
|
|
94
|
+
fi
|
|
95
|
+
done
|
|
96
|
+
fi
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**If i18n structure wrong:** Create `src/i18n/locales/{fr,en,it,de}/{module}.json` following the template in `smartstack-frontend.md` section 2. NEVER embed translations in a single `.ts` file.
|
|
100
|
+
|
|
101
|
+
**Correct structure:**
|
|
102
|
+
```
|
|
103
|
+
src/i18n/locales/
|
|
104
|
+
├── fr/{module}.json ← French (primary)
|
|
105
|
+
├── en/{module}.json ← English
|
|
106
|
+
├── it/{module}.json ← Italian
|
|
107
|
+
└── de/{module}.json ← German
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Each file MUST contain: `title`, `description`, `actions`, `labels`, `columns`, `form`, `errors`, `validation`, `messages`, `empty`.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Gate 4: Lazy Loading
|
|
115
|
+
|
|
116
|
+
Check for static page imports in route/App files.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
APP_TSX=$(find src/ -name "App.tsx" -not -path "*/node_modules/*" 2>/dev/null | head -1)
|
|
120
|
+
ROUTE_FILES=$(find src/routes/ -name "*.tsx" -o -name "*.ts" 2>/dev/null)
|
|
121
|
+
if [ -n "$APP_TSX" ]; then
|
|
122
|
+
STATIC_IMPORTS=$(grep -Pn "^import .+ from '@/pages/" "$APP_TSX" $ROUTE_FILES 2>/dev/null)
|
|
123
|
+
if [ -n "$STATIC_IMPORTS" ]; then
|
|
124
|
+
echo "FAIL: Static page imports in App.tsx/routes — MUST use React.lazy()"
|
|
125
|
+
echo "$STATIC_IMPORTS"
|
|
126
|
+
else
|
|
127
|
+
echo "PASS: Lazy loading"
|
|
128
|
+
fi
|
|
129
|
+
fi
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Gate 5: useTranslation in Pages
|
|
135
|
+
|
|
136
|
+
Verify pages use i18n.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
PAGE_FILES=$(find src/pages/ -name "*.tsx" 2>/dev/null | grep -v "\.test\." | grep -v node_modules)
|
|
140
|
+
if [ -n "$PAGE_FILES" ]; then
|
|
141
|
+
TOTAL=$(echo "$PAGE_FILES" | wc -l)
|
|
142
|
+
WITH_I18N=$(grep -l "useTranslation" $PAGE_FILES 2>/dev/null | wc -l)
|
|
143
|
+
if [ "$WITH_I18N" -eq 0 ]; then
|
|
144
|
+
echo "FAIL: No pages use useTranslation — all text must be translated"
|
|
145
|
+
else
|
|
146
|
+
echo "PASS: $WITH_I18N/$TOTAL pages use useTranslation"
|
|
147
|
+
fi
|
|
148
|
+
fi
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Explicit I18n File Creation
|
|
154
|
+
|
|
155
|
+
When creating i18n files, generate EXACTLY this structure:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
src/i18n/locales/
|
|
159
|
+
├── fr/{module}.json ← French (primary)
|
|
160
|
+
├── en/{module}.json ← English
|
|
161
|
+
├── it/{module}.json ← Italian
|
|
162
|
+
└── de/{module}.json ← German
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Each file MUST contain these keys: `title`, `description`, `actions`, `labels`, `columns`, `form`, `errors`, `validation`, `messages`, `empty`. See `smartstack-frontend.md` section 2 for the complete JSON template.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## ALL 5 Gates MUST PASS
|
|
170
|
+
|
|
171
|
+
**Before creating the frontend commit:**
|
|
172
|
+
1. Do NOT commit frontend changes until ALL checks pass
|
|
173
|
+
2. If ANY gate fails, fix the issues first
|
|
174
|
+
3. When delegating to `/ui-components` skill, include explicit instructions:
|
|
175
|
+
- "CSS: Use CSS variables ONLY — `bg-[var(--bg-card)]`, `text-[var(--text-primary)]`. NEVER use hardcoded Tailwind colors."
|
|
176
|
+
- "Forms: Create/Edit forms are FULL PAGES with own routes (e.g., `/create`, `/:id/edit`). NEVER use modals/dialogs."
|
|
177
|
+
- "I18n: ALL text must use `t('namespace:key', 'Fallback')`. Generate JSON files in `src/i18n/locales/`."
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Frontend Patterns — Economy Mode Guidelines
|
|
2
|
+
|
|
3
|
+
> **Loaded by:** step-03-execute.md (Layer 1 section: economy_mode frontend tasks)
|
|
4
|
+
> **Purpose:** Quick reference for frontend creation in sequential (economy) mode.
|
|
5
|
+
> **Detailed patterns:** See `smartstack-frontend.md` (referenced from smartstack-layers.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Frontend Tasks — Sequential Execution (economy_mode)
|
|
10
|
+
|
|
11
|
+
For each frontend task in the plan (Layer 1):
|
|
12
|
+
|
|
13
|
+
1. **API Client:** `MCP scaffold_api_client` → API client + types + React Query hook
|
|
14
|
+
2. **Routes:** `MCP scaffold_routes` with `outputFormat: 'clientRoutes'` for lazy imports
|
|
15
|
+
3. **Pages:** **INVOKE `/ui-components` skill** (read SKILL.md + ALL patterns) — MANDATORY for ALL page types
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Required Page Types Per Module
|
|
20
|
+
|
|
21
|
+
Create ALL 4 page types per module:
|
|
22
|
+
- `ListPage.tsx` — entity list with SmartTable/EntityCard
|
|
23
|
+
- `DetailPage.tsx` — entity detail view
|
|
24
|
+
- `EntityCreatePage.tsx` (route: `/create`) — FULL PAGE form, NEVER modal
|
|
25
|
+
- `EntityEditPage.tsx` (route: `/:id/edit`) — FULL PAGE form, NEVER modal
|
|
26
|
+
|
|
27
|
+
**Wire ALL routes in App.tsx:** `index` (ListPage), `:id` (DetailPage), `create` (CreatePage), `:id/edit` (EditPage)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Foreign Key (FK) Fields — CRITICAL
|
|
32
|
+
|
|
33
|
+
Any Guid FK property (e.g., EmployeeId, DepartmentId) MUST use `EntityLookup` component:
|
|
34
|
+
- **NEVER** a `<select>` dropdown
|
|
35
|
+
- **NEVER** a `<input type="text">`
|
|
36
|
+
- **A `<select>` loaded from API state is NOT a substitute for EntityLookup**
|
|
37
|
+
|
|
38
|
+
See `smartstack-frontend.md` section 6 for the full EntityLookup pattern. Backend GetAll endpoints MUST support `?search=` parameter (enables EntityLookup on frontend).
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Forms: ZERO Modals/Popups/Drawers/Slide-overs
|
|
43
|
+
|
|
44
|
+
**ALL forms are full pages with their own URL:**
|
|
45
|
+
- Create forms: route `/{module}/create`
|
|
46
|
+
- Edit forms: route `/{module}/:id/edit`
|
|
47
|
+
- NEVER embed forms as drawers, panels, or slide-overs
|
|
48
|
+
- Back button with `navigate(-1)` on every form page
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Detail Pages: Tab Behavior (CRITICAL)
|
|
53
|
+
|
|
54
|
+
**Tabs MUST switch content LOCALLY via `setActiveTab()` — NEVER `navigate()` to another page.**
|
|
55
|
+
|
|
56
|
+
Sub-resource data (e.g., employee's leaves) loads inline via API call filtered by parent entity ID. See `smartstack-frontend.md` section 3 "Tab Behavior Rules".
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Tests (MANDATORY)
|
|
61
|
+
|
|
62
|
+
Generate form tests as co-located files:
|
|
63
|
+
- `EntityCreatePage.test.tsx` (next to CreatePage.tsx)
|
|
64
|
+
- `EntityEditPage.test.tsx` (next to EditPage.tsx)
|
|
65
|
+
|
|
66
|
+
Cover: rendering, validation, submit, pre-fill, navigation, errors. See `smartstack-frontend.md` section 8 for test templates.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Section-Level Routes (if sections exist)
|
|
71
|
+
|
|
72
|
+
**SECTION PERMISSIONS:** After calling `MCP generate_permissions` for the module navRoute (2 segments: `{app}.{module}`), also call it for EACH section navRoute (3 segments: `{app}.{module}.{section}`)
|
|
73
|
+
|
|
74
|
+
**SECTION ROUTES:** After generating module routes, add section child routes to the module's `children` array. Wire `PermissionGuard` for section routes with section-level permissions.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Sub-Resource Handling
|
|
79
|
+
|
|
80
|
+
If a section controller has sub-resource endpoints (e.g., `[HttpGet("types")]` for LeaveTypes inside LeavesController), you MUST EITHER:
|
|
81
|
+
1. Create dedicated frontend pages for the sub-resource (ListPage, CreatePage, EditPage) with routes wired in App.tsx, OR
|
|
82
|
+
2. NOT include any `navigate()` button that links to those sub-resource pages
|
|
83
|
+
|
|
84
|
+
**Prefer separate controllers** with `[NavRoute(..., Suffix = "types")]` — see `smartstack-api.md` Sub-Resource Pattern. A dead link (navigate to a route with no page) is a BLOCKING issue (POST-CHECK 42).
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## I18n (Translations)
|
|
89
|
+
|
|
90
|
+
Generate i18n JSON files for all 4 languages (fr, en, it, de):
|
|
91
|
+
- Location: `src/i18n/locales/{lang}/{module}.json`
|
|
92
|
+
- Keys: `actions`, `labels`, `errors`, `validation`, `columns`, `form`, `messages`, `empty`
|
|
93
|
+
- ALL `t()` calls MUST use namespace prefix + fallback: `t('ns:key', 'Default text')`
|
|
94
|
+
|
|
95
|
+
**CRITICAL:** After creating i18n JSON files, register EACH new namespace in the i18n config file (config.ts/index.ts/i18n.ts). Unregistered namespaces → `useTranslation(['module'])` returns empty strings at runtime. POST-CHECK 45 validates this.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Folder Structure
|
|
100
|
+
|
|
101
|
+
MUST use: `src/pages/{App}/{Module}/` hierarchy (NOT flat).
|
|
102
|
+
|
|
103
|
+
All pages must follow: **hooks → useEffect(load) → loading state → error state → content**
|
|
104
|
+
|
|
105
|
+
Use **CSS variables ONLY** for styling — hardcoded Tailwind colors are BLOCKING (POST-CHECK 13).
|