@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
|
@@ -79,7 +79,7 @@ public enum EntityScope
|
|
|
79
79
|
```csharp
|
|
80
80
|
using SmartStack.Domain.Common;
|
|
81
81
|
|
|
82
|
-
namespace {ProjectName}.Domain.Entities.{
|
|
82
|
+
namespace {ProjectName}.Domain.Entities.{App}.{Module};
|
|
83
83
|
|
|
84
84
|
public class {Name} : BaseEntity, ITenantEntity, IAuditableEntity
|
|
85
85
|
{
|
|
@@ -299,7 +299,7 @@ using SmartStack.Application.Common.Interfaces.Identity;
|
|
|
299
299
|
using SmartStack.Application.Common.Interfaces.Tenants;
|
|
300
300
|
using SmartStack.Application.Common.Interfaces.Persistence;
|
|
301
301
|
|
|
302
|
-
namespace {ProjectName}.Infrastructure.Services.{
|
|
302
|
+
namespace {ProjectName}.Infrastructure.Services.{App}.{Module};
|
|
303
303
|
|
|
304
304
|
public class {Name}Service : I{Name}Service
|
|
305
305
|
{
|
|
@@ -432,10 +432,10 @@ using Microsoft.AspNetCore.Mvc;
|
|
|
432
432
|
using SmartStack.Api.Routing;
|
|
433
433
|
using SmartStack.Api.Authorization;
|
|
434
434
|
|
|
435
|
-
namespace {ProjectName}.Api.Controllers.{
|
|
435
|
+
namespace {ProjectName}.Api.Controllers.{App};
|
|
436
436
|
|
|
437
437
|
[ApiController]
|
|
438
|
-
[NavRoute("{
|
|
438
|
+
[NavRoute("{app}.{module}")]
|
|
439
439
|
[Authorize]
|
|
440
440
|
public class {Name}Controller : ControllerBase
|
|
441
441
|
{
|
|
@@ -500,10 +500,10 @@ public class {Name}Controller : ControllerBase
|
|
|
500
500
|
**CRITICAL:** Use `[RequirePermission(Permissions.{Module}.{Action})]` on EVERY endpoint — NEVER `[Authorize]` alone (no RBAC enforcement).
|
|
501
501
|
|
|
502
502
|
**CRITICAL — Permission paths use IDENTICAL segments to NavRoute codes (kebab-case):**
|
|
503
|
-
- NavRoute: `
|
|
504
|
-
- NavRoute: `
|
|
505
|
-
- FORBIDDEN: `
|
|
506
|
-
- SmartStack.app convention: `
|
|
503
|
+
- NavRoute: `human-resources.employees` → Permission: `human-resources.employees.read`
|
|
504
|
+
- NavRoute: `human-resources.employees.leaves` → Permission: `human-resources.employees.leaves.read`
|
|
505
|
+
- FORBIDDEN: `humanresources.employees.read` (no kebab-case — mismatches NavRoute)
|
|
506
|
+
- SmartStack.app convention: `support-client.my-tickets.read` (always kebab-case)
|
|
507
507
|
|
|
508
508
|
### Section-Level Controller (NavRoute with 4 segments)
|
|
509
509
|
|
|
@@ -512,11 +512,11 @@ When a module has sections, each section gets its own controller with a 4-segmen
|
|
|
512
512
|
```csharp
|
|
513
513
|
// Section-level controller: navRoute has 4 segments
|
|
514
514
|
[ApiController]
|
|
515
|
-
[NavRoute("{
|
|
515
|
+
[NavRoute("{app}.{module}.{section}")]
|
|
516
516
|
[Authorize]
|
|
517
517
|
public class {Section}Controller : ControllerBase
|
|
518
518
|
{
|
|
519
|
-
// Example:
|
|
519
|
+
// Example: human-resources.employees.departments
|
|
520
520
|
[HttpGet]
|
|
521
521
|
[RequirePermission(Permissions.{Section}.Read)]
|
|
522
522
|
public async Task<ActionResult<PaginatedResult<{Section}ResponseDto>>> GetAll(
|
|
@@ -531,12 +531,12 @@ public class {Section}Controller : ControllerBase
|
|
|
531
531
|
**NavRoute segment rules:**
|
|
532
532
|
| Level | NavRoute format | Example |
|
|
533
533
|
|-------|----------------|---------|
|
|
534
|
-
| Module | `{
|
|
535
|
-
| Section | `{
|
|
534
|
+
| Module | `{app}.{module}` (2 segments) | `human-resources.employees` |
|
|
535
|
+
| Section | `{app}.{module}.{section}` (3 segments) | `human-resources.employees.departments` |
|
|
536
536
|
|
|
537
537
|
**Namespace:** `SmartStack.Api.Routing` (NOT `SmartStack.Api.Core.Routing`)
|
|
538
538
|
|
|
539
|
-
**NavRoute resolves at startup from DB:** `
|
|
539
|
+
**NavRoute resolves at startup from DB:** `administration.users` → `api/administration/users`
|
|
540
540
|
|
|
541
541
|
### Sub-Resource Pattern (NavRoute Suffix)
|
|
542
542
|
|
|
@@ -545,7 +545,7 @@ When an entity is a child of another entity (e.g., LeaveTypes under Leaves), use
|
|
|
545
545
|
```csharp
|
|
546
546
|
// Sub-resource controller: types are nested under leaves
|
|
547
547
|
[ApiController]
|
|
548
|
-
[NavRoute("
|
|
548
|
+
[NavRoute("human-resources.employees.leaves", Suffix = "types")]
|
|
549
549
|
[Authorize]
|
|
550
550
|
public class LeaveTypesController : ControllerBase
|
|
551
551
|
{
|
|
@@ -582,22 +582,22 @@ public async Task<ActionResult<PaginatedResult<LeaveTypeResponseDto>>> GetAllLea
|
|
|
582
582
|
|
|
583
583
|
| Level | Route Format | Example |
|
|
584
584
|
|-------|-------------|---------|
|
|
585
|
-
| Application | `/{
|
|
586
|
-
| Module | `/{
|
|
587
|
-
| Section | `/{
|
|
588
|
-
| Resource | `/{
|
|
585
|
+
| Application | `/{app-kebab}` | `/human-resources` |
|
|
586
|
+
| Module | `/{app-kebab}/{module-kebab}` | `/human-resources/employees` |
|
|
587
|
+
| Section | `/{app-kebab}/{module-kebab}/{section-kebab}` | `/human-resources/employees/departments` |
|
|
588
|
+
| Resource | `/{app-kebab}/{module-kebab}/{section-kebab}/{resource-kebab}` | `/human-resources/employees/departments/export` |
|
|
589
589
|
|
|
590
590
|
**ROUTE SPECIAL CASES (list and detail sections):**
|
|
591
591
|
> The `list` and `detail` sections are NOT functional sub-areas — they are view modes of the module itself.
|
|
592
592
|
> Their navigation routes MUST NOT add extra segments:
|
|
593
|
-
> - `list` section route = module route (e.g., `/
|
|
594
|
-
> - `detail` section route = module route + `/:id` (e.g., `/
|
|
593
|
+
> - `list` section route = module route (e.g., `/human-resources/employees`)
|
|
594
|
+
> - `detail` section route = module route + `/:id` (e.g., `/human-resources/employees/:id`)
|
|
595
595
|
> - FORBIDDEN: `/employees/list`, `/employees/detail/:id`
|
|
596
596
|
> - Other sections (dashboard, approve, import, etc.) = module route + `/{section-kebab}` (normal behavior)
|
|
597
597
|
|
|
598
598
|
**Rules:**
|
|
599
599
|
- Routes ALWAYS start with `/`
|
|
600
|
-
- Routes ALWAYS include the full hierarchy from
|
|
600
|
+
- Routes ALWAYS include the full hierarchy from application to current level
|
|
601
601
|
- Routes ALWAYS use kebab-case (NOT PascalCase, NOT camelCase)
|
|
602
602
|
- Code identifiers stay PascalCase in C# (`HumanResources`) but routes are kebab-case (`human-resources`)
|
|
603
603
|
|
|
@@ -612,24 +612,14 @@ private static string ToKebabCase(string value)
|
|
|
612
612
|
|
|
613
613
|
### SeedConstants Pattern
|
|
614
614
|
|
|
615
|
-
> **CRITICAL — NavigationContext IDs are NEVER generated.**
|
|
616
|
-
> Contexts (`business`, `platform`, `personal`) are pre-seeded by SmartStack core with hardcoded GUIDs.
|
|
617
|
-
> You MUST query the context by code at runtime in the SeedDataProvider:
|
|
618
|
-
> `var ctx = await db.NavigationContexts.FirstOrDefaultAsync(c => c.Code == "business", ct);`
|
|
619
|
-
> **FORBIDDEN:** `DeterministicGuid("nav:business")` or any ContextId constant in SeedConstants.
|
|
620
|
-
|
|
621
615
|
```csharp
|
|
622
616
|
public static class SeedConstants
|
|
623
617
|
{
|
|
624
618
|
// Deterministic GUIDs (SHA256-based, reproducible across environments)
|
|
625
619
|
// NOTE: Application/Module/Section/Resource IDs are deterministic.
|
|
626
|
-
|
|
627
|
-
public static readonly Guid
|
|
628
|
-
public static readonly Guid
|
|
629
|
-
public static readonly Guid SectionId = DeterministicGuid("nav:business.human-resources.employees.departments");
|
|
630
|
-
|
|
631
|
-
// FORBIDDEN — Context IDs are NOT deterministic, they come from SmartStack core:
|
|
632
|
-
// public static readonly Guid BusinessContextId = DeterministicGuid("nav:business"); // WRONG!
|
|
620
|
+
public static readonly Guid ApplicationId = DeterministicGuid("nav:human-resources");
|
|
621
|
+
public static readonly Guid ModuleId = DeterministicGuid("nav:human-resources.employees");
|
|
622
|
+
public static readonly Guid SectionId = DeterministicGuid("nav:human-resources.employees.departments");
|
|
633
623
|
|
|
634
624
|
private static Guid DeterministicGuid(string input)
|
|
635
625
|
{
|
|
@@ -647,30 +637,25 @@ public static class SeedConstants
|
|
|
647
637
|
### Navigation Seed Data Example
|
|
648
638
|
|
|
649
639
|
```csharp
|
|
650
|
-
//
|
|
651
|
-
var businessCtx = await db.NavigationContexts
|
|
652
|
-
.FirstOrDefaultAsync(c => c.Code == "business", ct);
|
|
653
|
-
if (businessCtx == null) return; // Context not yet seeded by SmartStack core
|
|
654
|
-
|
|
655
|
-
// Application: /business/human-resources
|
|
640
|
+
// Application: /human-resources
|
|
656
641
|
var app = NavigationApplication.Create(
|
|
657
|
-
|
|
642
|
+
"human-resources", "Human Resources", "HR Management",
|
|
658
643
|
"Users", IconType.Lucide,
|
|
659
|
-
"/
|
|
644
|
+
"/human-resources", // FULL PATH — starts with /, kebab-case
|
|
660
645
|
10);
|
|
661
646
|
|
|
662
|
-
// Module: /
|
|
647
|
+
// Module: /human-resources/employees
|
|
663
648
|
var module = NavigationModule.Create(
|
|
664
649
|
app.Id, "employees", "Employees", "Employee management",
|
|
665
650
|
"UserCheck", IconType.Lucide,
|
|
666
|
-
"/
|
|
651
|
+
"/human-resources/employees", // FULL PATH — includes parent
|
|
667
652
|
10);
|
|
668
653
|
|
|
669
|
-
// Section: /
|
|
654
|
+
// Section: /human-resources/employees/departments
|
|
670
655
|
var section = NavigationSection.Create(
|
|
671
656
|
module.Id, "departments", "Departments", "Manage departments",
|
|
672
657
|
"Building2", IconType.Lucide,
|
|
673
|
-
"/
|
|
658
|
+
"/human-resources/employees/departments", // FULL PATH
|
|
674
659
|
10);
|
|
675
660
|
```
|
|
676
661
|
|
|
@@ -678,10 +663,9 @@ var section = NavigationSection.Create(
|
|
|
678
663
|
|
|
679
664
|
| Mistake | Reality |
|
|
680
665
|
|---------|---------|
|
|
681
|
-
| `"humanresources"` as route | Must be `"/
|
|
682
|
-
| `"employees"` as route | Must be `"/
|
|
666
|
+
| `"humanresources"` as route | Must be `"/human-resources"` (full path, kebab-case) |
|
|
667
|
+
| `"employees"` as route | Must be `"/human-resources/employees"` (includes parent) |
|
|
683
668
|
| `Guid.NewGuid()` in seed data | Must use deterministic GUIDs (SHA256) |
|
|
684
|
-
| `DeterministicGuid("nav:business")` for ContextId | Context IDs are pre-seeded by SmartStack core — look up by code |
|
|
685
669
|
| Missing translations | Must have 4 languages: fr, en, it, de |
|
|
686
670
|
| Missing NavigationApplicationSeedData | Menu invisible without Application level |
|
|
687
671
|
|
|
@@ -747,9 +731,9 @@ services.AddValidatorsFromAssemblyContaining<Create{Name}DtoValidator>();
|
|
|
747
731
|
| `ICurrentUser` in service code | Does NOT exist — use `ICurrentUserService` + `ICurrentTenantService` |
|
|
748
732
|
| `_currentTenant.TenantId!.Value` | Crashes with 500 — use `?? throw new TenantContextRequiredException()` |
|
|
749
733
|
| `UnauthorizedAccessException("Tenant context is required")` | Returns 401 → clears frontend token. Use `TenantContextRequiredException()` (400) |
|
|
750
|
-
| Route `"humanresources"` in seed data | Must be full path `"/
|
|
734
|
+
| Route `"humanresources"` in seed data | Must be full path `"/human-resources"` |
|
|
751
735
|
| Route without leading `/` | All routes must start with `/` |
|
|
752
|
-
| `
|
|
736
|
+
| `humanresources.employees.read` in permissions | Permission segments MUST match NavRoute kebab-case: `human-resources.employees.read` |
|
|
753
737
|
| `Permission.Create()` | Does NOT exist — use `CreateForModule()`, `CreateForSection()`, etc. |
|
|
754
738
|
| `GetAllAsync()` without search param | ALL GetAll endpoints MUST support `?search=` for EntityLookup |
|
|
755
739
|
| `string Date` in DTO | Date-only fields MUST use `DateOnly`, NEVER `string` |
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
```tsx
|
|
16
16
|
// Named exports — use .then() to wrap
|
|
17
17
|
const EmployeesPage = lazy(() =>
|
|
18
|
-
import('@/pages/
|
|
18
|
+
import('@/pages/HumanResources/Employees/EmployeesPage')
|
|
19
19
|
.then(m => ({ default: m.EmployeesPage }))
|
|
20
20
|
);
|
|
21
21
|
|
|
@@ -32,7 +32,7 @@ import { PageLoader } from '@/components/ui/PageLoader';
|
|
|
32
32
|
// Route element wrapping
|
|
33
33
|
element: (
|
|
34
34
|
<Suspense fallback={<PageLoader />}>
|
|
35
|
-
<PermissionGuard permissions={ROUTES['
|
|
35
|
+
<PermissionGuard permissions={ROUTES['hr.employees'].permissions}>
|
|
36
36
|
<EmployeesPage />
|
|
37
37
|
</PermissionGuard>
|
|
38
38
|
</Suspense>
|
|
@@ -44,12 +44,12 @@ element: (
|
|
|
44
44
|
- **NEVER** static-import page components in route files
|
|
45
45
|
- **ALWAYS** use `<Suspense fallback={<PageLoader />}>` around lazy components
|
|
46
46
|
- **ALWAYS** use the `.then(m => ({ default: m.ComponentName }))` pattern for named exports
|
|
47
|
-
-
|
|
47
|
+
- The unified AppLayout component is ALSO lazy-loaded
|
|
48
48
|
|
|
49
49
|
**FORBIDDEN:**
|
|
50
50
|
```tsx
|
|
51
51
|
// WRONG: static import in route file
|
|
52
|
-
import { EmployeesPage } from '@/pages/
|
|
52
|
+
import { EmployeesPage } from '@/pages/HumanResources/Employees/EmployeesPage';
|
|
53
53
|
|
|
54
54
|
// WRONG: no Suspense wrapper
|
|
55
55
|
element: <EmployeesPage />
|
|
@@ -65,7 +65,7 @@ element: <EmployeesPage />
|
|
|
65
65
|
**CORRECT — Lazy imports in client App.tsx:**
|
|
66
66
|
```tsx
|
|
67
67
|
const ClientsListPage = lazy(() =>
|
|
68
|
-
import('@/pages/
|
|
68
|
+
import('@/pages/HumanResources/Clients/ClientsListPage')
|
|
69
69
|
.then(m => ({ default: m.ClientsListPage }))
|
|
70
70
|
);
|
|
71
71
|
```
|
|
@@ -73,7 +73,7 @@ const ClientsListPage = lazy(() =>
|
|
|
73
73
|
**FORBIDDEN — Static imports in client App.tsx:**
|
|
74
74
|
```tsx
|
|
75
75
|
// WRONG: Static import kills code splitting
|
|
76
|
-
import { ClientsListPage } from '@/pages/
|
|
76
|
+
import { ClientsListPage } from '@/pages/HumanResources/Clients/ClientsListPage';
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
> **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.
|
|
@@ -425,8 +425,8 @@ const handleTabClick = (tab: TabKey) => {
|
|
|
425
425
|
|
|
426
426
|
| Action | Route pattern | Page component | File location |
|
|
427
427
|
|--------|--------------|----------------|---------------|
|
|
428
|
-
| Create | `/{module}/create` | `EntityCreatePage` | `src/pages/{
|
|
429
|
-
| Edit | `/{module}/:id/edit` | `EntityEditPage` | `src/pages/{
|
|
428
|
+
| Create | `/{module}/create` | `EntityCreatePage` | `src/pages/{App}/{Module}/EntityCreatePage.tsx` |
|
|
429
|
+
| Edit | `/{module}/:id/edit` | `EntityEditPage` | `src/pages/{App}/{Module}/EntityEditPage.tsx` |
|
|
430
430
|
|
|
431
431
|
### Create Page Template
|
|
432
432
|
|
|
@@ -562,11 +562,11 @@ export function EntityEditPage() {
|
|
|
562
562
|
```tsx
|
|
563
563
|
// In route files — form pages are also lazy-loaded
|
|
564
564
|
const EntityCreatePage = lazy(() =>
|
|
565
|
-
import('@/pages/
|
|
565
|
+
import('@/pages/HumanResources/Employees/EntityCreatePage')
|
|
566
566
|
.then(m => ({ default: m.EntityCreatePage }))
|
|
567
567
|
);
|
|
568
568
|
const EntityEditPage = lazy(() =>
|
|
569
|
-
import('@/pages/
|
|
569
|
+
import('@/pages/HumanResources/Employees/EntityEditPage')
|
|
570
570
|
.then(m => ({ default: m.EntityEditPage }))
|
|
571
571
|
);
|
|
572
572
|
|
|
@@ -610,7 +610,7 @@ const EntityEditPage = lazy(() =>
|
|
|
610
610
|
// PermissionGuard for section-level routes
|
|
611
611
|
element: (
|
|
612
612
|
<Suspense fallback={<PageLoader />}>
|
|
613
|
-
<PermissionGuard permissions={ROUTES['
|
|
613
|
+
<PermissionGuard permissions={ROUTES['app.module.section'].permissions}>
|
|
614
614
|
<SectionPage />
|
|
615
615
|
</PermissionGuard>
|
|
616
616
|
</Suspense>
|
|
@@ -742,7 +742,7 @@ interface EntityLookupOption {
|
|
|
742
742
|
}
|
|
743
743
|
|
|
744
744
|
interface EntityLookupProps {
|
|
745
|
-
/** API endpoint to search entities (e.g., '/api/
|
|
745
|
+
/** API endpoint to search entities (e.g., '/api/human-resources/employees') */
|
|
746
746
|
apiEndpoint: string;
|
|
747
747
|
/** Currently selected entity ID */
|
|
748
748
|
value: string | null;
|
|
@@ -948,7 +948,7 @@ import { EntityLookup } from '@/components/ui/EntityLookup';
|
|
|
948
948
|
|
|
949
949
|
// Inside the form:
|
|
950
950
|
<EntityLookup
|
|
951
|
-
apiEndpoint="/api/
|
|
951
|
+
apiEndpoint="/api/human-resources/employees"
|
|
952
952
|
value={formData.employeeId}
|
|
953
953
|
onChange={(id) => handleChange('employeeId', id)}
|
|
954
954
|
label={t('module:form.employee', 'Employee')}
|
|
@@ -964,7 +964,7 @@ import { EntityLookup } from '@/components/ui/EntityLookup';
|
|
|
964
964
|
|
|
965
965
|
// For DepartmentId FK:
|
|
966
966
|
<EntityLookup
|
|
967
|
-
apiEndpoint="/api/
|
|
967
|
+
apiEndpoint="/api/human-resources/departments"
|
|
968
968
|
value={formData.departmentId}
|
|
969
969
|
onChange={(id) => handleChange('departmentId', id)}
|
|
970
970
|
label={t('module:form.department', 'Department')}
|
|
@@ -1077,7 +1077,7 @@ public async Task<PaginatedResult<EntityResponseDto>> GetAllAsync(
|
|
|
1077
1077
|
**CORRECT — ONLY this pattern:**
|
|
1078
1078
|
```tsx
|
|
1079
1079
|
<EntityLookup
|
|
1080
|
-
apiEndpoint="/api/
|
|
1080
|
+
apiEndpoint="/api/human-resources/departments"
|
|
1081
1081
|
value={formData.departmentId}
|
|
1082
1082
|
onChange={(id) => handleChange('departmentId', id)}
|
|
1083
1083
|
label={t('module:form.department', 'Department')}
|
|
@@ -1156,7 +1156,7 @@ The `DocRenderer` shared component renders all 8 documentation sections (overvie
|
|
|
1156
1156
|
If the automatic route mapping doesn't work for your module, pass a custom URL:
|
|
1157
1157
|
|
|
1158
1158
|
```tsx
|
|
1159
|
-
<DocToggleButton customDocUrl="/docs/
|
|
1159
|
+
<DocToggleButton customDocUrl="/docs/human-resources/employees" />
|
|
1160
1160
|
```
|
|
1161
1161
|
|
|
1162
1162
|
### Rules
|
|
@@ -1181,7 +1181,7 @@ Before marking frontend tasks as complete, verify:
|
|
|
1181
1181
|
- [ ] No hardcoded strings in JSX — all text goes through `t()`
|
|
1182
1182
|
- [ ] CSS uses variables only — no hardcoded Tailwind colors (BLOCKING POST-CHECK 13)
|
|
1183
1183
|
- [ ] Pages follow loading → error → content pattern
|
|
1184
|
-
- [ ] Pages use `src/pages/{
|
|
1184
|
+
- [ ] Pages use `src/pages/{App}/{Module}/` hierarchy
|
|
1185
1185
|
- [ ] API calls use generated hooks or `apiClient` (never raw axios)
|
|
1186
1186
|
- [ ] Components use SmartTable/SmartFilter/EntityCard (never raw HTML tables)
|
|
1187
1187
|
- [ ] **FK fields use `EntityLookup` — ZERO plain text inputs for Guid FK fields**
|
|
@@ -1470,7 +1470,7 @@ And in the module-specific translation files (e.g., `employees.json`):
|
|
|
1470
1470
|
### Test File Convention
|
|
1471
1471
|
|
|
1472
1472
|
```
|
|
1473
|
-
src/pages/{
|
|
1473
|
+
src/pages/{App}/{Module}/
|
|
1474
1474
|
├── EntityCreatePage.tsx
|
|
1475
1475
|
├── EntityCreatePage.test.tsx ← MANDATORY
|
|
1476
1476
|
├── EntityEditPage.tsx
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
## Layer 0 — Domain (sequential)
|
|
9
9
|
|
|
10
|
-
**Entities:** `Domain/Entities/{
|
|
11
|
-
**Enums:** `Domain/Enums/{
|
|
12
|
-
**Exceptions:** `Domain/Exceptions/{
|
|
10
|
+
**Entities:** `Domain/Entities/{App}/{Module}/`
|
|
11
|
+
**Enums:** `Domain/Enums/{App}/{Module}/`
|
|
12
|
+
**Exceptions:** `Domain/Exceptions/{App}/{Module}/`
|
|
13
13
|
|
|
14
14
|
| Action | Tool |
|
|
15
15
|
|--------|------|
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
## Layer 0 — Infrastructure: EF Core (sequential)
|
|
34
34
|
|
|
35
|
-
**Configs:** `Infrastructure/Persistence/Configurations/{
|
|
35
|
+
**Configs:** `Infrastructure/Persistence/Configurations/{App}/{Module}/`
|
|
36
36
|
**Migrations:** `Infrastructure/Persistence/Migrations/` (NEVER subdirectories)
|
|
37
37
|
|
|
38
38
|
| Action | Tool |
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
|
|
61
61
|
## Layer 1 — Application (parallel with API)
|
|
62
62
|
|
|
63
|
-
**Services:** `Application/Services/{
|
|
64
|
-
**Service impls:** `Infrastructure/Services/{
|
|
65
|
-
**DTOs:** `Application/DTOs/{
|
|
66
|
-
**Validators:** `Application/Validators/{
|
|
63
|
+
**Services:** `Application/Services/{App}/{Module}/` (interface)
|
|
64
|
+
**Service impls:** `Infrastructure/Services/{App}/{Module}/` (implementation)
|
|
65
|
+
**DTOs:** `Application/DTOs/{App}/{Module}/`
|
|
66
|
+
**Validators:** `Application/Validators/{App}/{Module}/`
|
|
67
67
|
|
|
68
68
|
| Action | Tool |
|
|
69
69
|
|--------|------|
|
|
@@ -92,14 +92,7 @@
|
|
|
92
92
|
|
|
93
93
|
## Layer 1 — API (parallel with Application)
|
|
94
94
|
|
|
95
|
-
**Controllers:** `Api/Controllers/{
|
|
96
|
-
|
|
97
|
-
| Context | Controller Folder |
|
|
98
|
-
|---------|-------------------|
|
|
99
|
-
| `platform.administration` | `Admin` |
|
|
100
|
-
| `platform.support` | `Support` |
|
|
101
|
-
| `business.*` | `Business` |
|
|
102
|
-
| `personal.*` | `User` |
|
|
95
|
+
**Controllers:** `Api/Controllers/{AppPascal}/{Entity}Controller.cs`
|
|
103
96
|
|
|
104
97
|
| Action | Tool |
|
|
105
98
|
|--------|------|
|
|
@@ -110,13 +103,13 @@
|
|
|
110
103
|
**Rules:**
|
|
111
104
|
- `[RequirePermission(Permissions.{Module}.{Action})]` on EVERY endpoint
|
|
112
105
|
- **NavRoute values MUST use kebab-case for ALL multi-word segments:**
|
|
113
|
-
- `[NavRoute("
|
|
114
|
-
- `[NavRoute("
|
|
115
|
-
- `[NavRoute("
|
|
116
|
-
- `[NavRoute("
|
|
117
|
-
- Permission paths MUST use kebab-case matching NavRoute codes (e.g., `
|
|
106
|
+
- `[NavRoute("human-resources.employees")]` (CORRECT)
|
|
107
|
+
- `[NavRoute("humanresources.employees")]` (WRONG — missing hyphens)
|
|
108
|
+
- `[NavRoute("project-management.projects")]` (CORRECT)
|
|
109
|
+
- `[NavRoute("projectmanagement.projects")]` (WRONG)
|
|
110
|
+
- Permission paths MUST use kebab-case matching NavRoute codes (e.g., `human-resources.employees.read`)
|
|
118
111
|
- FORBIDDEN: concatenated segments like `humanresources` — must be `human-resources`
|
|
119
|
-
- POST-CHECK 48 detects non-kebab-case NavRoute values. POST-CHECK 41 detects non-kebab-case permissions
|
|
112
|
+
- POST-CHECK 48 detects non-kebab-case NavRoute values. POST-CHECK 41 detects non-kebab-case permissions
|
|
120
113
|
- **FORBIDDEN:** `[Route("api/...")]` alongside `[NavRoute]` — causes 404s (POST-CHECK 50)
|
|
121
114
|
- `[NavRoute]` is the ONLY route attribute needed — resolves routes from DB at startup
|
|
122
115
|
- NEVER use `[Authorize]` without specific permission
|
|
@@ -130,7 +123,7 @@
|
|
|
130
123
|
**Folder:** `Infrastructure/Persistence/Seeding/Data/{ModulePascal}/`
|
|
131
124
|
|
|
132
125
|
> **Detailed templates:** See ralph-loop `references/core-seed-data.md` for complete C# code templates.
|
|
133
|
-
> Navigation hierarchy:
|
|
126
|
+
> Navigation hierarchy: Application → Module → Section → Resource (ALL levels need seed data).
|
|
134
127
|
|
|
135
128
|
| Action | Tool |
|
|
136
129
|
|--------|------|
|
|
@@ -163,20 +156,11 @@
|
|
|
163
156
|
|
|
164
157
|
### Deterministic GUID Pattern
|
|
165
158
|
|
|
166
|
-
> **CRITICAL — NavigationContext IDs are NEVER generated.**
|
|
167
|
-
> Contexts (`business`, `platform`, `personal`) are pre-seeded by SmartStack core with hardcoded GUIDs.
|
|
168
|
-
> Look up the context at runtime: `db.NavigationContexts.FirstOrDefaultAsync(c => c.Code == "business", ct)`
|
|
169
|
-
> **FORBIDDEN:** `GenerateDeterministicGuid("nav:business")` or any ContextId in SeedConstants.
|
|
170
|
-
|
|
171
159
|
```csharp
|
|
172
160
|
// Use SHA256 for deterministic GUIDs (reproducible across environments)
|
|
173
161
|
// NOTE: Application/Module/Section/Resource IDs are deterministic.
|
|
174
|
-
// Context IDs are NOT — they are pre-seeded by SmartStack core.
|
|
175
162
|
public static readonly Guid ModuleId = GenerateDeterministicGuid("nav-module-{app}-{module}");
|
|
176
163
|
|
|
177
|
-
// FORBIDDEN — Context IDs must NOT be generated:
|
|
178
|
-
// public static readonly Guid BusinessContextId = GenerateDeterministicGuid("nav:business"); // WRONG!
|
|
179
|
-
|
|
180
164
|
private static Guid GenerateDeterministicGuid(string input)
|
|
181
165
|
{
|
|
182
166
|
var hash = System.Security.Cryptography.SHA256.HashData(
|
|
@@ -192,19 +176,18 @@ private static Guid GenerateDeterministicGuid(string input)
|
|
|
192
176
|
> **Routes stored in DB drive the platform menu AND application-tracking.**
|
|
193
177
|
> Short routes (e.g., `humanresources`) cause **400 Bad Request** on every page navigation.
|
|
194
178
|
|
|
195
|
-
**Route format: `/{
|
|
179
|
+
**Route format: `/{app-kebab}/{module-kebab}/{section-kebab}`**
|
|
196
180
|
|
|
197
181
|
| Level | Code (C#) | Route (DB) |
|
|
198
182
|
|-------|-----------|-----------|
|
|
199
|
-
| Application | `human-resources` | `/
|
|
200
|
-
| Module | `employees` | `/
|
|
201
|
-
| Section | `departments` | `/
|
|
202
|
-
| Resource | `export` | `/
|
|
183
|
+
| Application | `human-resources` | `/human-resources` |
|
|
184
|
+
| Module | `employees` | `/human-resources/employees` |
|
|
185
|
+
| Section | `departments` | `/human-resources/employees/departments` |
|
|
186
|
+
| Resource | `export` | `/human-resources/employees/departments/export` |
|
|
203
187
|
|
|
204
|
-
**
|
|
205
|
-
- `/
|
|
206
|
-
- `/
|
|
207
|
-
- `/personal/myspace/profile` (not `profile`)
|
|
188
|
+
**Examples (verified from SmartStack.app):**
|
|
189
|
+
- `/administration` (not `administration` without `/`)
|
|
190
|
+
- `/administration/users` (not `users`)
|
|
208
191
|
|
|
209
192
|
- PascalCase for C# code identifiers (`HumanResources`)
|
|
210
193
|
- **kebab-case** for ALL URL routes in seed data (`human-resources`)
|
|
@@ -216,32 +199,31 @@ private static string ToKebabCase(string value)
|
|
|
216
199
|
=> System.Text.RegularExpressions.Regex.Replace(value, "([a-z])([A-Z])", "$1-$2").ToLowerInvariant();
|
|
217
200
|
|
|
218
201
|
// Route construction:
|
|
219
|
-
var appRoute = $"/{ToKebabCase(
|
|
220
|
-
// → "/
|
|
202
|
+
var appRoute = $"/{ToKebabCase(appCode)}";
|
|
203
|
+
// → "/human-resources"
|
|
221
204
|
|
|
222
205
|
var moduleRoute = $"{appRoute}/{ToKebabCase(moduleCode)}";
|
|
223
|
-
// → "/
|
|
206
|
+
// → "/human-resources/employees"
|
|
224
207
|
|
|
225
208
|
var sectionRoute = $"{moduleRoute}/{ToKebabCase(sectionCode)}";
|
|
226
|
-
// → "/
|
|
209
|
+
// → "/human-resources/employees/departments"
|
|
227
210
|
```
|
|
228
211
|
|
|
229
212
|
**ROUTE SPECIAL CASES (list and detail sections):**
|
|
230
213
|
> `list` and `detail` are view modes of the module, NOT functional sub-areas.
|
|
231
|
-
> - `list` section route = module route (e.g., `/
|
|
232
|
-
> - `detail` section route = module route + `/:id` (e.g., `/
|
|
214
|
+
> - `list` section route = module route (e.g., `/human-resources/employees`) — NO `/list` suffix
|
|
215
|
+
> - `detail` section route = module route + `/:id` (e.g., `/human-resources/employees/:id`) — NOT `/detail/:id`
|
|
233
216
|
> - FORBIDDEN: `/employees/list`, `/employees/detail/:id`
|
|
234
217
|
> - Other sections (dashboard, approve, import) = module route + `/{section-kebab}` (normal)
|
|
235
218
|
|
|
236
219
|
**FORBIDDEN:**
|
|
237
220
|
- `Guid.NewGuid()` → use deterministic GUIDs (SHA256)
|
|
238
|
-
- `DeterministicGuid("nav:business")` for ContextId → context IDs are pre-seeded by SmartStack core, look up by code at runtime
|
|
239
221
|
- Missing translations (must have fr, en, it, de)
|
|
240
222
|
- Empty seed classes with no seeding logic
|
|
241
223
|
- PascalCase in route URLs → always kebab-case
|
|
242
224
|
- Missing NavigationApplicationSeedData → menu invisible
|
|
243
|
-
- **Short routes without `/` prefix** → `"humanresources"` must be `"/
|
|
244
|
-
- **Routes without parent hierarchy** → `"employees"` must be `"/
|
|
225
|
+
- **Short routes without `/` prefix** → `"humanresources"` must be `"/human-resources"`
|
|
226
|
+
- **Routes without parent hierarchy** → `"employees"` must be `"/human-resources/employees"`
|
|
245
227
|
|
|
246
228
|
---
|
|
247
229
|
|
|
@@ -249,7 +231,7 @@ var sectionRoute = $"{moduleRoute}/{ToKebabCase(sectionCode)}";
|
|
|
249
231
|
|
|
250
232
|
> **Detailed patterns:** See `references/smartstack-frontend.md` for complete code templates.
|
|
251
233
|
|
|
252
|
-
**Pages:** `src/pages/{
|
|
234
|
+
**Pages:** `src/pages/{AppPascal}/{Module}/`
|
|
253
235
|
**Components:** `src/components/{Module}/`
|
|
254
236
|
|
|
255
237
|
| Action | Tool |
|
|
@@ -259,13 +241,7 @@ var sectionRoute = $"{moduleRoute}/{ToKebabCase(sectionCode)}";
|
|
|
259
241
|
| Complex pages | /ui-components skill + `smartstack-frontend.md` patterns |
|
|
260
242
|
| Validate routes | MCP `validate_frontend_routes` |
|
|
261
243
|
|
|
262
|
-
**Layout mapping:**
|
|
263
|
-
|
|
264
|
-
| Context | Layout | Route prefix |
|
|
265
|
-
|---------|--------|-------------|
|
|
266
|
-
| `platform.*` | `AdminLayout` | `/platform` |
|
|
267
|
-
| `business.*` | `BusinessLayout` | `/business` |
|
|
268
|
-
| `personal.*` | `UserLayout` | `/personal/myspace` |
|
|
244
|
+
**Layout mapping:** Configured per application in the routing configuration.
|
|
269
245
|
|
|
270
246
|
### Lazy Loading (MANDATORY)
|
|
271
247
|
|
|
@@ -273,7 +249,7 @@ ALL page components MUST be lazy-loaded using `React.lazy()`:
|
|
|
273
249
|
|
|
274
250
|
```tsx
|
|
275
251
|
const EmployeesPage = lazy(() =>
|
|
276
|
-
import('@/pages/
|
|
252
|
+
import('@/pages/HumanResources/Employees/EmployeesPage')
|
|
277
253
|
.then(m => ({ default: m.EmployeesPage }))
|
|
278
254
|
);
|
|
279
255
|
|
|
@@ -326,7 +302,7 @@ If the module defines `{sections}`, generate frontend routes for EACH section as
|
|
|
326
302
|
{ path: '{section-kebab}/:id/edit', element: <Suspense fallback={<PageLoader />}><Edit{Section}Page /></Suspense> },
|
|
327
303
|
```
|
|
328
304
|
|
|
329
|
-
Section pages live in `src/pages/{
|
|
305
|
+
Section pages live in `src/pages/{AppPascal}/{Module}/{Section}/`.
|
|
330
306
|
|
|
331
307
|
### FK Fields in Forms (CRITICAL)
|
|
332
308
|
|
|
@@ -335,7 +311,7 @@ Any entity property that is a FK Guid (e.g., `EmployeeId`, `DepartmentId`) MUST
|
|
|
335
311
|
```tsx
|
|
336
312
|
// CORRECT — EntityLookup for FK field (ONLY acceptable pattern)
|
|
337
313
|
<EntityLookup
|
|
338
|
-
apiEndpoint="/api/
|
|
314
|
+
apiEndpoint="/api/human-resources/employees"
|
|
339
315
|
value={formData.employeeId}
|
|
340
316
|
onChange={(id) => handleChange('employeeId', id)}
|
|
341
317
|
label={t('module:form.employee', 'Employee')}
|
|
@@ -358,7 +334,7 @@ Any entity property that is a FK Guid (e.g., `EmployeeId`, `DepartmentId`) MUST
|
|
|
358
334
|
See `references/smartstack-frontend.md` section 6 for the full `EntityLookup` component definition and usage patterns.
|
|
359
335
|
|
|
360
336
|
**FORBIDDEN:**
|
|
361
|
-
- `src/pages/{Module}/` (flat, missing
|
|
337
|
+
- `src/pages/{Module}/` (flat, missing App)
|
|
362
338
|
- `import axios` → use `@/services/api/apiClient`
|
|
363
339
|
- `<table>` → use SmartTable
|
|
364
340
|
- `<input type="text">` for FK Guid fields → use `EntityLookup`
|