@atlashub/smartstack-cli 3.7.0 → 3.9.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 +4 -2
- package/templates/agents/action.md +1 -0
- package/templates/agents/ba-writer.md +33 -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/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 +134 -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-03b-provider.md +4 -128
- 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 +11 -2
- package/templates/skills/business-analyse/html/ba-interactive.html +3214 -2246
- package/templates/skills/business-analyse/html/build-html.js +77 -0
- package/templates/skills/business-analyse/html/src/scripts/01-data-init.js +130 -0
- package/templates/skills/business-analyse/html/src/scripts/02-navigation.js +22 -0
- package/templates/skills/business-analyse/html/src/scripts/03-render-cadrage.js +208 -0
- package/templates/skills/business-analyse/html/src/scripts/04-render-modules.js +211 -0
- package/templates/skills/business-analyse/html/src/scripts/05-render-specs.js +554 -0
- package/templates/skills/business-analyse/html/src/scripts/06-render-consolidation.js +110 -0
- package/templates/skills/business-analyse/html/src/scripts/07-render-handoff.js +90 -0
- package/templates/skills/business-analyse/html/src/scripts/08-editing.js +45 -0
- package/templates/skills/business-analyse/html/src/scripts/09-export.js +168 -0
- package/templates/skills/business-analyse/html/src/scripts/10-comments.js +171 -0
- package/templates/skills/business-analyse/html/src/scripts/11-review-panel.js +161 -0
- package/templates/skills/business-analyse/html/src/styles/01-variables.css +38 -0
- package/templates/skills/business-analyse/html/src/styles/02-layout.css +101 -0
- package/templates/skills/business-analyse/html/src/styles/03-navigation.css +62 -0
- package/templates/skills/business-analyse/html/src/styles/04-cards.css +196 -0
- package/templates/skills/business-analyse/html/src/styles/05-modules.css +325 -0
- package/templates/skills/business-analyse/html/src/styles/06-wireframes.css +230 -0
- package/templates/skills/business-analyse/html/src/styles/07-comments.css +184 -0
- package/templates/skills/business-analyse/html/src/styles/08-review-panel.css +241 -0
- package/templates/skills/business-analyse/html/src/template.html +623 -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/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/steps/step-00-init.md +35 -68
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +5 -194
- package/templates/skills/business-analyse/steps/step-03a-data.md +6 -49
- package/templates/skills/business-analyse/steps/step-03b-ui.md +12 -178
- package/templates/skills/business-analyse/steps/step-03d-validate.md +3 -48
- package/templates/skills/business-analyse/steps/step-04-consolidation.md +9 -104
- package/templates/skills/business-analyse/steps/step-05a-handoff.md +25 -441
- package/templates/skills/business-analyse/steps/step-05b-deploy.md +19 -187
- 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 +6 -158
- package/templates/skills/controller/steps/step-04-perms.md +5 -144
- 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/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,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,134 @@
|
|
|
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, 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 SeedPermissionsAsync(ICoreDbContext context, CancellationToken ct)
|
|
79
|
+
{
|
|
80
|
+
// Check idempotence
|
|
81
|
+
var exists = await context.Permissions
|
|
82
|
+
.AnyAsync(p => p.Path == "{full_path}.*", ct);
|
|
83
|
+
if (exists) return;
|
|
84
|
+
|
|
85
|
+
// Retrieve modules by Code for FK resolution
|
|
86
|
+
// Use data from {Module}PermissionSeedData.cs
|
|
87
|
+
// Create via Permission.CreateForModule(...) and Permission.CreateWildcard(...)
|
|
88
|
+
// ...
|
|
89
|
+
await ((DbContext)context).SaveChangesAsync(ct);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public async Task SeedRolePermissionsAsync(ICoreDbContext context, CancellationToken ct)
|
|
93
|
+
{
|
|
94
|
+
// Check idempotence
|
|
95
|
+
var exists = await context.RolePermissions
|
|
96
|
+
.AnyAsync(rp => rp.Permission!.Path.StartsWith("{full_path}."), ct);
|
|
97
|
+
if (exists) return;
|
|
98
|
+
|
|
99
|
+
// Retrieve existing roles and created permissions
|
|
100
|
+
// Use data from {Module}RolePermissionSeedData.cs
|
|
101
|
+
// Create via RolePermission.Create(roleId, permissionId, "system")
|
|
102
|
+
// ...
|
|
103
|
+
await ((DbContext)context).SaveChangesAsync(ct);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Private helper methods fed by SeedData classes
|
|
107
|
+
// ...
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## DI Registration
|
|
114
|
+
|
|
115
|
+
Modify `Infrastructure/DependencyInjection.cs` of the client project:
|
|
116
|
+
|
|
117
|
+
```csharp
|
|
118
|
+
// Add using:
|
|
119
|
+
using SmartStack.Application.Common.Interfaces;
|
|
120
|
+
|
|
121
|
+
// In the registration method:
|
|
122
|
+
services.AddScoped<IClientSeedDataProvider, {AppPascalName}SeedDataProvider>();
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Critical Rules
|
|
128
|
+
|
|
129
|
+
1. **Factory methods mandatory**: `NavigationModule.Create(...)`, `Permission.CreateForModule(...)`, `RolePermission.Create(...)` — NEVER `new Entity()`
|
|
130
|
+
2. **Idempotence**: Each Seed method checks existence before inserting
|
|
131
|
+
3. **SaveChangesAsync per group**: Navigation → save → Permissions → save → RolePermissions → save
|
|
132
|
+
4. **Deterministic GUIDs**: Use IDs from SeedData classes (not `Guid.NewGuid()`)
|
|
133
|
+
5. **Resolve FK by Code**: Parent modules are found by `Code`, not hardcoded GUID
|
|
134
|
+
6. **Order property**: Use `100` as default. If multiple providers exist, they run in Order sequence
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Frontend Test Infrastructure & Generation
|
|
2
|
+
|
|
3
|
+
> Reference for step-07-tests.md — Vitest + Testing Library + MSW setup and component test generation.
|
|
4
|
+
|
|
5
|
+
## 1. Check Frontend Test Infrastructure
|
|
6
|
+
|
|
7
|
+
Verify that the frontend project has Vitest + Testing Library configured:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Check if vitest.config.ts exists in the web/frontend project
|
|
11
|
+
ls {WebProjectPath}/vitest.config.ts 2>/dev/null
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
If NOT found, deploy the test infrastructure:
|
|
15
|
+
|
|
16
|
+
### Install packages
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cd {WebProjectPath}
|
|
20
|
+
npm install -D vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom msw
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Copy infrastructure files from SmartStack templates
|
|
24
|
+
|
|
25
|
+
| Template Source | Destination |
|
|
26
|
+
|----------------|-------------|
|
|
27
|
+
| `templates/project/test-frontend/vitest.config.ts` | `{WebProjectPath}/vitest.config.ts` |
|
|
28
|
+
| `templates/project/test-frontend/setup.ts` | `{WebProjectPath}/src/test/setup.ts` |
|
|
29
|
+
| `templates/project/test-frontend/test-utils.tsx` | `{WebProjectPath}/src/test/test-utils.tsx` |
|
|
30
|
+
| `templates/project/test-frontend/msw/server.ts` | `{WebProjectPath}/src/test/msw/server.ts` |
|
|
31
|
+
| `templates/project/test-frontend/msw/handlers.ts` | `{WebProjectPath}/src/test/msw/handlers.ts` |
|
|
32
|
+
|
|
33
|
+
### Add test scripts to `package.json` (if missing)
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"scripts": {
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest",
|
|
40
|
+
"test:coverage": "vitest run --coverage"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 2. Generate Frontend Tests
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Tool: mcp__smartstack__scaffold_frontend_tests
|
|
49
|
+
Args:
|
|
50
|
+
name: "{entity_name}"
|
|
51
|
+
components: ["all"]
|
|
52
|
+
apiRoute: "/api/{entity_code}"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This generates:
|
|
56
|
+
- `src/pages/{context}/{application}/__tests__/{EntityName}Page.test.tsx` - Page rendering, loading, error states
|
|
57
|
+
- `src/pages/{context}/{application}/__tests__/{EntityName}ListView.test.tsx` - List display, pagination, view toggle
|
|
58
|
+
- `src/pages/{context}/{application}/__tests__/{EntityName}DetailPage.test.tsx` - Detail view, tabs, back navigation
|
|
59
|
+
- `src/hooks/__tests__/use{EntityName}Preferences.test.ts` - Preference get/set
|
|
60
|
+
- `src/services/api/__tests__/{entityName}Api.test.ts` - API client calls with MSW
|
|
61
|
+
|
|
62
|
+
## 3. Run Frontend Tests (BLOCKING)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cd {WebProjectPath}
|
|
66
|
+
npx vitest run --reporter=default
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**ALL frontend tests MUST pass.** If tests fail:
|
|
70
|
+
1. Read the failure output carefully
|
|
71
|
+
2. Fix the failing tests or the components they test
|
|
72
|
+
3. Re-run until all tests pass
|
|
73
|
+
4. Do NOT proceed to the next step until all tests are green
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Test Infrastructure Prerequisites
|
|
2
|
+
|
|
3
|
+
> Reference for step-07-tests.md — verify and scaffold test project before generating tests.
|
|
4
|
+
|
|
5
|
+
## 1. Verify Test Project Exists
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Look for existing test project
|
|
9
|
+
ls *Tests*/*.csproj 2>/dev/null || ls tests/*/*.csproj 2>/dev/null
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
If NO test project exists, create one:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
dotnet new xunit -n {SolutionName}.Tests -o tests/{SolutionName}.Tests
|
|
16
|
+
dotnet sln add tests/{SolutionName}.Tests/{SolutionName}.Tests.csproj
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 2. Required NuGet Packages
|
|
20
|
+
|
|
21
|
+
| Package | Purpose |
|
|
22
|
+
|---------|---------|
|
|
23
|
+
| `xunit` | Test framework |
|
|
24
|
+
| `FluentAssertions` | Assertion library |
|
|
25
|
+
| `Moq` | Mocking framework |
|
|
26
|
+
| `Microsoft.AspNetCore.Mvc.Testing` | Integration test support |
|
|
27
|
+
| `Microsoft.EntityFrameworkCore.Sqlite` | SQLite in-memory for REAL integration tests |
|
|
28
|
+
| `Microsoft.Data.Sqlite` | SQLite connection support |
|
|
29
|
+
| `Microsoft.EntityFrameworkCore.InMemory` | In-memory DB for repository tests |
|
|
30
|
+
| `FluentValidation.TestHelper` | Validator testing support |
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cd tests/{SolutionName}.Tests
|
|
34
|
+
dotnet add package FluentAssertions
|
|
35
|
+
dotnet add package Moq
|
|
36
|
+
dotnet add package Microsoft.AspNetCore.Mvc.Testing
|
|
37
|
+
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
|
|
38
|
+
dotnet add package Microsoft.Data.Sqlite
|
|
39
|
+
dotnet add package Microsoft.EntityFrameworkCore.InMemory
|
|
40
|
+
dotnet add package FluentValidation.TestHelper
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 3. Project References
|
|
44
|
+
|
|
45
|
+
The test project MUST reference the API project (for WebApplicationFactory):
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
cd tests/{SolutionName}.Tests
|
|
49
|
+
dotnet add reference ../../src/{SolutionName}.Api/{SolutionName}.Api.csproj
|
|
50
|
+
dotnet add reference ../../src/{SolutionName}.Application/{SolutionName}.Application.csproj
|
|
51
|
+
dotnet add reference ../../src/{SolutionName}.Domain/{SolutionName}.Domain.csproj
|
|
52
|
+
dotnet add reference ../../src/{SolutionName}.Infrastructure/{SolutionName}.Infrastructure.csproj
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 4. Program.cs Accessibility (BLOCKING)
|
|
56
|
+
|
|
57
|
+
The API project's `Program` class must be accessible for `WebApplicationFactory<Program>`.
|
|
58
|
+
|
|
59
|
+
Check if `Program.cs` ends with `public partial class Program { }`. If not, add it:
|
|
60
|
+
|
|
61
|
+
```csharp
|
|
62
|
+
// At the very end of Program.cs
|
|
63
|
+
public partial class Program { }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Alternatively**, add to the API `.csproj`:
|
|
67
|
+
|
|
68
|
+
```xml
|
|
69
|
+
<ItemGroup>
|
|
70
|
+
<InternalsVisibleTo Include="{SolutionName}.Tests" />
|
|
71
|
+
</ItemGroup>
|
|
72
|
+
```
|
|
@@ -138,204 +138,13 @@ The SeedData files will be consumed by the `IClientSeedDataProvider` generated a
|
|
|
138
138
|
|
|
139
139
|
## FALLBACK PROCEDURE (When MCP Unavailable)
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
### F1. Read Existing Configuration Files
|
|
149
|
-
|
|
150
|
-
**CRITICAL:** Before generating any code, read existing files to determine state:
|
|
151
|
-
|
|
152
|
-
1. **Find the Navigation Configuration directory:**
|
|
153
|
-
```
|
|
154
|
-
Glob: **/Persistence/Configurations/Navigation/Navigation*Configuration.cs
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
2. **Read NavigationTranslationConfiguration.cs** - Find the last GUID index:
|
|
158
|
-
```
|
|
159
|
-
Search for: the last call to GenerateGuid(index++)
|
|
160
|
-
The index variable starts at 1 and increments per translation entry.
|
|
161
|
-
Your new translations MUST continue from the next index value.
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
3. **Read Navigation{Level}Configuration.cs** - Check existing entities:
|
|
165
|
-
```
|
|
166
|
-
Read the Configuration for the target level (Context, Application, Module, Section).
|
|
167
|
-
Check if it already references a SeedData class: builder.HasData(Navigation{Level}SeedData.GetSeedData())
|
|
168
|
-
If yes: Read the corresponding SeedData class to find existing entries.
|
|
169
|
-
If no: You will need to add HasData() call.
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
4. **Read existing SeedData files** (if they exist):
|
|
173
|
-
```
|
|
174
|
-
Glob: **/Seeding/Data/Navigation/Navigation{Level}SeedData.cs
|
|
175
|
-
Check for existing entity IDs to avoid collisions.
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### F2. Determine Parent GUID
|
|
179
|
-
|
|
180
|
-
For non-context levels, find the parent entity GUID:
|
|
181
|
-
|
|
182
|
-
| Level | Parent | Where to Find Parent GUID |
|
|
183
|
-
|-------|--------|---------------------------|
|
|
184
|
-
| application | context | `NavigationContextSeedData.cs` → e.g. `PlatformContextId` |
|
|
185
|
-
| module | application | `NavigationApplicationSeedData.cs` → e.g. `AdministrationAppId` |
|
|
186
|
-
| section | module | `NavigationModuleSeedData.cs` → e.g. `UsersModuleId` |
|
|
187
|
-
|
|
188
|
-
Read the parent SeedData class and find the GUID matching `{parent_path}`.
|
|
189
|
-
|
|
190
|
-
### F3. Generate Navigation Entity GUID
|
|
191
|
-
|
|
192
|
-
Generate a deterministic GUID for the new navigation entity:
|
|
193
|
-
|
|
194
|
-
```csharp
|
|
195
|
-
// Use SHA256 hash of the full_path for deterministic generation
|
|
196
|
-
using var sha256 = System.Security.Cryptography.SHA256.Create();
|
|
197
|
-
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes("navigation-{level}-{full_path}"));
|
|
198
|
-
var guid = new Guid(hash.Take(16).ToArray());
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
**Rules:**
|
|
202
|
-
- NEVER use `Guid.NewGuid()`
|
|
203
|
-
- Read existing SeedData GUIDs to verify no collision
|
|
204
|
-
- Store result as `{navigation_guid}`
|
|
205
|
-
|
|
206
|
-
### F4. Write Navigation Entity Seed
|
|
207
|
-
|
|
208
|
-
Based on `{level}`, write the seed entry.
|
|
209
|
-
|
|
210
|
-
**Option A: Project uses SeedData classes (SmartStack.app pattern)**
|
|
211
|
-
|
|
212
|
-
If `Navigation{Level}SeedData.cs` exists, add the new entity:
|
|
213
|
-
|
|
214
|
-
```csharp
|
|
215
|
-
// In Infrastructure/Persistence/Seeding/Data/Navigation/Navigation{Level}SeedData.cs
|
|
216
|
-
|
|
217
|
-
// Add static GUID field
|
|
218
|
-
public static readonly Guid {PascalCode}Id = Guid.Parse("{navigation_guid}");
|
|
219
|
-
|
|
220
|
-
// Add to GetSeedData() return array
|
|
221
|
-
new {
|
|
222
|
-
Id = {PascalCode}Id,
|
|
223
|
-
ParentFk = Navigation{ParentLevel}SeedData.{ParentPascalCode}Id, // FK varies by level
|
|
224
|
-
Code = "{code}",
|
|
225
|
-
Label = "{labels.en}",
|
|
226
|
-
Description = "{descriptions.en}",
|
|
227
|
-
Icon = "{icon}",
|
|
228
|
-
IconType = IconType.Lucide,
|
|
229
|
-
Route = "/{full_path_with_slashes}",
|
|
230
|
-
DisplayOrder = {display_order},
|
|
231
|
-
IsActive = true,
|
|
232
|
-
CreatedAt = SeedConstants.SeedDate
|
|
233
|
-
}
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
**FK property by level:**
|
|
237
|
-
|
|
238
|
-
| Level | FK Property | References |
|
|
239
|
-
|-------|-------------|------------|
|
|
240
|
-
| context | (none) | - |
|
|
241
|
-
| application | `ContextId` | NavigationContextSeedData.{Parent}Id |
|
|
242
|
-
| module | `ApplicationId` | NavigationApplicationSeedData.{Parent}Id |
|
|
243
|
-
| section | `ModuleId` | NavigationModuleSeedData.{Parent}Id |
|
|
244
|
-
|
|
245
|
-
**Option B: Project uses inline HasData**
|
|
246
|
-
|
|
247
|
-
If no SeedData class exists, add directly to `Navigation{Level}Configuration.cs`:
|
|
248
|
-
|
|
249
|
-
```csharp
|
|
250
|
-
// In Configure method, add:
|
|
251
|
-
builder.HasData(new {
|
|
252
|
-
Id = Guid.Parse("{navigation_guid}"),
|
|
253
|
-
// ... same properties as Option A
|
|
254
|
-
});
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
### F5. Write Translation Entries
|
|
258
|
-
|
|
259
|
-
Add 4 translation entries to `NavigationTranslationConfiguration.cs`:
|
|
260
|
-
|
|
261
|
-
1. Read the file to find the current highest `index` value
|
|
262
|
-
2. Continue from `index + 1`
|
|
263
|
-
3. Use the SAME `GenerateGuid` method already defined in the file:
|
|
264
|
-
|
|
265
|
-
```csharp
|
|
266
|
-
// In GetSeedData() method, add at the end before return:
|
|
267
|
-
|
|
268
|
-
// {level}: {code} translations
|
|
269
|
-
translations.Add(new {
|
|
270
|
-
Id = GenerateGuid(index++),
|
|
271
|
-
EntityType = NavigationEntityType.{Level},
|
|
272
|
-
EntityId = Navigation{Level}SeedData.{PascalCode}Id, // or Guid.Parse("{navigation_guid}")
|
|
273
|
-
LanguageCode = "fr",
|
|
274
|
-
Label = "{labels.fr}",
|
|
275
|
-
Description = "{descriptions.fr}",
|
|
276
|
-
CreatedAt = seedDate
|
|
277
|
-
});
|
|
278
|
-
translations.Add(new {
|
|
279
|
-
Id = GenerateGuid(index++),
|
|
280
|
-
EntityType = NavigationEntityType.{Level},
|
|
281
|
-
EntityId = Navigation{Level}SeedData.{PascalCode}Id,
|
|
282
|
-
LanguageCode = "en",
|
|
283
|
-
Label = "{labels.en}",
|
|
284
|
-
Description = "{descriptions.en}",
|
|
285
|
-
CreatedAt = seedDate
|
|
286
|
-
});
|
|
287
|
-
translations.Add(new {
|
|
288
|
-
Id = GenerateGuid(index++),
|
|
289
|
-
EntityType = NavigationEntityType.{Level},
|
|
290
|
-
EntityId = Navigation{Level}SeedData.{PascalCode}Id,
|
|
291
|
-
LanguageCode = "it",
|
|
292
|
-
Label = "{labels.it}",
|
|
293
|
-
Description = "{descriptions.it}",
|
|
294
|
-
CreatedAt = seedDate
|
|
295
|
-
});
|
|
296
|
-
translations.Add(new {
|
|
297
|
-
Id = GenerateGuid(index++),
|
|
298
|
-
EntityType = NavigationEntityType.{Level},
|
|
299
|
-
EntityId = Navigation{Level}SeedData.{PascalCode}Id,
|
|
300
|
-
LanguageCode = "de",
|
|
301
|
-
Label = "{labels.de}",
|
|
302
|
-
Description = "{descriptions.de}",
|
|
303
|
-
CreatedAt = seedDate
|
|
304
|
-
});
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
### F6. Store Result
|
|
308
|
-
|
|
309
|
-
```
|
|
310
|
-
{navigation_guid} = [generated GUID]
|
|
311
|
-
{seed_method} = "fallback" // Indicates MCP was not used
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### F7. Validation Checklist
|
|
315
|
-
|
|
316
|
-
Before proceeding, verify:
|
|
317
|
-
- [ ] Deterministic GUID generated (not NewGuid())
|
|
318
|
-
- [ ] 4 languages present (fr, en, it, de)
|
|
319
|
-
- [ ] Translation index continues existing sequence (no gaps, no collisions)
|
|
320
|
-
- [ ] Parent GUID correctly references existing entity
|
|
321
|
-
- [ ] Route path matches `/{context}/{app}/{module}` pattern
|
|
322
|
-
- [ ] DisplayOrder is consistent with existing entities
|
|
323
|
-
- [ ] Code is WRITTEN to files, not just displayed
|
|
324
|
-
|
|
325
|
-
### F8. Present Summary
|
|
326
|
-
|
|
327
|
-
```markdown
|
|
328
|
-
## Navigation Seeds Generated (Fallback)
|
|
329
|
-
|
|
330
|
-
**Entity:** {level} - {code}
|
|
331
|
-
**GUID:** {navigation_guid}
|
|
332
|
-
**Path:** {full_path}
|
|
333
|
-
|
|
334
|
-
### Files Updated
|
|
335
|
-
|
|
336
|
-
1. **Navigation{Level}SeedData.cs** (or Configuration.cs) - New entity entry
|
|
337
|
-
2. **NavigationTranslationConfiguration.cs** - 4 translation entries added
|
|
338
|
-
```
|
|
141
|
+
See [references/nav-fallback-procedure.md](../references/nav-fallback-procedure.md) for the complete 8-step fallback:
|
|
142
|
+
- **F1:** Read existing Configuration/SeedData files to determine state
|
|
143
|
+
- **F2:** Determine parent GUID by level
|
|
144
|
+
- **F3:** Generate deterministic GUID (SHA256, never NewGuid())
|
|
145
|
+
- **F4:** Write navigation entity seed (SeedData class or inline HasData)
|
|
146
|
+
- **F5:** Write 4 translation entries (continue existing index sequence)
|
|
147
|
+
- **F6-F8:** Store result, validation checklist, summary
|
|
339
148
|
|
|
340
149
|
---
|
|
341
150
|
|