@atlashub/smartstack-cli 3.8.0 → 3.10.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 +365 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/templates/agents/action.md +1 -0
- package/templates/agents/ba-writer.md +211 -0
- package/templates/agents/explore-codebase.md +1 -0
- package/templates/agents/explore-docs.md +1 -0
- package/templates/agents/fix-grammar.md +1 -0
- package/templates/agents/snipper.md +1 -0
- package/templates/skills/admin/SKILL.md +6 -0
- package/templates/skills/ai-prompt/SKILL.md +32 -136
- package/templates/skills/ai-prompt/steps/step-01-implementation.md +122 -0
- package/templates/skills/apex/SKILL.md +120 -0
- package/templates/skills/apex/_shared.md +86 -0
- package/templates/skills/apex/references/agent-teams-protocol.md +164 -0
- package/templates/skills/apex/references/smartstack-layers.md +173 -0
- package/templates/skills/apex/steps/step-00-init.md +156 -0
- package/templates/skills/apex/steps/step-01-analyze.md +169 -0
- package/templates/skills/apex/steps/step-02-plan.md +160 -0
- package/templates/skills/apex/steps/step-03-execute.md +166 -0
- package/templates/skills/apex/steps/step-04-validate.md +138 -0
- package/templates/skills/apex/steps/step-05-examine.md +124 -0
- package/templates/skills/apex/steps/step-06-resolve.md +105 -0
- package/templates/skills/apex/steps/step-07-tests.md +130 -0
- package/templates/skills/apex/steps/step-08-run-tests.md +115 -0
- package/templates/skills/application/SKILL.md +10 -0
- package/templates/skills/application/references/application-roles-template.md +227 -0
- package/templates/skills/application/references/backend-controller-hierarchy.md +58 -0
- package/templates/skills/application/references/backend-entity-seeding.md +72 -0
- package/templates/skills/application/references/backend-verification.md +88 -0
- package/templates/skills/application/references/frontend-verification.md +111 -0
- package/templates/skills/application/references/nav-fallback-procedure.md +200 -0
- package/templates/skills/application/references/provider-template.md +158 -0
- package/templates/skills/application/references/test-frontend.md +73 -0
- package/templates/skills/application/references/test-prerequisites.md +72 -0
- package/templates/skills/application/steps/step-01-navigation.md +7 -198
- package/templates/skills/application/steps/step-03-roles.md +45 -7
- package/templates/skills/application/steps/step-03b-provider.md +15 -132
- package/templates/skills/application/steps/step-04-backend.md +20 -350
- package/templates/skills/application/steps/step-05-frontend.md +12 -101
- package/templates/skills/application/steps/step-07-tests.md +12 -132
- package/templates/skills/business-analyse/SKILL.md +67 -6
- package/templates/skills/business-analyse/html/ba-interactive.html +176 -14
- package/templates/skills/business-analyse/html/src/scripts/01-data-init.js +1 -0
- package/templates/skills/business-analyse/html/src/scripts/05-render-specs.js +16 -4
- package/templates/skills/business-analyse/html/src/scripts/06-render-consolidation.js +7 -2
- package/templates/skills/business-analyse/html/src/scripts/09-export.js +103 -0
- package/templates/skills/business-analyse/html/src/scripts/10-comments.js +12 -6
- package/templates/skills/business-analyse/html/src/scripts/11-review-panel.js +24 -2
- package/templates/skills/business-analyse/html/src/styles/08-review-panel.css +12 -0
- package/templates/skills/business-analyse/html/src/template.html +1 -0
- package/templates/skills/business-analyse/references/agent-pooling-best-practices.md +477 -0
- package/templates/skills/business-analyse/references/cache-warming-strategy.md +578 -0
- package/templates/skills/business-analyse/references/cadrage-structure-cards.md +78 -0
- package/templates/skills/business-analyse/references/cadrage-vibe-coding.md +97 -0
- package/templates/skills/business-analyse/references/consolidation-structural-checks.md +92 -0
- package/templates/skills/business-analyse/references/deploy-data-build.md +121 -0
- package/templates/skills/business-analyse/references/deploy-modes.md +49 -0
- package/templates/skills/business-analyse/references/handoff-file-templates.md +119 -0
- package/templates/skills/business-analyse/references/handoff-mappings.md +81 -0
- package/templates/skills/business-analyse/references/html-data-mapping.md +10 -2
- package/templates/skills/business-analyse/references/init-schema-deployment.md +65 -0
- package/templates/skills/business-analyse/references/review-data-mapping.md +363 -0
- package/templates/skills/business-analyse/references/robustness-checks.md +538 -0
- package/templates/skills/business-analyse/references/spec-auto-inference.md +57 -0
- package/templates/skills/business-analyse/references/ui-dashboard-spec.md +85 -0
- package/templates/skills/business-analyse/references/ui-resource-cards.md +110 -0
- package/templates/skills/business-analyse/references/validate-incremental-html.md +55 -0
- package/templates/skills/business-analyse/schemas/sections/specification-schema.json +33 -1
- package/templates/skills/business-analyse/steps/step-00-init.md +186 -53
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +5 -194
- package/templates/skills/business-analyse/steps/step-03a-data.md +42 -49
- package/templates/skills/business-analyse/steps/step-03b-ui.md +12 -178
- package/templates/skills/business-analyse/steps/step-03c-compile.md +71 -2
- package/templates/skills/business-analyse/steps/step-03d-validate.md +277 -48
- package/templates/skills/business-analyse/steps/step-04-consolidation.md +175 -104
- package/templates/skills/business-analyse/steps/step-05a-handoff.md +66 -438
- package/templates/skills/business-analyse/steps/step-05b-deploy.md +35 -184
- package/templates/skills/business-analyse/steps/step-05c-ralph-readiness.md +526 -0
- package/templates/skills/business-analyse/steps/step-06-review.md +277 -0
- package/templates/skills/cc-agent/references/agent-behavior-patterns.md +95 -0
- package/templates/skills/cc-agent/steps/step-02-generate.md +5 -78
- package/templates/skills/check-version/SKILL.md +7 -0
- package/templates/skills/controller/references/controller-code-templates.md +159 -0
- package/templates/skills/controller/references/permission-sync-templates.md +152 -0
- package/templates/skills/controller/steps/step-03-generate.md +166 -158
- package/templates/skills/controller/steps/step-04-perms.md +5 -144
- package/templates/skills/controller/templates.md +11 -2
- package/templates/skills/debug/SKILL.md +7 -0
- package/templates/skills/explore/SKILL.md +6 -0
- package/templates/skills/feature-full/SKILL.md +39 -142
- package/templates/skills/feature-full/steps/step-01-implementation.md +120 -0
- package/templates/skills/gitflow/references/init-config-template.md +135 -0
- package/templates/skills/gitflow/references/init-name-normalization.md +103 -0
- package/templates/skills/gitflow/references/plan-template.md +69 -0
- package/templates/skills/gitflow/references/start-efcore-preflight.md +70 -0
- package/templates/skills/gitflow/references/start-local-config.md +110 -0
- package/templates/skills/gitflow/steps/step-init.md +18 -289
- package/templates/skills/gitflow/steps/step-plan.md +6 -63
- package/templates/skills/gitflow/steps/step-start.md +16 -126
- package/templates/skills/mcp/SKILL.md +9 -213
- package/templates/skills/mcp/steps/step-01-healthcheck.md +108 -0
- package/templates/skills/mcp/steps/step-02-tools.md +73 -0
- package/templates/skills/notification/SKILL.md +7 -0
- package/templates/skills/quick-search/SKILL.md +5 -0
- package/templates/skills/ralph-loop/SKILL.md +99 -381
- package/templates/skills/ralph-loop/references/category-rules.md +259 -0
- package/templates/skills/ralph-loop/references/compact-loop.md +182 -0
- package/templates/skills/ralph-loop/references/core-seed-data.md +173 -21
- package/templates/skills/ralph-loop/references/task-transform-legacy.md +259 -0
- package/templates/skills/ralph-loop/references/team-orchestration.md +189 -0
- package/templates/skills/ralph-loop/steps/step-00-init.md +111 -383
- package/templates/skills/ralph-loop/steps/step-01-task.md +79 -896
- package/templates/skills/ralph-loop/steps/step-02-execute.md +68 -680
- package/templates/skills/ralph-loop/steps/step-03-commit.md +47 -277
- package/templates/skills/ralph-loop/steps/step-04-check.md +124 -607
- package/templates/skills/ralph-loop/steps/step-05-report.md +68 -367
- package/templates/skills/refactor/SKILL.md +12 -176
- package/templates/skills/refactor/steps/step-01-discover.md +60 -0
- package/templates/skills/refactor/steps/step-02-execute.md +67 -0
- package/templates/skills/review-code/SKILL.md +19 -257
- package/templates/skills/review-code/steps/step-01-smartstack.md +96 -0
- package/templates/skills/review-code/steps/step-02-detailed-review.md +80 -0
- package/templates/skills/review-code/steps/step-03-react.md +44 -0
- package/templates/skills/ui-components/SKILL.md +7 -0
- package/templates/skills/utils/SKILL.md +6 -0
- package/templates/skills/validate/SKILL.md +6 -0
- package/templates/skills/validate-feature/SKILL.md +8 -0
- package/templates/skills/workflow/SKILL.md +40 -118
- package/templates/skills/workflow/steps/step-01-implementation.md +84 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Controller NavRoute and Folder Hierarchy
|
|
2
|
+
|
|
3
|
+
> Referenced from `steps/step-04-backend.md` — Controller file organization and NavRoute conventions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Controller File Location
|
|
8
|
+
|
|
9
|
+
Controllers are organized by **context short name** and **application** (matching SmartStack.app pattern):
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Api/Controllers/
|
|
13
|
+
├── Admin/ ← platform.administration
|
|
14
|
+
│ ├── {Application}/ ← Application sub-folder (e.g., AI/, Communications/, Tenants/)
|
|
15
|
+
│ │ └── {EntityName}Controller.cs
|
|
16
|
+
│ └── {EntityName}Controller.cs ← Direct controllers (no application sub-folder)
|
|
17
|
+
├── Business/ ← business.*
|
|
18
|
+
│ └── {EntityName}Controller.cs
|
|
19
|
+
├── Support/ ← platform.support
|
|
20
|
+
│ └── {EntityName}Controller.cs
|
|
21
|
+
├── User/ ← personal.*
|
|
22
|
+
│ └── {EntityName}Controller.cs
|
|
23
|
+
└── {SharedControllers}.cs ← Root-level (Auth, Config, Navigation, etc.)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Context-to-Folder Mapping
|
|
27
|
+
|
|
28
|
+
| NavRoute Context | Controller Folder | Example |
|
|
29
|
+
|-----------------|-------------------|---------|
|
|
30
|
+
| `platform.administration` | `Admin` | `Controllers/Admin/TenantsController.cs` |
|
|
31
|
+
| `platform.administration.{app}` | `Admin/{App}` | `Controllers/Admin/AI/AiPromptsController.cs` |
|
|
32
|
+
| `platform.support` | `Support` | `Controllers/Support/TicketsController.cs` |
|
|
33
|
+
| `business.*` | `Business` | `Controllers/Business/MyTicketsController.cs` |
|
|
34
|
+
| `personal.*` | `User` | `Controllers/User/PreferencesController.cs` |
|
|
35
|
+
|
|
36
|
+
## Controller Attributes
|
|
37
|
+
|
|
38
|
+
The generated controller uses NavRoute attribute:
|
|
39
|
+
|
|
40
|
+
```csharp
|
|
41
|
+
[NavRoute("{full_path}")]
|
|
42
|
+
[ApiController]
|
|
43
|
+
[Authorize]
|
|
44
|
+
public class {EntityName}Controller : ControllerBase
|
|
45
|
+
{
|
|
46
|
+
[HttpGet]
|
|
47
|
+
[RequirePermission(Permissions.{Context}.{Application}.{Module}.Read)]
|
|
48
|
+
public async Task<ActionResult<IEnumerable<{EntityName}Dto>>> GetAll() { ... }
|
|
49
|
+
|
|
50
|
+
// ... other CRUD methods
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This ensures:
|
|
55
|
+
- API route is derived from navigation path
|
|
56
|
+
- Permissions use the constants from Permissions.cs
|
|
57
|
+
- Frontend can discover API path from NavRoute registry
|
|
58
|
+
- Controller file is in the correct context/application folder
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Entity Seeding Pattern
|
|
2
|
+
|
|
3
|
+
> Reference: See `templates-seed.md` section "TEMPLATE: ENTITY SEED DATA (SeedData Provider)"
|
|
4
|
+
|
|
5
|
+
## SeedData File
|
|
6
|
+
|
|
7
|
+
**`Infrastructure/Persistence/Seeding/Data/{Domain}/{EntityName}SeedData.cs`**
|
|
8
|
+
|
|
9
|
+
Follow SmartStack.app pattern:
|
|
10
|
+
- Static class with `internal static IEnumerable<{EntityName}SeedItem> GetAll{EntityName}s()`
|
|
11
|
+
- Use deterministic GUIDs (NEVER `Guid.NewGuid()`)
|
|
12
|
+
- Include 3-5 sample entities with varied, realistic data
|
|
13
|
+
- For multi-tenant: organize by tenant using `GetTenant1{EntityName}s()` helpers
|
|
14
|
+
|
|
15
|
+
```csharp
|
|
16
|
+
public static class {EntityName}SeedData
|
|
17
|
+
{
|
|
18
|
+
public static readonly Guid Sample1Id = Guid.Parse("...");
|
|
19
|
+
public static readonly Guid Sample2Id = Guid.Parse("...");
|
|
20
|
+
public static readonly Guid Sample3Id = Guid.Parse("...");
|
|
21
|
+
|
|
22
|
+
internal static IEnumerable<{EntityName}SeedItem> GetAll{EntityName}s()
|
|
23
|
+
{
|
|
24
|
+
return new[]
|
|
25
|
+
{
|
|
26
|
+
new {EntityName}SeedItem { Id = Sample1Id, /* ... */ },
|
|
27
|
+
new {EntityName}SeedItem { Id = Sample2Id, /* ... */ },
|
|
28
|
+
new {EntityName}SeedItem { Id = Sample3Id, /* ... */ }
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
internal class {EntityName}SeedItem
|
|
34
|
+
{
|
|
35
|
+
public Guid Id { get; init; }
|
|
36
|
+
// ... all required entity properties
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## DevDataSeeder Update
|
|
41
|
+
|
|
42
|
+
Add to `Infrastructure/Persistence/Seeding/DevDataSeeder.cs`:
|
|
43
|
+
- `using` for the new SeedData namespace
|
|
44
|
+
- `await Seed{EntityName}sAsync(cancellationToken);` in `SeedAsync()` method
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
private async Task Seed{EntityName}sAsync(CancellationToken cancellationToken)
|
|
48
|
+
{
|
|
49
|
+
_logger.LogInformation("Seeding demo {EntityName}s...");
|
|
50
|
+
|
|
51
|
+
var existingCount = await _context.{EntityName}s.CountAsync(cancellationToken);
|
|
52
|
+
if (existingCount > 0)
|
|
53
|
+
{
|
|
54
|
+
_logger.LogWarning("{EntityName}s already seeded ({Count} exist), skipping.", existingCount);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var createdCount = 0;
|
|
59
|
+
foreach (var seedItem in {EntityName}SeedData.GetAll{EntityName}s())
|
|
60
|
+
{
|
|
61
|
+
var entity = {EntityName}.Create(/* map seedItem properties */);
|
|
62
|
+
typeof({EntityName}).GetProperty("Id")?.SetValue(entity, seedItem.Id);
|
|
63
|
+
_context.{EntityName}s.Add(entity);
|
|
64
|
+
createdCount++;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (createdCount > 0)
|
|
68
|
+
await _context.SaveChangesAsync(cancellationToken);
|
|
69
|
+
|
|
70
|
+
_logger.LogInformation("Created {Count} demo {EntityName}s.", createdCount);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Backend Post-Generation Verification
|
|
2
|
+
|
|
3
|
+
**Run ALL checks before proceeding to next step.**
|
|
4
|
+
|
|
5
|
+
## Check 1: Backend Build (BLOCKING)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
dotnet build {SolutionName}.sln --no-restore
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
IF build fails: Read errors, fix compilation issues, re-run until success.
|
|
12
|
+
|
|
13
|
+
## Check 2: DbSet Registration (BLOCKING)
|
|
14
|
+
|
|
15
|
+
Search for `DbSet<{EntityName}>` in `I{DbContextName}.cs` or `{DbContextName}.cs`.
|
|
16
|
+
|
|
17
|
+
IF NOT found, add:
|
|
18
|
+
```csharp
|
|
19
|
+
public DbSet<{EntityName}> {EntityName}s => Set<{EntityName}>();
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Check 3: DI Registration (BLOCKING)
|
|
23
|
+
|
|
24
|
+
Search for `I{EntityName}Service` in `DependencyInjection.cs`.
|
|
25
|
+
|
|
26
|
+
IF NOT found, add:
|
|
27
|
+
```csharp
|
|
28
|
+
services.AddScoped<I{EntityName}Service, {EntityName}Service>();
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Check 4: RequirePermission Attributes (BLOCKING)
|
|
32
|
+
|
|
33
|
+
Each HTTP action MUST have `[RequirePermission(Permissions.{Context}.{Application}.{Module}.{Action})]`.
|
|
34
|
+
|
|
35
|
+
## Check 5: Entity Configuration (BLOCKING)
|
|
36
|
+
|
|
37
|
+
Verify:
|
|
38
|
+
- `builder.ToTable("{table_prefix}{EntityName}s")` uses correct prefix
|
|
39
|
+
- `builder.HasKey(e => e.Id)` present
|
|
40
|
+
- `builder.HasIndex` for unique fields
|
|
41
|
+
|
|
42
|
+
## Check 5b: Seeding Infrastructure (first entity only)
|
|
43
|
+
|
|
44
|
+
**If this is the FIRST entity (no existing DevDataSeeder):**
|
|
45
|
+
|
|
46
|
+
1. **`Infrastructure/Persistence/Seeding/Data/SeedConstants.cs`**
|
|
47
|
+
```csharp
|
|
48
|
+
namespace {BaseNamespace}.Infrastructure.Persistence.Seeding.Data;
|
|
49
|
+
public static class SeedConstants
|
|
50
|
+
{
|
|
51
|
+
public static readonly DateTime SeedDate = new(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
2. **`Infrastructure/Persistence/Seeding/DevDataSeeder.cs`**
|
|
56
|
+
```csharp
|
|
57
|
+
public class DevDataSeeder : IDevDataSeeder
|
|
58
|
+
{
|
|
59
|
+
private readonly ExtensionsDbContext _context;
|
|
60
|
+
private readonly ILogger<DevDataSeeder> _logger;
|
|
61
|
+
public DevDataSeeder(ExtensionsDbContext context, ILogger<DevDataSeeder> logger) { _context = context; _logger = logger; }
|
|
62
|
+
public async Task SeedAsync(CancellationToken cancellationToken = default)
|
|
63
|
+
{
|
|
64
|
+
_logger.LogInformation("Starting development data seeding...");
|
|
65
|
+
// Add Seed{Entity}sAsync calls here
|
|
66
|
+
_logger.LogInformation("Development data seeding complete.");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
3. Register: `services.AddScoped<IDevDataSeeder, DevDataSeeder>();`
|
|
72
|
+
|
|
73
|
+
## Check 5c: SqlObjects Directory (first entity only)
|
|
74
|
+
|
|
75
|
+
**If no existing SqlObjectHelper:**
|
|
76
|
+
|
|
77
|
+
1. **`Infrastructure/Persistence/SqlObjects/SqlObjectHelper.cs`** - Helper for embedded SQL resources
|
|
78
|
+
2. Create `Infrastructure/Persistence/SqlObjects/Functions/` directory
|
|
79
|
+
3. Ensure `.csproj` has: `<EmbeddedResource Include="Persistence\SqlObjects\**\*.sql" />`
|
|
80
|
+
|
|
81
|
+
## Check 6: Convention Validation (RECOMMENDED)
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Tool: mcp__smartstack__validate_conventions
|
|
85
|
+
Args: target: "backend", scope: "{entity_name}"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Verifies naming conventions, architecture layers, required attributes, DTO patterns.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Frontend: Routing Rules & Post-Generation Verification
|
|
2
|
+
|
|
3
|
+
> Reference for step-05-frontend.md — routing rules and mandatory verification checks.
|
|
4
|
+
|
|
5
|
+
## Routing Rules
|
|
6
|
+
|
|
7
|
+
### Rule 1: Routes MUST be inside Layout wrappers
|
|
8
|
+
|
|
9
|
+
**CRITICAL:** All routes MUST be nested inside the appropriate context layout. This is what provides the SmartStack shell (header with AvatarMenu, sidebar, navigation).
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
// CORRECT - Inside BusinessLayout (shell renders: header + AvatarMenu + sidebar)
|
|
13
|
+
<Route path="/business" element={<BusinessLayout />}>
|
|
14
|
+
<Route path="sales/products" element={<ProductsPage />} />
|
|
15
|
+
</Route>
|
|
16
|
+
|
|
17
|
+
// FORBIDDEN - Outside layout (NO shell, NO header, NO AvatarMenu!)
|
|
18
|
+
<Route path="/business/sales/products" element={<ProductsPage />} />
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Rule 2: Use nested routes (not flat)
|
|
22
|
+
|
|
23
|
+
**CRITICAL:** SmartStack requires NESTED routes within the layout:
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
// CORRECT - Nested routes inside layout
|
|
27
|
+
<Route path="/business" element={<BusinessLayout />}>
|
|
28
|
+
<Route path="sales">
|
|
29
|
+
<Route index element={<Navigate to="products" replace />} />
|
|
30
|
+
<Route path="products" element={<ProductsPage />} />
|
|
31
|
+
<Route path="orders" element={<OrdersPage />} />
|
|
32
|
+
</Route>
|
|
33
|
+
</Route>
|
|
34
|
+
|
|
35
|
+
// FORBIDDEN - Flat routes (cause redirect issues + bypass layout)
|
|
36
|
+
<Route path="/business/sales" element={<Navigate to="products" />} />
|
|
37
|
+
<Route path="/business/sales/products" element={<ProductsPage />} />
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Post-Generation Verification (MANDATORY)
|
|
41
|
+
|
|
42
|
+
**Before proceeding to step-06, run these checks on ALL generated frontend files:**
|
|
43
|
+
|
|
44
|
+
### 1. CSS Variables Check (BLOCKING)
|
|
45
|
+
|
|
46
|
+
Scan all generated `.tsx` files for hardcoded Tailwind colors:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
FORBIDDEN patterns: bg-blue-, bg-red-, bg-green-, bg-gray-, bg-amber-,
|
|
50
|
+
text-blue-, text-red-, text-green-, text-gray-, text-amber-,
|
|
51
|
+
border-blue-, border-red-, border-green-, border-gray-
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
If ANY hardcoded color is found → **FIX IT** using CSS variables from style-guide.md before continuing.
|
|
55
|
+
|
|
56
|
+
### 2. API Client Check (BLOCKING)
|
|
57
|
+
|
|
58
|
+
Verify all API service files use the configured client:
|
|
59
|
+
- **CORRECT:** `import { api } from '@/services/api/apiClient'` or `import api from '../api'`
|
|
60
|
+
- **FORBIDDEN:** `import axios from 'axios'`
|
|
61
|
+
|
|
62
|
+
### 3. EntityCard Check
|
|
63
|
+
|
|
64
|
+
If a grid/card view is generated, verify it uses `EntityCard` component (not custom divs).
|
|
65
|
+
|
|
66
|
+
### 4. i18n Check (BLOCKING)
|
|
67
|
+
|
|
68
|
+
Verify exactly **4 language files** exist with identical key structures:
|
|
69
|
+
- `fr/{entityCode}.json`
|
|
70
|
+
- `en/{entityCode}.json`
|
|
71
|
+
- `it/{entityCode}.json`
|
|
72
|
+
- `de/{entityCode}.json`
|
|
73
|
+
|
|
74
|
+
### 5. Route Check (BLOCKING)
|
|
75
|
+
|
|
76
|
+
Verify routes are:
|
|
77
|
+
- **INSIDE** the Layout wrapper (`BusinessLayout`, `AdminLayout`, or `UserLayout`)
|
|
78
|
+
- **NESTED** (not flat)
|
|
79
|
+
- Following path convention: `/{context}/{application}/{module}`
|
|
80
|
+
|
|
81
|
+
### 6. States Check
|
|
82
|
+
|
|
83
|
+
Verify the list page includes:
|
|
84
|
+
- Loading state (spinner)
|
|
85
|
+
- Error state (icon + message + retry button)
|
|
86
|
+
- Empty state (icon + message)
|
|
87
|
+
|
|
88
|
+
### 7. TypeScript Build Check (BLOCKING)
|
|
89
|
+
|
|
90
|
+
Run the frontend type check to verify all generated files compile:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
cd web && npx tsc --noEmit 2>&1 | head -50
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
OR if the project uses a build script:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
cd web && npm run build 2>&1 | head -80
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
IF type errors exist **in generated files**: Fix them before proceeding.
|
|
103
|
+
Common issues: missing imports, wrong interface names, incorrect prop types, missing hook return types.
|
|
104
|
+
|
|
105
|
+
IF type errors exist **in other pre-existing files**: NON-BLOCKING. Note them but proceed.
|
|
106
|
+
|
|
107
|
+
**Focus only on errors in files generated by this step:**
|
|
108
|
+
- `pages/{context}/{application}/{module}/*.tsx`
|
|
109
|
+
- `services/api/{entityCode}Api.ts`
|
|
110
|
+
- `types/{entityName}.types.ts`
|
|
111
|
+
- `hooks/use{EntityName}*.ts`
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Navigation: Fallback Procedure (When MCP Unavailable)
|
|
2
|
+
|
|
3
|
+
> Reference for step-01-navigation.md — generates navigation seeds following SmartStack.app patterns.
|
|
4
|
+
> Reference: `templates-seed.md` for code templates.
|
|
5
|
+
>
|
|
6
|
+
> **Branch by Project Type:**
|
|
7
|
+
> - If `{seeding_strategy}` = "hasdata" (core project): Follow F1-F8 below
|
|
8
|
+
> - If `{seeding_strategy}` = "provider" (client project): Follow **CLIENT PROJECT HANDLING** in step file
|
|
9
|
+
|
|
10
|
+
## F1. Read Existing Configuration Files
|
|
11
|
+
|
|
12
|
+
**CRITICAL:** Before generating any code, read existing files to determine state:
|
|
13
|
+
|
|
14
|
+
1. **Find the Navigation Configuration directory:**
|
|
15
|
+
```
|
|
16
|
+
Glob: **/Persistence/Configurations/Navigation/Navigation*Configuration.cs
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. **Read NavigationTranslationConfiguration.cs** - Find the last GUID index:
|
|
20
|
+
```
|
|
21
|
+
Search for: the last call to GenerateGuid(index++)
|
|
22
|
+
The index variable starts at 1 and increments per translation entry.
|
|
23
|
+
Your new translations MUST continue from the next index value.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
3. **Read Navigation{Level}Configuration.cs** - Check existing entities:
|
|
27
|
+
```
|
|
28
|
+
Read the Configuration for the target level (Context, Application, Module, Section).
|
|
29
|
+
Check if it already references a SeedData class: builder.HasData(Navigation{Level}SeedData.GetSeedData())
|
|
30
|
+
If yes: Read the corresponding SeedData class to find existing entries.
|
|
31
|
+
If no: You will need to add HasData() call.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
4. **Read existing SeedData files** (if they exist):
|
|
35
|
+
```
|
|
36
|
+
Glob: **/Seeding/Data/Navigation/Navigation{Level}SeedData.cs
|
|
37
|
+
Check for existing entity IDs to avoid collisions.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## F2. Determine Parent GUID
|
|
41
|
+
|
|
42
|
+
For non-context levels, find the parent entity GUID:
|
|
43
|
+
|
|
44
|
+
| Level | Parent | Where to Find Parent GUID |
|
|
45
|
+
|-------|--------|---------------------------|
|
|
46
|
+
| application | context | `NavigationContextSeedData.cs` → e.g. `PlatformContextId` |
|
|
47
|
+
| module | application | `NavigationApplicationSeedData.cs` → e.g. `AdministrationAppId` |
|
|
48
|
+
| section | module | `NavigationModuleSeedData.cs` → e.g. `UsersModuleId` |
|
|
49
|
+
|
|
50
|
+
Read the parent SeedData class and find the GUID matching `{parent_path}`.
|
|
51
|
+
|
|
52
|
+
## F3. Generate Navigation Entity GUID
|
|
53
|
+
|
|
54
|
+
Generate a deterministic GUID for the new navigation entity:
|
|
55
|
+
|
|
56
|
+
```csharp
|
|
57
|
+
// Use SHA256 hash of the full_path for deterministic generation
|
|
58
|
+
using var sha256 = System.Security.Cryptography.SHA256.Create();
|
|
59
|
+
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes("navigation-{level}-{full_path}"));
|
|
60
|
+
var guid = new Guid(hash.Take(16).ToArray());
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Rules:**
|
|
64
|
+
- NEVER use `Guid.NewGuid()`
|
|
65
|
+
- Read existing SeedData GUIDs to verify no collision
|
|
66
|
+
- Store result as `{navigation_guid}`
|
|
67
|
+
|
|
68
|
+
## F4. Write Navigation Entity Seed
|
|
69
|
+
|
|
70
|
+
Based on `{level}`, write the seed entry.
|
|
71
|
+
|
|
72
|
+
**Option A: Project uses SeedData classes (SmartStack.app pattern)**
|
|
73
|
+
|
|
74
|
+
If `Navigation{Level}SeedData.cs` exists, add the new entity:
|
|
75
|
+
|
|
76
|
+
```csharp
|
|
77
|
+
// In Infrastructure/Persistence/Seeding/Data/Navigation/Navigation{Level}SeedData.cs
|
|
78
|
+
|
|
79
|
+
// Add static GUID field
|
|
80
|
+
public static readonly Guid {PascalCode}Id = Guid.Parse("{navigation_guid}");
|
|
81
|
+
|
|
82
|
+
// Add to GetSeedData() return array
|
|
83
|
+
new {
|
|
84
|
+
Id = {PascalCode}Id,
|
|
85
|
+
ParentFk = Navigation{ParentLevel}SeedData.{ParentPascalCode}Id, // FK varies by level
|
|
86
|
+
Code = "{code}",
|
|
87
|
+
Label = "{labels.en}",
|
|
88
|
+
Description = "{descriptions.en}",
|
|
89
|
+
Icon = "{icon}",
|
|
90
|
+
IconType = IconType.Lucide,
|
|
91
|
+
Route = "/{full_path_with_slashes}",
|
|
92
|
+
DisplayOrder = {display_order},
|
|
93
|
+
IsActive = true,
|
|
94
|
+
CreatedAt = SeedConstants.SeedDate
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**FK property by level:**
|
|
99
|
+
|
|
100
|
+
| Level | FK Property | References |
|
|
101
|
+
|-------|-------------|------------|
|
|
102
|
+
| context | (none) | - |
|
|
103
|
+
| application | `ContextId` | NavigationContextSeedData.{Parent}Id |
|
|
104
|
+
| module | `ApplicationId` | NavigationApplicationSeedData.{Parent}Id |
|
|
105
|
+
| section | `ModuleId` | NavigationModuleSeedData.{Parent}Id |
|
|
106
|
+
|
|
107
|
+
**Option B: Project uses inline HasData**
|
|
108
|
+
|
|
109
|
+
If no SeedData class exists, add directly to `Navigation{Level}Configuration.cs`:
|
|
110
|
+
|
|
111
|
+
```csharp
|
|
112
|
+
// In Configure method, add:
|
|
113
|
+
builder.HasData(new {
|
|
114
|
+
Id = Guid.Parse("{navigation_guid}"),
|
|
115
|
+
// ... same properties as Option A
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## F5. Write Translation Entries
|
|
120
|
+
|
|
121
|
+
Add 4 translation entries to `NavigationTranslationConfiguration.cs`:
|
|
122
|
+
|
|
123
|
+
1. Read the file to find the current highest `index` value
|
|
124
|
+
2. Continue from `index + 1`
|
|
125
|
+
3. Use the SAME `GenerateGuid` method already defined in the file:
|
|
126
|
+
|
|
127
|
+
```csharp
|
|
128
|
+
// In GetSeedData() method, add at the end before return:
|
|
129
|
+
|
|
130
|
+
// {level}: {code} translations
|
|
131
|
+
translations.Add(new {
|
|
132
|
+
Id = GenerateGuid(index++),
|
|
133
|
+
EntityType = NavigationEntityType.{Level},
|
|
134
|
+
EntityId = Navigation{Level}SeedData.{PascalCode}Id, // or Guid.Parse("{navigation_guid}")
|
|
135
|
+
LanguageCode = "fr",
|
|
136
|
+
Label = "{labels.fr}",
|
|
137
|
+
Description = "{descriptions.fr}",
|
|
138
|
+
CreatedAt = seedDate
|
|
139
|
+
});
|
|
140
|
+
translations.Add(new {
|
|
141
|
+
Id = GenerateGuid(index++),
|
|
142
|
+
EntityType = NavigationEntityType.{Level},
|
|
143
|
+
EntityId = Navigation{Level}SeedData.{PascalCode}Id,
|
|
144
|
+
LanguageCode = "en",
|
|
145
|
+
Label = "{labels.en}",
|
|
146
|
+
Description = "{descriptions.en}",
|
|
147
|
+
CreatedAt = seedDate
|
|
148
|
+
});
|
|
149
|
+
translations.Add(new {
|
|
150
|
+
Id = GenerateGuid(index++),
|
|
151
|
+
EntityType = NavigationEntityType.{Level},
|
|
152
|
+
EntityId = Navigation{Level}SeedData.{PascalCode}Id,
|
|
153
|
+
LanguageCode = "it",
|
|
154
|
+
Label = "{labels.it}",
|
|
155
|
+
Description = "{descriptions.it}",
|
|
156
|
+
CreatedAt = seedDate
|
|
157
|
+
});
|
|
158
|
+
translations.Add(new {
|
|
159
|
+
Id = GenerateGuid(index++),
|
|
160
|
+
EntityType = NavigationEntityType.{Level},
|
|
161
|
+
EntityId = Navigation{Level}SeedData.{PascalCode}Id,
|
|
162
|
+
LanguageCode = "de",
|
|
163
|
+
Label = "{labels.de}",
|
|
164
|
+
Description = "{descriptions.de}",
|
|
165
|
+
CreatedAt = seedDate
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## F6. Store Result
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
{navigation_guid} = [generated GUID]
|
|
173
|
+
{seed_method} = "fallback" // Indicates MCP was not used
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## F7. Validation Checklist
|
|
177
|
+
|
|
178
|
+
Before proceeding, verify:
|
|
179
|
+
- [ ] Deterministic GUID generated (not NewGuid())
|
|
180
|
+
- [ ] 4 languages present (fr, en, it, de)
|
|
181
|
+
- [ ] Translation index continues existing sequence (no gaps, no collisions)
|
|
182
|
+
- [ ] Parent GUID correctly references existing entity
|
|
183
|
+
- [ ] Route path matches `/{context}/{app}/{module}` pattern
|
|
184
|
+
- [ ] DisplayOrder is consistent with existing entities
|
|
185
|
+
- [ ] Code is WRITTEN to files, not just displayed
|
|
186
|
+
|
|
187
|
+
## F8. Present Summary
|
|
188
|
+
|
|
189
|
+
```markdown
|
|
190
|
+
## Navigation Seeds Generated (Fallback)
|
|
191
|
+
|
|
192
|
+
**Entity:** {level} - {code}
|
|
193
|
+
**GUID:** {navigation_guid}
|
|
194
|
+
**Path:** {full_path}
|
|
195
|
+
|
|
196
|
+
### Files Updated
|
|
197
|
+
|
|
198
|
+
1. **Navigation{Level}SeedData.cs** (or Configuration.cs) - New entity entry
|
|
199
|
+
2. **NavigationTranslationConfiguration.cs** - 4 translation entries added
|
|
200
|
+
```
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# IClientSeedDataProvider Template
|
|
2
|
+
|
|
3
|
+
> Referenced from `steps/step-03b-provider.md` — C# template for client project seed data providers.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Provider Class Template
|
|
8
|
+
|
|
9
|
+
**Location:** `Infrastructure/Persistence/Seeding/{AppPascalName}SeedDataProvider.cs`
|
|
10
|
+
|
|
11
|
+
Where `{AppPascalName}` is derived from the application code (e.g., `free-bike` → `FreeBike`).
|
|
12
|
+
|
|
13
|
+
```csharp
|
|
14
|
+
using Microsoft.EntityFrameworkCore;
|
|
15
|
+
using SmartStack.Application.Common.Interfaces;
|
|
16
|
+
using SmartStack.Domain.Navigation;
|
|
17
|
+
using SmartStack.Domain.Platform.Administration.Roles;
|
|
18
|
+
|
|
19
|
+
namespace {BaseNamespace}.Infrastructure.Persistence.Seeding;
|
|
20
|
+
|
|
21
|
+
/// <summary>
|
|
22
|
+
/// Seeds {AppLabel} navigation, roles, permissions, and role-permission data
|
|
23
|
+
/// into the SmartStack Core schema at application startup.
|
|
24
|
+
/// Implements <see cref="IClientSeedDataProvider"/> for runtime seeding
|
|
25
|
+
/// (no Core migrations required).
|
|
26
|
+
/// </summary>
|
|
27
|
+
public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
|
|
28
|
+
{
|
|
29
|
+
public int Order => 100;
|
|
30
|
+
|
|
31
|
+
public async Task SeedNavigationAsync(ICoreDbContext context, CancellationToken ct)
|
|
32
|
+
{
|
|
33
|
+
// Check idempotence
|
|
34
|
+
var exists = await context.NavigationApplications
|
|
35
|
+
.AnyAsync(a => a.Code == "{app_code}", ct);
|
|
36
|
+
if (exists) return;
|
|
37
|
+
|
|
38
|
+
// 1. Retrieve the parent context ("business", "platform", etc.)
|
|
39
|
+
var parentContext = await context.NavigationContexts
|
|
40
|
+
.FirstAsync(c => c.Code == "{context_code}", ct);
|
|
41
|
+
|
|
42
|
+
// 2. Create the application
|
|
43
|
+
var app = NavigationApplication.Create(
|
|
44
|
+
parentContext.Id,
|
|
45
|
+
"{app_code}",
|
|
46
|
+
"{app_label_en}",
|
|
47
|
+
"{app_desc_en}",
|
|
48
|
+
"{app_icon}",
|
|
49
|
+
IconType.Lucide,
|
|
50
|
+
"/{context_code}/{app_code}",
|
|
51
|
+
{display_order});
|
|
52
|
+
context.NavigationApplications.Add(app);
|
|
53
|
+
await ((DbContext)context).SaveChangesAsync(ct);
|
|
54
|
+
|
|
55
|
+
// 3. Create modules
|
|
56
|
+
// Use GUIDs and data from {Module}NavigationSeedData.cs
|
|
57
|
+
foreach (var moduleData in GetModuleSeedEntries(app.Id))
|
|
58
|
+
{
|
|
59
|
+
var module = NavigationModule.Create(
|
|
60
|
+
moduleData.ApplicationId,
|
|
61
|
+
moduleData.Code,
|
|
62
|
+
moduleData.Label,
|
|
63
|
+
moduleData.Description,
|
|
64
|
+
moduleData.Icon,
|
|
65
|
+
IconType.Lucide,
|
|
66
|
+
moduleData.Route,
|
|
67
|
+
moduleData.DisplayOrder);
|
|
68
|
+
context.NavigationModules.Add(module);
|
|
69
|
+
}
|
|
70
|
+
await ((DbContext)context).SaveChangesAsync(ct);
|
|
71
|
+
|
|
72
|
+
// 4. Create translations (4 languages per entity)
|
|
73
|
+
// Use data from {Module}NavigationTranslationSeedData.cs
|
|
74
|
+
// ...
|
|
75
|
+
await ((DbContext)context).SaveChangesAsync(ct);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public async Task SeedRolesAsync(ICoreDbContext context, CancellationToken ct)
|
|
79
|
+
{
|
|
80
|
+
// Check idempotence
|
|
81
|
+
var applicationId = ApplicationRolesSeedData.ApplicationId;
|
|
82
|
+
var exists = await context.Roles
|
|
83
|
+
.AnyAsync(r => r.ApplicationId == applicationId, ct);
|
|
84
|
+
if (exists) return;
|
|
85
|
+
|
|
86
|
+
// Create application-scoped roles (Admin, Manager, Contributor, Viewer)
|
|
87
|
+
// Use data from ApplicationRolesSeedData.cs
|
|
88
|
+
foreach (var entry in ApplicationRolesSeedData.GetRoleEntries())
|
|
89
|
+
{
|
|
90
|
+
var role = Role.Create(
|
|
91
|
+
entry.Code,
|
|
92
|
+
entry.Name,
|
|
93
|
+
entry.Description,
|
|
94
|
+
entry.ApplicationId,
|
|
95
|
+
entry.IsSystem);
|
|
96
|
+
context.Roles.Add(role);
|
|
97
|
+
}
|
|
98
|
+
await ((DbContext)context).SaveChangesAsync(ct);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public async Task SeedPermissionsAsync(ICoreDbContext context, CancellationToken ct)
|
|
102
|
+
{
|
|
103
|
+
// Check idempotence
|
|
104
|
+
var exists = await context.Permissions
|
|
105
|
+
.AnyAsync(p => p.Path == "{full_path}.*", ct);
|
|
106
|
+
if (exists) return;
|
|
107
|
+
|
|
108
|
+
// Retrieve modules by Code for FK resolution
|
|
109
|
+
// Use data from {Module}PermissionSeedData.cs
|
|
110
|
+
// Create via Permission.CreateForModule(...) and Permission.CreateWildcard(...)
|
|
111
|
+
// ...
|
|
112
|
+
await ((DbContext)context).SaveChangesAsync(ct);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public async Task SeedRolePermissionsAsync(ICoreDbContext context, CancellationToken ct)
|
|
116
|
+
{
|
|
117
|
+
// Check idempotence
|
|
118
|
+
var exists = await context.RolePermissions
|
|
119
|
+
.AnyAsync(rp => rp.Permission!.Path.StartsWith("{full_path}."), ct);
|
|
120
|
+
if (exists) return;
|
|
121
|
+
|
|
122
|
+
// Retrieve existing roles and created permissions
|
|
123
|
+
// Use data from {Module}RolePermissionSeedData.cs
|
|
124
|
+
// Create via RolePermission.Create(roleId, permissionId, "system")
|
|
125
|
+
// ...
|
|
126
|
+
await ((DbContext)context).SaveChangesAsync(ct);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Private helper methods fed by SeedData classes
|
|
130
|
+
// ...
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## DI Registration
|
|
137
|
+
|
|
138
|
+
Modify `Infrastructure/DependencyInjection.cs` of the client project:
|
|
139
|
+
|
|
140
|
+
```csharp
|
|
141
|
+
// Add using:
|
|
142
|
+
using SmartStack.Application.Common.Interfaces;
|
|
143
|
+
|
|
144
|
+
// In the registration method:
|
|
145
|
+
services.AddScoped<IClientSeedDataProvider, {AppPascalName}SeedDataProvider>();
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Critical Rules
|
|
151
|
+
|
|
152
|
+
1. **Factory methods mandatory**: `NavigationModule.Create(...)`, `Role.Create(...)`, `Permission.CreateForModule(...)`, `RolePermission.Create(...)` — NEVER `new Entity()`
|
|
153
|
+
2. **Idempotence**: Each Seed method checks existence before inserting
|
|
154
|
+
3. **SaveChangesAsync per group**: Navigation → save → Roles → save → Permissions → save → RolePermissions → save
|
|
155
|
+
4. **Execution order**: `SeedRolesAsync()` MUST be called BEFORE `SeedRolePermissionsAsync()` (roles must exist before mapping)
|
|
156
|
+
5. **Deterministic GUIDs**: Use IDs from SeedData classes (not `Guid.NewGuid()`)
|
|
157
|
+
6. **Resolve FK by Code**: Parent modules and roles are found by `Code`, not hardcoded GUID
|
|
158
|
+
7. **Order property**: Use `100` as default. If multiple providers exist, they run in Order sequence
|