@atlashub/smartstack-cli 3.9.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/package.json +1 -1
- package/templates/agents/ba-writer.md +178 -0
- package/templates/skills/application/references/application-roles-template.md +227 -0
- package/templates/skills/application/references/provider-template.md +30 -6
- package/templates/skills/application/steps/step-03-roles.md +45 -7
- package/templates/skills/application/steps/step-03b-provider.md +13 -6
- package/templates/skills/business-analyse/SKILL.md +56 -4
- 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/robustness-checks.md +538 -0
- package/templates/skills/business-analyse/schemas/sections/specification-schema.json +33 -1
- package/templates/skills/business-analyse/steps/step-00-init.md +166 -0
- package/templates/skills/business-analyse/steps/step-03a-data.md +36 -0
- package/templates/skills/business-analyse/steps/step-03c-compile.md +71 -2
- package/templates/skills/business-analyse/steps/step-03d-validate.md +274 -0
- package/templates/skills/business-analyse/steps/step-04-consolidation.md +166 -0
- package/templates/skills/business-analyse/steps/step-05a-handoff.md +44 -0
- package/templates/skills/business-analyse/steps/step-05b-deploy.md +21 -2
- package/templates/skills/business-analyse/steps/step-05c-ralph-readiness.md +526 -0
- package/templates/skills/controller/steps/step-03-generate.md +184 -24
- package/templates/skills/controller/templates.md +11 -2
- package/templates/skills/ralph-loop/references/core-seed-data.md +173 -21
|
@@ -1,48 +1,189 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: step-03-generate
|
|
3
|
-
description: Generate controller
|
|
3
|
+
description: Generate controller using MCP scaffold_extension with NavRoute
|
|
4
4
|
next_step: steps/step-04-perms.md
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Step 3: Generate Controller
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## MANDATORY EXECUTION RULES
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- ALWAYS use MCP `scaffold_extension` tool - NEVER use templates
|
|
12
|
+
- ALWAYS generate Controller + DTOs as a unit
|
|
13
|
+
- ALWAYS include NavRoute attribute for frontend/backend sync
|
|
14
|
+
- YOU ARE AN ORCHESTRATOR calling MCP, not a generator
|
|
15
|
+
- MCP is the SOURCE OF TRUTH for code generation
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
## YOUR TASK
|
|
18
|
+
|
|
19
|
+
Call the SmartStack MCP `scaffold_extension` tool with type "controller" to generate:
|
|
20
|
+
1. API Controller with NavRoute attribute
|
|
21
|
+
2. DTOs (Response, Create, Update)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## AVAILABLE STATE
|
|
26
|
+
|
|
27
|
+
From previous steps:
|
|
28
|
+
|
|
29
|
+
| Variable | Description |
|
|
30
|
+
|----------|-------------|
|
|
31
|
+
| `{area}` | Controller folder (Admin, Business, Support, User) |
|
|
32
|
+
| `{module}` | kebab-case module identifier |
|
|
33
|
+
| `{entity}` | Entity name (PascalCase) |
|
|
34
|
+
| `{permission_path}` | Complete navigation path (navRoute) |
|
|
35
|
+
| `{controller_type}` | crud, readonly, custom, auth |
|
|
14
36
|
|
|
15
37
|
---
|
|
16
38
|
|
|
17
|
-
## EXECUTION SEQUENCE
|
|
39
|
+
## EXECUTION SEQUENCE
|
|
18
40
|
|
|
19
|
-
### 1.
|
|
41
|
+
### 1. Derive Entity Name
|
|
20
42
|
|
|
21
|
-
|
|
43
|
+
Convert `{module}` to PascalCase for entity name:
|
|
22
44
|
|
|
23
45
|
```
|
|
24
|
-
|
|
46
|
+
module: "products" → entityName: "Product"
|
|
47
|
+
module: "order-items" → entityName: "OrderItem"
|
|
48
|
+
module: "user-profiles" → entityName: "UserProfile"
|
|
25
49
|
```
|
|
26
50
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
51
|
+
### 2. Determine Table Prefix
|
|
52
|
+
|
|
53
|
+
Based on navigation context extracted from `{permission_path}`:
|
|
54
|
+
|
|
55
|
+
| Context | Table Prefix | Controller Folder |
|
|
56
|
+
|---------|--------------|-------------------|
|
|
57
|
+
| platform.administration | `auth_` or `cfg_` | `Admin` |
|
|
58
|
+
| platform.support | `support_` | `Support` |
|
|
59
|
+
| business.* | `ref_` or domain-specific | `Business` |
|
|
60
|
+
| personal.* | `usr_` | `User` |
|
|
61
|
+
|
|
62
|
+
### 3. Call MCP scaffold_extension (TWO CALLS)
|
|
63
|
+
|
|
64
|
+
**First call: Generate DTOs**
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Tool: mcp__smartstack__scaffold_extension
|
|
68
|
+
Args:
|
|
69
|
+
type: "dto"
|
|
70
|
+
name: "{entityName}" # PascalCase from step 1
|
|
71
|
+
options:
|
|
72
|
+
navRoute: "{permission_path}" # For proper namespace hierarchy
|
|
73
|
+
schema: "core"
|
|
74
|
+
dryRun: false
|
|
75
|
+
```
|
|
31
76
|
|
|
32
|
-
|
|
77
|
+
**Second call: Generate Controller with NavRoute**
|
|
33
78
|
|
|
34
|
-
**Target path:**
|
|
35
79
|
```
|
|
36
|
-
|
|
80
|
+
Tool: mcp__smartstack__scaffold_extension
|
|
81
|
+
Args:
|
|
82
|
+
type: "controller"
|
|
83
|
+
name: "{entityName}" # PascalCase from step 1
|
|
84
|
+
options:
|
|
85
|
+
navRoute: "{permission_path}" # MANDATORY for NavRoute attribute
|
|
86
|
+
navRouteSuffix: null # Optional (e.g., "details" → [NavRoute("path", Suffix = "details")])
|
|
87
|
+
dryRun: false
|
|
37
88
|
```
|
|
38
|
-
> Context mapping: `business` → `Business`, `platform` → `Admin`, `personal` → `User`
|
|
39
89
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
90
|
+
**CRITICAL: NavRoute is MANDATORY** - Without it, frontend/backend sync will fail.
|
|
91
|
+
|
|
92
|
+
**Why two calls?**
|
|
93
|
+
- The skill `/controller` assumes the Entity already exists (verified in step-01-analyze.md)
|
|
94
|
+
- Type "dto" generates DTOs without regenerating the Entity
|
|
95
|
+
- Type "controller" generates the Controller with NavRoute and references to DTOs
|
|
96
|
+
|
|
97
|
+
### 4. Parse MCP Responses
|
|
98
|
+
|
|
99
|
+
**From first call (DTOs):**
|
|
100
|
+
- `Application/{Context}/{Application}/{Module}/DTOs/{entityName}ResponseDto.cs` - Response DTO
|
|
101
|
+
- `Application/{Context}/{Application}/{Module}/DTOs/Create{entityName}Dto.cs` - Create request
|
|
102
|
+
- `Application/{Context}/{Application}/{Module}/DTOs/Update{entityName}Dto.cs` - Update request
|
|
103
|
+
|
|
104
|
+
**From second call (Controller):**
|
|
105
|
+
- `Api/Controllers/{area}/{entityName}Controller.cs` - REST Controller **with [NavRoute]**
|
|
106
|
+
|
|
107
|
+
### 5. Present Output to User
|
|
108
|
+
|
|
109
|
+
```markdown
|
|
110
|
+
## Controller Generated via MCP
|
|
111
|
+
|
|
112
|
+
### API Layer
|
|
113
|
+
- `Controllers/{area}/{entityName}Controller.cs`
|
|
114
|
+
- **NavRoute: `{permission_path}`** ✅
|
|
115
|
+
- Endpoints:
|
|
116
|
+
- GET /api/{module} - List all
|
|
117
|
+
- GET /api/{module}/{id} - Get by ID
|
|
118
|
+
- POST /api/{module} - Create
|
|
119
|
+
- PUT /api/{module}/{id} - Update
|
|
120
|
+
- DELETE /api/{module}/{id} - Delete
|
|
121
|
+
|
|
122
|
+
### Application Layer (DTOs)
|
|
123
|
+
- `{Context}/{Application}/{Module}/DTOs/{entityName}ResponseDto.cs`
|
|
124
|
+
- `{Context}/{Application}/{Module}/DTOs/Create{entityName}Dto.cs`
|
|
125
|
+
- `{Context}/{Application}/{Module}/DTOs/Update{entityName}Dto.cs`
|
|
126
|
+
|
|
127
|
+
### ✅ NavRoute Integration
|
|
128
|
+
The controller uses `[NavRoute("{permission_path}")]` which enables:
|
|
129
|
+
- ✅ Automatic frontend route generation
|
|
130
|
+
- ✅ Permission-based navigation sync
|
|
131
|
+
- ✅ Dynamic API routing from Navigation entities
|
|
132
|
+
|
|
133
|
+
### Next Steps
|
|
134
|
+
1. Permissions will be synchronized in step-04-perms.md
|
|
135
|
+
2. Validate conventions with MCP `validate_conventions`
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## MCP RESPONSE HANDLING
|
|
141
|
+
|
|
142
|
+
### Success Case
|
|
143
|
+
|
|
144
|
+
**After first call (DTOs):**
|
|
145
|
+
- Display all generated DTO files
|
|
146
|
+
- Verify DTOs match entity properties
|
|
147
|
+
- Continue to second call
|
|
148
|
+
|
|
149
|
+
**After second call (Controller):**
|
|
150
|
+
- Display controller file
|
|
151
|
+
- Show NavRoute attribute included
|
|
152
|
+
- Highlight frontend/backend sync enabled
|
|
153
|
+
- Store controller info for permission sync
|
|
154
|
+
- Proceed to step-04-perms.md
|
|
155
|
+
|
|
156
|
+
### Error Case
|
|
157
|
+
|
|
158
|
+
**If first call (DTOs) fails:**
|
|
159
|
+
- Display error message
|
|
160
|
+
- Suggest checking entity name format
|
|
161
|
+
- Verify entity properties are defined
|
|
162
|
+
- Verify MCP server is running (`/mcp:healthcheck`)
|
|
163
|
+
- Do NOT proceed to second call
|
|
164
|
+
|
|
165
|
+
**If second call (Controller) fails:**
|
|
166
|
+
- Display error message
|
|
167
|
+
- Note that DTOs were generated successfully
|
|
168
|
+
- Suggest checking navRoute format
|
|
169
|
+
- Verify MCP server is running (`/mcp:healthcheck`)
|
|
170
|
+
- Do NOT proceed to step-04-perms.md
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## NAVROUTE VALIDATION
|
|
175
|
+
|
|
176
|
+
**After generation, verify NavRoute is present:**
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
Generated controller MUST contain:
|
|
180
|
+
[NavRoute("{permission_path}")]
|
|
181
|
+
|
|
182
|
+
WITHOUT NavRoute:
|
|
183
|
+
❌ Frontend routes will be hardcoded
|
|
184
|
+
❌ No automatic permission sync
|
|
185
|
+
❌ Manual navigation management required
|
|
186
|
+
```
|
|
46
187
|
|
|
47
188
|
---
|
|
48
189
|
|
|
@@ -53,7 +194,7 @@ Generated Files:
|
|
|
53
194
|
|
|
54
195
|
| File | Path | Status |
|
|
55
196
|
|------|------|--------|
|
|
56
|
-
| Controller | src/.../Controllers/{area}/{
|
|
197
|
+
| Controller | src/.../Controllers/{area}/{entity}Controller.cs | ✅ Created with [NavRoute] |
|
|
57
198
|
| CreateDto | src/.../DTOs/{module}/{entity}CreateDto.cs | ✅ Created |
|
|
58
199
|
| UpdateDto | src/.../DTOs/{module}/{entity}UpdateDto.cs | ✅ Created |
|
|
59
200
|
| ResponseDto | src/.../DTOs/{module}/{entity}ResponseDto.cs | ✅ Created |
|
|
@@ -63,6 +204,25 @@ Generated Files:
|
|
|
63
204
|
|
|
64
205
|
---
|
|
65
206
|
|
|
207
|
+
## SUCCESS METRICS
|
|
208
|
+
|
|
209
|
+
- MCP scaffold_extension called successfully (DTOs)
|
|
210
|
+
- DTOs generated (ResponseDto, CreateDto, UpdateDto)
|
|
211
|
+
- MCP scaffold_extension called successfully (Controller)
|
|
212
|
+
- Controller generated with **[NavRoute]** attribute
|
|
213
|
+
- NavRoute matches permission_path
|
|
214
|
+
- Controller references DTOs correctly
|
|
215
|
+
- Proceeded to step-04-perms.md
|
|
216
|
+
|
|
217
|
+
## FAILURE MODES
|
|
218
|
+
|
|
219
|
+
- MCP call failed (display error, run /mcp:healthcheck, stop)
|
|
220
|
+
- Invalid entity name (must be PascalCase)
|
|
221
|
+
- Invalid navRoute format
|
|
222
|
+
- MCP server not running
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
66
226
|
## NEXT STEP:
|
|
67
227
|
|
|
68
|
-
After generation complete, proceed to `./step-04-perms.md`
|
|
228
|
+
After controller generation complete, proceed to `./step-04-perms.md`
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
# SmartStack Controller Templates
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
3
|
+
> **⚠️ OBSOLETE - DO NOT USE THESE TEMPLATES MANUALLY**
|
|
4
|
+
>
|
|
5
|
+
> **The `/controller` skill now uses the MCP `scaffold_extension` tool to generate controllers.**
|
|
6
|
+
> These templates are kept for reference only. All controller generation MUST go through the MCP to ensure:
|
|
7
|
+
> - ✅ `[NavRoute]` attribute is included for frontend/backend sync
|
|
8
|
+
> - ✅ Permissions are correctly generated
|
|
9
|
+
> - ✅ Consistency with SmartStack conventions
|
|
10
|
+
>
|
|
11
|
+
> **To generate a controller, use:** `/controller` skill which calls MCP `scaffold_extension` automatically.
|
|
12
|
+
>
|
|
13
|
+
> **If you modify these templates, they will NOT be used.** The MCP templates in `templates/mcp-scaffolding/controller.cs.hbs` are the source of truth.
|
|
5
14
|
|
|
6
15
|
---
|
|
7
16
|
|
|
@@ -279,7 +279,129 @@ If MCP `generate_permissions` fails, use the template above directly with values
|
|
|
279
279
|
|
|
280
280
|
---
|
|
281
281
|
|
|
282
|
-
## 4.
|
|
282
|
+
## 4. ApplicationRolesSeedData.cs (Application-Level, Once per Application)
|
|
283
|
+
|
|
284
|
+
**File:** `Infrastructure/Persistence/Seeding/Data/ApplicationRolesSeedData.cs`
|
|
285
|
+
|
|
286
|
+
### Purpose
|
|
287
|
+
|
|
288
|
+
Creates the 4 standard application-scoped roles: Admin, Manager, Contributor, Viewer.
|
|
289
|
+
|
|
290
|
+
**CRITICAL:** This file is created **ONCE per application** (not per module).
|
|
291
|
+
Without these roles, role-permission mappings in `SeedRolePermissionsAsync()` will fail silently.
|
|
292
|
+
|
|
293
|
+
### GUID Generation Rule
|
|
294
|
+
|
|
295
|
+
```csharp
|
|
296
|
+
// Deterministic GUID from application ID + role type
|
|
297
|
+
private static Guid GenerateRoleGuid(string roleType)
|
|
298
|
+
{
|
|
299
|
+
using var sha256 = System.Security.Cryptography.SHA256.Create();
|
|
300
|
+
var hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes($"role-{ApplicationId}-{roleType}"));
|
|
301
|
+
return new Guid(hash.Take(16).ToArray());
|
|
302
|
+
}
|
|
303
|
+
// roleType values: "admin", "manager", "contributor", "viewer"
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Template
|
|
307
|
+
|
|
308
|
+
```csharp
|
|
309
|
+
using SmartStack.Domain.Platform.Administration.Roles;
|
|
310
|
+
|
|
311
|
+
namespace {BaseNamespace}.Infrastructure.Persistence.Seeding.Data;
|
|
312
|
+
|
|
313
|
+
/// <summary>
|
|
314
|
+
/// Application-scoped role seed data for {AppLabel}.
|
|
315
|
+
/// Defines the 4 standard application roles: Admin, Manager, Contributor, Viewer.
|
|
316
|
+
/// Consumed by IClientSeedDataProvider at application startup.
|
|
317
|
+
/// </summary>
|
|
318
|
+
public static class ApplicationRolesSeedData
|
|
319
|
+
{
|
|
320
|
+
// Application ID from NavigationApplicationSeedData
|
|
321
|
+
private static readonly Guid ApplicationId = {ApplicationGuid};
|
|
322
|
+
|
|
323
|
+
public static readonly Guid AdminRoleId = GenerateRoleGuid("admin");
|
|
324
|
+
public static readonly Guid ManagerRoleId = GenerateRoleGuid("manager");
|
|
325
|
+
public static readonly Guid ContributorRoleId = GenerateRoleGuid("contributor");
|
|
326
|
+
public static readonly Guid ViewerRoleId = GenerateRoleGuid("viewer");
|
|
327
|
+
|
|
328
|
+
public static IEnumerable<ApplicationRoleSeedEntry> GetRoleEntries()
|
|
329
|
+
{
|
|
330
|
+
yield return new ApplicationRoleSeedEntry
|
|
331
|
+
{
|
|
332
|
+
Id = AdminRoleId,
|
|
333
|
+
Code = "admin",
|
|
334
|
+
Name = "{AppLabel} Admin",
|
|
335
|
+
Description = "Full administrative access to {AppLabel}",
|
|
336
|
+
ApplicationId = ApplicationId,
|
|
337
|
+
IsSystem = false,
|
|
338
|
+
IsActive = true,
|
|
339
|
+
DisplayOrder = 1
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
yield return new ApplicationRoleSeedEntry
|
|
343
|
+
{
|
|
344
|
+
Id = ManagerRoleId,
|
|
345
|
+
Code = "manager",
|
|
346
|
+
Name = "{AppLabel} Manager",
|
|
347
|
+
Description = "Management access to {AppLabel} (Create, Read, Update)",
|
|
348
|
+
ApplicationId = ApplicationId,
|
|
349
|
+
IsSystem = false,
|
|
350
|
+
IsActive = true,
|
|
351
|
+
DisplayOrder = 2
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
yield return new ApplicationRoleSeedEntry
|
|
355
|
+
{
|
|
356
|
+
Id = ContributorRoleId,
|
|
357
|
+
Code = "contributor",
|
|
358
|
+
Name = "{AppLabel} Contributor",
|
|
359
|
+
Description = "Contributor access to {AppLabel} (Create, Read)",
|
|
360
|
+
ApplicationId = ApplicationId,
|
|
361
|
+
IsSystem = false,
|
|
362
|
+
IsActive = true,
|
|
363
|
+
DisplayOrder = 3
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
yield return new ApplicationRoleSeedEntry
|
|
367
|
+
{
|
|
368
|
+
Id = ViewerRoleId,
|
|
369
|
+
Code = "viewer",
|
|
370
|
+
Name = "{AppLabel} Viewer",
|
|
371
|
+
Description = "Read-only access to {AppLabel}",
|
|
372
|
+
ApplicationId = ApplicationId,
|
|
373
|
+
IsSystem = false,
|
|
374
|
+
IsActive = true,
|
|
375
|
+
DisplayOrder = 4
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
private static Guid GenerateRoleGuid(string roleType)
|
|
380
|
+
{
|
|
381
|
+
using var sha256 = System.Security.Cryptography.SHA256.Create();
|
|
382
|
+
var hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes($"role-{ApplicationId}-{roleType}"));
|
|
383
|
+
return new Guid(hash.Take(16).ToArray());
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
public class ApplicationRoleSeedEntry
|
|
388
|
+
{
|
|
389
|
+
public Guid Id { get; init; }
|
|
390
|
+
public string Code { get; init; } = null!;
|
|
391
|
+
public string Name { get; init; } = null!;
|
|
392
|
+
public string Description { get; init; } = null!;
|
|
393
|
+
public Guid ApplicationId { get; init; }
|
|
394
|
+
public bool IsSystem { get; init; }
|
|
395
|
+
public bool IsActive { get; init; }
|
|
396
|
+
public int DisplayOrder { get; init; }
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Replace placeholders** with values from PRD and navigation metadata.
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## 5. {Module}RolesSeedData.cs (Per Module)
|
|
283
405
|
|
|
284
406
|
**File:** `Infrastructure/Persistence/Seeding/Data/{ModulePascal}/RolesSeedData.cs`
|
|
285
407
|
|
|
@@ -335,7 +457,7 @@ public class RolePermissionSeedEntry
|
|
|
335
457
|
|
|
336
458
|
---
|
|
337
459
|
|
|
338
|
-
##
|
|
460
|
+
## 6. IClientSeedDataProvider Implementation
|
|
339
461
|
|
|
340
462
|
**File:** `Infrastructure/Persistence/Seeding/{AppPascalName}SeedDataProvider.cs`
|
|
341
463
|
|
|
@@ -343,10 +465,11 @@ public class RolePermissionSeedEntry
|
|
|
343
465
|
|
|
344
466
|
| Rule | Description |
|
|
345
467
|
|------|-------------|
|
|
346
|
-
| Factory methods | `NavigationModule.Create(...)`, `Permission.CreateForModule(...)`, `RolePermission.Create(...)` — NEVER `new Entity()` |
|
|
468
|
+
| Factory methods | `NavigationModule.Create(...)`, `Role.Create(...)`, `Permission.CreateForModule(...)`, `RolePermission.Create(...)` — NEVER `new Entity()` |
|
|
347
469
|
| Idempotence | Each Seed method checks existence before inserting |
|
|
348
|
-
|
|
|
349
|
-
|
|
|
470
|
+
| Execution order | Navigation → Roles → Permissions → RolePermissions (roles MUST exist before mapping) |
|
|
471
|
+
| SaveChanges per group | Navigation -> save -> Roles -> save -> Permissions -> save -> RolePermissions -> save |
|
|
472
|
+
| FK resolution by Code | Parent entities (modules, roles) found by `Code`, not hardcoded GUID |
|
|
350
473
|
| DI registration | `services.AddScoped<IClientSeedDataProvider, {AppPascalName}SeedDataProvider>()` |
|
|
351
474
|
|
|
352
475
|
### Template
|
|
@@ -357,13 +480,14 @@ using SmartStack.Application.Common.Interfaces;
|
|
|
357
480
|
using SmartStack.Application.Common.Interfaces.Seeding;
|
|
358
481
|
using SmartStack.Domain.Navigation;
|
|
359
482
|
using SmartStack.Domain.Platform.Administration.Roles;
|
|
483
|
+
using {BaseNamespace}.Infrastructure.Persistence.Seeding.Data;
|
|
360
484
|
using {BaseNamespace}.Infrastructure.Persistence.Seeding.Data.{Module1Pascal};
|
|
361
485
|
// using {BaseNamespace}.Infrastructure.Persistence.Seeding.Data.{Module2Pascal}; // Add per module
|
|
362
486
|
|
|
363
487
|
namespace {BaseNamespace}.Infrastructure.Persistence.Seeding;
|
|
364
488
|
|
|
365
489
|
/// <summary>
|
|
366
|
-
/// Seeds {AppLabel} navigation, permissions, and role-permission data
|
|
490
|
+
/// Seeds {AppLabel} navigation, roles, permissions, and role-permission data
|
|
367
491
|
/// into the SmartStack Core schema at application startup.
|
|
368
492
|
/// </summary>
|
|
369
493
|
public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
|
|
@@ -420,6 +544,28 @@ public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
|
|
|
420
544
|
await ((DbContext)context).SaveChangesAsync(ct);
|
|
421
545
|
}
|
|
422
546
|
|
|
547
|
+
public async Task SeedRolesAsync(ICoreDbContext context, CancellationToken ct)
|
|
548
|
+
{
|
|
549
|
+
// Check idempotence
|
|
550
|
+
var applicationId = ApplicationRolesSeedData.ApplicationId;
|
|
551
|
+
var exists = await context.Roles
|
|
552
|
+
.AnyAsync(r => r.ApplicationId == applicationId, ct);
|
|
553
|
+
if (exists) return;
|
|
554
|
+
|
|
555
|
+
// Create application-scoped roles (Admin, Manager, Contributor, Viewer)
|
|
556
|
+
foreach (var entry in ApplicationRolesSeedData.GetRoleEntries())
|
|
557
|
+
{
|
|
558
|
+
var role = Role.Create(
|
|
559
|
+
entry.Code,
|
|
560
|
+
entry.Name,
|
|
561
|
+
entry.Description,
|
|
562
|
+
entry.ApplicationId,
|
|
563
|
+
entry.IsSystem);
|
|
564
|
+
context.Roles.Add(role);
|
|
565
|
+
}
|
|
566
|
+
await ((DbContext)context).SaveChangesAsync(ct);
|
|
567
|
+
}
|
|
568
|
+
|
|
423
569
|
public async Task SeedPermissionsAsync(ICoreDbContext context, CancellationToken ct)
|
|
424
570
|
{
|
|
425
571
|
var exists = await context.Permissions
|
|
@@ -495,43 +641,49 @@ services.AddScoped<IClientSeedDataProvider, {AppPascalName}SeedDataProvider>();
|
|
|
495
641
|
|
|
496
642
|
---
|
|
497
643
|
|
|
498
|
-
##
|
|
644
|
+
## 7. Multi-Module Handling
|
|
499
645
|
|
|
500
646
|
When processing multiple modules in the same ralph-loop run:
|
|
501
647
|
|
|
502
648
|
### Module 1 (first): Creates everything from scratch
|
|
503
649
|
|
|
504
|
-
1. `
|
|
505
|
-
2. `{Module1}
|
|
506
|
-
3. `{Module1}
|
|
507
|
-
4. `{
|
|
508
|
-
5.
|
|
650
|
+
1. `ApplicationRolesSeedData.cs` (application-level, once per app)
|
|
651
|
+
2. `{Module1}NavigationSeedData.cs`
|
|
652
|
+
3. `{Module1}PermissionsSeedData.cs`
|
|
653
|
+
4. `{Module1}RolesSeedData.cs`
|
|
654
|
+
5. `{AppPascalName}SeedDataProvider.cs` (new, with 4 methods)
|
|
655
|
+
6. DI registration (new)
|
|
509
656
|
|
|
510
657
|
### Module 2+ (subsequent): Append to existing provider
|
|
511
658
|
|
|
512
|
-
1. `
|
|
513
|
-
2. `{Module2}
|
|
514
|
-
3. `{Module2}
|
|
515
|
-
4. `{
|
|
516
|
-
5.
|
|
659
|
+
1. `ApplicationRolesSeedData.cs` (already exists — skip)
|
|
660
|
+
2. `{Module2}NavigationSeedData.cs` (new file)
|
|
661
|
+
3. `{Module2}PermissionsSeedData.cs` (new file)
|
|
662
|
+
4. `{Module2}RolesSeedData.cs` (new file)
|
|
663
|
+
5. `{AppPascalName}SeedDataProvider.cs` (**modify** — add using, add entries in Navigation/Permissions/RolePermissions methods)
|
|
664
|
+
6. DI registration (already exists — skip)
|
|
517
665
|
|
|
518
|
-
**Detection:** Check if `{AppPascalName}SeedDataProvider.cs` exists. If yes, READ it and ADD the new module's entries to
|
|
666
|
+
**Detection:** Check if `{AppPascalName}SeedDataProvider.cs` exists. If yes, READ it and ADD the new module's entries to the appropriate methods (Navigation, Permissions, RolePermissions). Do NOT modify SeedRolesAsync().
|
|
519
667
|
|
|
520
668
|
---
|
|
521
669
|
|
|
522
|
-
##
|
|
670
|
+
## 8. Verification Checklist (BLOCKING)
|
|
523
671
|
|
|
524
672
|
Before marking the task as completed, verify ALL:
|
|
525
673
|
|
|
526
674
|
- [ ] Deterministic GUIDs (NEVER `Guid.NewGuid()`) — SHA256 of path
|
|
527
675
|
- [ ] 4 languages for each navigation entity (fr, en, it, de)
|
|
676
|
+
- [ ] `ApplicationRolesSeedData.cs` created (once per application)
|
|
677
|
+
- [ ] 4 application roles defined: Admin, Manager, Contributor, Viewer
|
|
678
|
+
- [ ] Each role has a valid `Code` value ("admin", "manager", "contributor", "viewer")
|
|
528
679
|
- [ ] `Permissions.cs` constants match seed data paths
|
|
529
680
|
- [ ] MCP `generate_permissions` called (or fallback used)
|
|
530
681
|
- [ ] Role-permission mappings assigned (Admin, Manager, Contributor, Viewer)
|
|
531
|
-
- [ ] `IClientSeedDataProvider` generated with
|
|
682
|
+
- [ ] `IClientSeedDataProvider` generated with 4 methods (Navigation, Roles, Permissions, RolePermissions)
|
|
683
|
+
- [ ] Execution order: Navigation → Roles → Permissions → RolePermissions
|
|
532
684
|
- [ ] Each Seed method is idempotent (checks existence before inserting)
|
|
533
685
|
- [ ] Factory methods used throughout (NEVER `new Entity()`)
|
|
534
|
-
- [ ] `SaveChangesAsync` called per group (Navigation → Permissions → RolePermissions)
|
|
686
|
+
- [ ] `SaveChangesAsync` called per group (Navigation → Roles → Permissions → RolePermissions)
|
|
535
687
|
- [ ] DI registration added: `services.AddScoped<IClientSeedDataProvider, ...>()`
|
|
536
688
|
- [ ] `dotnet build` passes after generation
|
|
537
689
|
|