@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
|
@@ -49,134 +49,10 @@ From previous steps:
|
|
|
49
49
|
|
|
50
50
|
## FILES TO GENERATE
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
**
|
|
55
|
-
|
|
56
|
-
Where `{AppPascalName}` is derived from the application code (e.g., `free-bike` -> `FreeBike`).
|
|
57
|
-
|
|
58
|
-
**Pattern:**
|
|
59
|
-
|
|
60
|
-
```csharp
|
|
61
|
-
using Microsoft.EntityFrameworkCore;
|
|
62
|
-
using SmartStack.Application.Common.Interfaces;
|
|
63
|
-
using SmartStack.Domain.Navigation;
|
|
64
|
-
using SmartStack.Domain.Platform.Administration.Roles;
|
|
65
|
-
|
|
66
|
-
namespace {BaseNamespace}.Infrastructure.Persistence.Seeding;
|
|
67
|
-
|
|
68
|
-
/// <summary>
|
|
69
|
-
/// Seeds {AppLabel} navigation, permissions, and role-permission data
|
|
70
|
-
/// into the SmartStack Core schema at application startup.
|
|
71
|
-
/// Implements <see cref="IClientSeedDataProvider"/> for runtime seeding
|
|
72
|
-
/// (no Core migrations required).
|
|
73
|
-
/// </summary>
|
|
74
|
-
public class {AppPascalName}SeedDataProvider : IClientSeedDataProvider
|
|
75
|
-
{
|
|
76
|
-
public int Order => 100;
|
|
77
|
-
|
|
78
|
-
public async Task SeedNavigationAsync(ICoreDbContext context, CancellationToken ct)
|
|
79
|
-
{
|
|
80
|
-
// Check idempotence
|
|
81
|
-
var exists = await context.NavigationApplications
|
|
82
|
-
.AnyAsync(a => a.Code == "{app_code}", ct);
|
|
83
|
-
if (exists) return;
|
|
84
|
-
|
|
85
|
-
// 1. Retrieve the parent context ("business", "platform", etc.)
|
|
86
|
-
var parentContext = await context.NavigationContexts
|
|
87
|
-
.FirstAsync(c => c.Code == "{context_code}", ct);
|
|
88
|
-
|
|
89
|
-
// 2. Create the application
|
|
90
|
-
var app = NavigationApplication.Create(
|
|
91
|
-
parentContext.Id,
|
|
92
|
-
"{app_code}",
|
|
93
|
-
"{app_label_en}",
|
|
94
|
-
"{app_desc_en}",
|
|
95
|
-
"{app_icon}",
|
|
96
|
-
IconType.Lucide,
|
|
97
|
-
"/{context_code}/{app_code}",
|
|
98
|
-
{display_order});
|
|
99
|
-
context.NavigationApplications.Add(app);
|
|
100
|
-
await ((DbContext)context).SaveChangesAsync(ct);
|
|
101
|
-
|
|
102
|
-
// 3. Create modules
|
|
103
|
-
// Use GUIDs and data from {Module}NavigationSeedData.cs
|
|
104
|
-
foreach (var moduleData in GetModuleSeedEntries(app.Id))
|
|
105
|
-
{
|
|
106
|
-
var module = NavigationModule.Create(
|
|
107
|
-
moduleData.ApplicationId,
|
|
108
|
-
moduleData.Code,
|
|
109
|
-
moduleData.Label,
|
|
110
|
-
moduleData.Description,
|
|
111
|
-
moduleData.Icon,
|
|
112
|
-
IconType.Lucide,
|
|
113
|
-
moduleData.Route,
|
|
114
|
-
moduleData.DisplayOrder);
|
|
115
|
-
context.NavigationModules.Add(module);
|
|
116
|
-
}
|
|
117
|
-
await ((DbContext)context).SaveChangesAsync(ct);
|
|
118
|
-
|
|
119
|
-
// 4. Create translations (4 languages per entity)
|
|
120
|
-
// Use data from {Module}NavigationTranslationSeedData.cs
|
|
121
|
-
// ...
|
|
122
|
-
await ((DbContext)context).SaveChangesAsync(ct);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
public async Task SeedPermissionsAsync(ICoreDbContext context, CancellationToken ct)
|
|
126
|
-
{
|
|
127
|
-
// Check idempotence
|
|
128
|
-
var exists = await context.Permissions
|
|
129
|
-
.AnyAsync(p => p.Path == "{full_path}.*", ct);
|
|
130
|
-
if (exists) return;
|
|
131
|
-
|
|
132
|
-
// Retrieve modules by Code for FK resolution
|
|
133
|
-
// Use data from {Module}PermissionSeedData.cs
|
|
134
|
-
// Create via Permission.CreateForModule(...) and Permission.CreateWildcard(...)
|
|
135
|
-
// ...
|
|
136
|
-
await ((DbContext)context).SaveChangesAsync(ct);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
public async Task SeedRolePermissionsAsync(ICoreDbContext context, CancellationToken ct)
|
|
140
|
-
{
|
|
141
|
-
// Check idempotence
|
|
142
|
-
var exists = await context.RolePermissions
|
|
143
|
-
.AnyAsync(rp => rp.Permission!.Path.StartsWith("{full_path}."), ct);
|
|
144
|
-
if (exists) return;
|
|
145
|
-
|
|
146
|
-
// Retrieve existing roles and created permissions
|
|
147
|
-
// Use data from {Module}RolePermissionSeedData.cs
|
|
148
|
-
// Create via RolePermission.Create(roleId, permissionId, "system")
|
|
149
|
-
// ...
|
|
150
|
-
await ((DbContext)context).SaveChangesAsync(ct);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Private helper methods fed by SeedData classes
|
|
154
|
-
// ...
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### 2. DI Registration
|
|
159
|
-
|
|
160
|
-
Modify `Infrastructure/DependencyInjection.cs` of the client project:
|
|
161
|
-
|
|
162
|
-
```csharp
|
|
163
|
-
// Add using:
|
|
164
|
-
using SmartStack.Application.Common.Interfaces;
|
|
165
|
-
|
|
166
|
-
// In the registration method:
|
|
167
|
-
services.AddScoped<IClientSeedDataProvider, {AppPascalName}SeedDataProvider>();
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
---
|
|
171
|
-
|
|
172
|
-
## CRITICAL RULES
|
|
173
|
-
|
|
174
|
-
1. **Factory methods mandatory**: `NavigationModule.Create(...)`, `Permission.CreateForModule(...)`, `RolePermission.Create(...)` - NEVER `new Entity()`
|
|
175
|
-
2. **Idempotence**: Each Seed method checks existence before inserting
|
|
176
|
-
3. **SaveChangesAsync per group**: Navigation -> save -> Permissions -> save -> RolePermissions -> save
|
|
177
|
-
4. **Deterministic GUIDs**: Use IDs from SeedData classes (not Guid.NewGuid())
|
|
178
|
-
5. **Resolve FK by Code**: Parent modules are found by `Code`, not hardcoded GUID
|
|
179
|
-
6. **Order property**: Use `100` as default. If multiple providers exist, they run in Order sequence
|
|
52
|
+
See [references/provider-template.md](../references/provider-template.md) for the complete implementation:
|
|
53
|
+
- **Provider class** (`{AppPascalName}SeedDataProvider.cs`) with 3 seed methods (Navigation, Permissions, RolePermissions)
|
|
54
|
+
- **DI registration** pattern for `Infrastructure/DependencyInjection.cs`
|
|
55
|
+
- **6 critical rules** (factory methods, idempotence, SaveChangesAsync order, deterministic GUIDs, FK by Code, Order property)
|
|
180
56
|
|
|
181
57
|
---
|
|
182
58
|
|
|
@@ -148,79 +148,9 @@ questions:
|
|
|
148
148
|
|
|
149
149
|
#### If User Selects YES:
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
**
|
|
154
|
-
|
|
155
|
-
1. **`Infrastructure/Persistence/Seeding/Data/{Domain}/{EntityName}SeedData.cs`**
|
|
156
|
-
|
|
157
|
-
Follow the SmartStack.app pattern (same architecture as core):
|
|
158
|
-
- Static class with `internal static IEnumerable<{EntityName}SeedItem> GetAll{EntityName}s()`
|
|
159
|
-
- Use deterministic GUIDs (NEVER `Guid.NewGuid()`)
|
|
160
|
-
- Include 3-5 sample entities with varied, realistic data
|
|
161
|
-
- Internal record class `{EntityName}SeedItem` with all entity properties
|
|
162
|
-
- For multi-tenant entities: organize by tenant using `GetTenant1{EntityName}s()` helper methods
|
|
163
|
-
- Reference existing tenant/user IDs from `TenantSeedData`/`UserSeedData` for foreign keys
|
|
164
|
-
|
|
165
|
-
```csharp
|
|
166
|
-
// Infrastructure/Persistence/Seeding/Data/{Domain}/{EntityName}SeedData.cs
|
|
167
|
-
|
|
168
|
-
public static class {EntityName}SeedData
|
|
169
|
-
{
|
|
170
|
-
public static readonly Guid Sample1Id = Guid.Parse("...");
|
|
171
|
-
public static readonly Guid Sample2Id = Guid.Parse("...");
|
|
172
|
-
public static readonly Guid Sample3Id = Guid.Parse("...");
|
|
173
|
-
|
|
174
|
-
internal static IEnumerable<{EntityName}SeedItem> GetAll{EntityName}s()
|
|
175
|
-
{
|
|
176
|
-
return new[]
|
|
177
|
-
{
|
|
178
|
-
new {EntityName}SeedItem { Id = Sample1Id, /* ... */ },
|
|
179
|
-
new {EntityName}SeedItem { Id = Sample2Id, /* ... */ },
|
|
180
|
-
new {EntityName}SeedItem { Id = Sample3Id, /* ... */ }
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
internal class {EntityName}SeedItem
|
|
186
|
-
{
|
|
187
|
-
public Guid Id { get; init; }
|
|
188
|
-
// ... all required entity properties
|
|
189
|
-
}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
2. **Update `Infrastructure/Persistence/Seeding/DevDataSeeder.cs`**
|
|
193
|
-
- Add `using` for the new SeedData namespace
|
|
194
|
-
- Add `await Seed{EntityName}sAsync(cancellationToken);` in `SeedAsync()` method
|
|
195
|
-
- Add private seeding method:
|
|
196
|
-
|
|
197
|
-
```csharp
|
|
198
|
-
private async Task Seed{EntityName}sAsync(CancellationToken cancellationToken)
|
|
199
|
-
{
|
|
200
|
-
_logger.LogInformation("Seeding demo {EntityName}s...");
|
|
201
|
-
|
|
202
|
-
var existingCount = await _context.{EntityName}s.CountAsync(cancellationToken);
|
|
203
|
-
if (existingCount > 0)
|
|
204
|
-
{
|
|
205
|
-
_logger.LogWarning("{EntityName}s already seeded ({Count} exist), skipping.", existingCount);
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
var createdCount = 0;
|
|
210
|
-
foreach (var seedItem in {EntityName}SeedData.GetAll{EntityName}s())
|
|
211
|
-
{
|
|
212
|
-
var entity = {EntityName}.Create(/* map seedItem properties */);
|
|
213
|
-
typeof({EntityName}).GetProperty("Id")?.SetValue(entity, seedItem.Id);
|
|
214
|
-
_context.{EntityName}s.Add(entity);
|
|
215
|
-
createdCount++;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (createdCount > 0)
|
|
219
|
-
await _context.SaveChangesAsync(cancellationToken);
|
|
220
|
-
|
|
221
|
-
_logger.LogInformation("Created {Count} demo {EntityName}s.", createdCount);
|
|
222
|
-
}
|
|
223
|
-
```
|
|
151
|
+
See [references/backend-entity-seeding.md](../references/backend-entity-seeding.md) for the full seeding pattern:
|
|
152
|
+
1. **SeedData file** (`{EntityName}SeedData.cs`) — static class with deterministic GUIDs, 3-5 samples
|
|
153
|
+
2. **DevDataSeeder update** — add `Seed{EntityName}sAsync()` method with idempotent check
|
|
224
154
|
|
|
225
155
|
#### If User Selects NO:
|
|
226
156
|
|
|
@@ -246,58 +176,10 @@ Store entity information for frontend generation:
|
|
|
246
176
|
|
|
247
177
|
## CONTROLLER NAVROUTE AND FOLDER HIERARCHY
|
|
248
178
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
```
|
|
254
|
-
Api/Controllers/
|
|
255
|
-
├── Admin/ ← platform.administration
|
|
256
|
-
│ ├── {Application}/ ← Application sub-folder (e.g., AI/, Communications/, Tenants/)
|
|
257
|
-
│ │ └── {EntityName}Controller.cs
|
|
258
|
-
│ └── {EntityName}Controller.cs ← Direct controllers (no application sub-folder)
|
|
259
|
-
├── Business/ ← business.*
|
|
260
|
-
│ └── {EntityName}Controller.cs
|
|
261
|
-
├── Support/ ← platform.support
|
|
262
|
-
│ └── {EntityName}Controller.cs
|
|
263
|
-
├── User/ ← personal.*
|
|
264
|
-
│ └── {EntityName}Controller.cs
|
|
265
|
-
└── {SharedControllers}.cs ← Root-level (Auth, Config, Navigation, etc.)
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Context-to-Folder Mapping
|
|
269
|
-
|
|
270
|
-
| NavRoute Context | Controller Folder | Example |
|
|
271
|
-
|-----------------|-------------------|---------|
|
|
272
|
-
| `platform.administration` | `Admin` | `Controllers/Admin/TenantsController.cs` |
|
|
273
|
-
| `platform.administration.{app}` | `Admin/{App}` | `Controllers/Admin/AI/AiPromptsController.cs` |
|
|
274
|
-
| `platform.support` | `Support` | `Controllers/Support/TicketsController.cs` |
|
|
275
|
-
| `business.*` | `Business` | `Controllers/Business/MyTicketsController.cs` |
|
|
276
|
-
| `personal.*` | `User` | `Controllers/User/PreferencesController.cs` |
|
|
277
|
-
|
|
278
|
-
### Controller Attributes
|
|
279
|
-
|
|
280
|
-
The generated controller uses NavRoute attribute:
|
|
281
|
-
|
|
282
|
-
```csharp
|
|
283
|
-
[NavRoute("{full_path}")]
|
|
284
|
-
[ApiController]
|
|
285
|
-
[Authorize]
|
|
286
|
-
public class {EntityName}Controller : ControllerBase
|
|
287
|
-
{
|
|
288
|
-
[HttpGet]
|
|
289
|
-
[RequirePermission(Permissions.{Context}.{Application}.{Module}.Read)]
|
|
290
|
-
public async Task<ActionResult<IEnumerable<{EntityName}Dto>>> GetAll() { ... }
|
|
291
|
-
|
|
292
|
-
// ... other CRUD methods
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
This ensures:
|
|
297
|
-
- API route is derived from navigation path
|
|
298
|
-
- Permissions use the constants from Permissions.cs
|
|
299
|
-
- Frontend can discover API path from NavRoute registry
|
|
300
|
-
- Controller file is in the correct context/application folder
|
|
179
|
+
See [references/backend-controller-hierarchy.md](../references/backend-controller-hierarchy.md) for the complete reference:
|
|
180
|
+
- Controller file organization (Admin/Business/Support/User folders)
|
|
181
|
+
- Context-to-folder mapping table
|
|
182
|
+
- NavRoute attribute C# template with RequirePermission
|
|
301
183
|
|
|
302
184
|
---
|
|
303
185
|
|
|
@@ -323,234 +205,22 @@ If MCP call fails:
|
|
|
323
205
|
|
|
324
206
|
## POST-GENERATION VERIFICATION (MANDATORY)
|
|
325
207
|
|
|
326
|
-
**Before proceeding to step-05, run
|
|
327
|
-
|
|
328
|
-
### Check 1: Backend Build (BLOCKING)
|
|
329
|
-
|
|
330
|
-
```bash
|
|
331
|
-
dotnet build {SolutionName}.sln --no-restore
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
IF build fails:
|
|
335
|
-
- Read the error output carefully
|
|
336
|
-
- Fix compilation errors in generated files (common: missing `using`, wrong namespace, type mismatch)
|
|
337
|
-
- Re-run build until it succeeds
|
|
338
|
-
- DO NOT proceed to step-05 until the backend builds successfully
|
|
339
|
-
|
|
340
|
-
### Check 2: DbSet Registration (BLOCKING)
|
|
341
|
-
|
|
342
|
-
Verify the entity DbSet is registered in the DbContext interface:
|
|
343
|
-
|
|
344
|
-
```
|
|
345
|
-
Search for: DbSet<{EntityName}>
|
|
346
|
-
In: **/I{DbContextName}.cs or **/{DbContextName}.cs
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
IF NOT found: Add the DbSet declaration immediately:
|
|
350
|
-
```csharp
|
|
351
|
-
public DbSet<{EntityName}> {EntityName}s => Set<{EntityName}>();
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
### Check 3: DI Registration (BLOCKING)
|
|
208
|
+
**Before proceeding to step-05, run ALL checks.**
|
|
355
209
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
```
|
|
359
|
-
Search for: I{EntityName}Service
|
|
360
|
-
In: **/DependencyInjection.cs
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
IF NOT found: Add the service registration immediately:
|
|
364
|
-
```csharp
|
|
365
|
-
services.AddScoped<I{EntityName}Service, {EntityName}Service>();
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
### Check 4: RequirePermission Attributes (BLOCKING)
|
|
369
|
-
|
|
370
|
-
Verify ALL controller actions have `[RequirePermission]` attributes:
|
|
371
|
-
|
|
372
|
-
```
|
|
373
|
-
Search for: [HttpGet], [HttpPost], [HttpPut], [HttpDelete]
|
|
374
|
-
In: **/Controllers/**/{EntityName}Controller.cs
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
Each HTTP action MUST have a corresponding `[RequirePermission(Permissions.{Context}.{Application}.{Module}.{Action})]`.
|
|
378
|
-
IF any action is missing the attribute: Add it immediately.
|
|
379
|
-
|
|
380
|
-
### Check 5: Entity Configuration (BLOCKING)
|
|
381
|
-
|
|
382
|
-
Verify the EF Core configuration file exists and has correct structure:
|
|
383
|
-
|
|
384
|
-
```
|
|
385
|
-
Search for: {EntityName}Configuration
|
|
386
|
-
In: **/Persistence/Configurations/**/*Configuration.cs
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
Verify:
|
|
390
|
-
- `builder.ToTable("{table_prefix}{EntityName}s")` uses the correct table prefix
|
|
391
|
-
- `builder.HasKey(e => e.Id)` is present
|
|
392
|
-
- `builder.HasIndex` is defined for unique fields (e.g., Code)
|
|
393
|
-
|
|
394
|
-
IF configuration is incomplete: Fix it before continuing.
|
|
395
|
-
|
|
396
|
-
### Check 5b: Seeding Infrastructure (BLOCKING - first entity only)
|
|
397
|
-
|
|
398
|
-
**If this is the FIRST entity created in this project (no existing DevDataSeeder):**
|
|
399
|
-
|
|
400
|
-
Scaffold the full seeding infrastructure following the SmartStack.app architecture:
|
|
401
|
-
|
|
402
|
-
1. **Create `Infrastructure/Persistence/Seeding/Data/SeedConstants.cs`**
|
|
403
|
-
|
|
404
|
-
```csharp
|
|
405
|
-
namespace {BaseNamespace}.Infrastructure.Persistence.Seeding.Data;
|
|
406
|
-
|
|
407
|
-
/// <summary>
|
|
408
|
-
/// Shared constants for seed data across all modules.
|
|
409
|
-
/// </summary>
|
|
410
|
-
public static class SeedConstants
|
|
411
|
-
{
|
|
412
|
-
public static readonly DateTime SeedDate = new(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
413
|
-
}
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
2. **Create `Infrastructure/Persistence/Seeding/DevDataSeeder.cs`**
|
|
417
|
-
|
|
418
|
-
```csharp
|
|
419
|
-
using Microsoft.EntityFrameworkCore;
|
|
420
|
-
using Microsoft.Extensions.Logging;
|
|
421
|
-
using SmartStack.Application.Common.Interfaces;
|
|
422
|
-
|
|
423
|
-
namespace {BaseNamespace}.Infrastructure.Persistence.Seeding;
|
|
424
|
-
|
|
425
|
-
/// <summary>
|
|
426
|
-
/// Seeds development/demo data at application startup.
|
|
427
|
-
/// Only runs when EnableDevSeeding = true.
|
|
428
|
-
/// </summary>
|
|
429
|
-
public class DevDataSeeder : IDevDataSeeder
|
|
430
|
-
{
|
|
431
|
-
private readonly ExtensionsDbContext _context;
|
|
432
|
-
private readonly ILogger<DevDataSeeder> _logger;
|
|
433
|
-
|
|
434
|
-
public DevDataSeeder(ExtensionsDbContext context, ILogger<DevDataSeeder> logger)
|
|
435
|
-
{
|
|
436
|
-
_context = context;
|
|
437
|
-
_logger = logger;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
public async Task SeedAsync(CancellationToken cancellationToken = default)
|
|
441
|
-
{
|
|
442
|
-
_logger.LogInformation("Starting development data seeding...");
|
|
443
|
-
// Add Seed{Entity}sAsync calls here as entities are created
|
|
444
|
-
_logger.LogInformation("Development data seeding complete.");
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
3. **Register DevDataSeeder in `Infrastructure/DependencyInjection.cs`:**
|
|
450
|
-
```csharp
|
|
451
|
-
services.AddScoped<IDevDataSeeder, DevDataSeeder>();
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
**If DevDataSeeder already exists:** Skip this check.
|
|
455
|
-
|
|
456
|
-
### Check 5c: SqlObjects Directory (BLOCKING - first entity only)
|
|
457
|
-
|
|
458
|
-
**If this is the FIRST entity in the project (no existing SqlObjectHelper):**
|
|
459
|
-
|
|
460
|
-
Scaffold the SQL objects infrastructure:
|
|
461
|
-
|
|
462
|
-
1. **Create `Infrastructure/Persistence/SqlObjects/SqlObjectHelper.cs`**
|
|
463
|
-
|
|
464
|
-
```csharp
|
|
465
|
-
using System.Reflection;
|
|
466
|
-
using Microsoft.EntityFrameworkCore.Migrations;
|
|
467
|
-
|
|
468
|
-
namespace {BaseNamespace}.Infrastructure.Persistence.SqlObjects;
|
|
469
|
-
|
|
470
|
-
/// <summary>
|
|
471
|
-
/// Helper for applying SQL objects (Functions, Views, Stored Procedures) from embedded resources.
|
|
472
|
-
/// SQL files use CREATE OR ALTER for idempotency — safe to re-run on any migration or squash.
|
|
473
|
-
/// </summary>
|
|
474
|
-
public static class SqlObjectHelper
|
|
475
|
-
{
|
|
476
|
-
private static readonly Assembly Assembly = typeof(SqlObjectHelper).Assembly;
|
|
477
|
-
private const string ResourcePrefix = "{BaseNamespace}.Infrastructure.Persistence.SqlObjects.";
|
|
478
|
-
|
|
479
|
-
public static void ApplyAll(MigrationBuilder migrationBuilder)
|
|
480
|
-
{
|
|
481
|
-
ApplyAllFunctions(migrationBuilder);
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
public static void ApplyAllFunctions(MigrationBuilder migrationBuilder)
|
|
485
|
-
{
|
|
486
|
-
ApplyCategory(migrationBuilder, "Functions");
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
public static void ApplyOne(MigrationBuilder migrationBuilder, string resourceName)
|
|
490
|
-
{
|
|
491
|
-
var sql = ReadSqlObject(resourceName);
|
|
492
|
-
migrationBuilder.Sql(sql);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
public static string ReadSqlObject(string resourceName)
|
|
496
|
-
{
|
|
497
|
-
var fullName = ResourcePrefix + resourceName;
|
|
498
|
-
using var stream = Assembly.GetManifestResourceStream(fullName)
|
|
499
|
-
?? throw new InvalidOperationException(
|
|
500
|
-
$"SQL object resource '{fullName}' not found. " +
|
|
501
|
-
$"Ensure the .sql file is marked as EmbeddedResource in the .csproj.");
|
|
502
|
-
using var reader = new StreamReader(stream);
|
|
503
|
-
return reader.ReadToEnd();
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
private static void ApplyCategory(MigrationBuilder migrationBuilder, string category)
|
|
507
|
-
{
|
|
508
|
-
var prefix = ResourcePrefix + category + ".";
|
|
509
|
-
var resources = Assembly.GetManifestResourceNames()
|
|
510
|
-
.Where(n => n.StartsWith(prefix, StringComparison.Ordinal)
|
|
511
|
-
&& n.EndsWith(".sql", StringComparison.Ordinal))
|
|
512
|
-
.OrderBy(n => n, StringComparer.Ordinal);
|
|
513
|
-
|
|
514
|
-
foreach (var resource in resources)
|
|
515
|
-
{
|
|
516
|
-
using var stream = Assembly.GetManifestResourceStream(resource)!;
|
|
517
|
-
using var reader = new StreamReader(stream);
|
|
518
|
-
migrationBuilder.Sql(reader.ReadToEnd());
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
2. **Create empty directory `Infrastructure/Persistence/SqlObjects/Functions/`**
|
|
525
|
-
- Where `.sql` files for TVFs and scalar functions will be stored
|
|
526
|
-
|
|
527
|
-
3. **Ensure `.csproj` has EmbeddedResource glob for SQL files:**
|
|
528
|
-
```xml
|
|
529
|
-
<ItemGroup>
|
|
530
|
-
<EmbeddedResource Include="Persistence\SqlObjects\**\*.sql" />
|
|
531
|
-
</ItemGroup>
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
**If SqlObjectHelper already exists:** Skip this check.
|
|
535
|
-
|
|
536
|
-
### Check 6: Convention Validation (RECOMMENDED)
|
|
537
|
-
|
|
538
|
-
Run MCP convention validation on the generated backend code:
|
|
539
|
-
|
|
540
|
-
```
|
|
541
|
-
Tool: mcp__smartstack__validate_conventions
|
|
542
|
-
Args:
|
|
543
|
-
target: "backend"
|
|
544
|
-
scope: "{entity_name}"
|
|
545
|
-
```
|
|
210
|
+
See [references/backend-verification.md](../references/backend-verification.md) for the complete verification checklist:
|
|
546
211
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
212
|
+
| Check | Type | What |
|
|
213
|
+
|-------|------|------|
|
|
214
|
+
| 1. Backend Build | BLOCKING | `dotnet build --no-restore` must succeed |
|
|
215
|
+
| 2. DbSet Registration | BLOCKING | `DbSet<{EntityName}>` in DbContext |
|
|
216
|
+
| 3. DI Registration | BLOCKING | `I{EntityName}Service` in DependencyInjection.cs |
|
|
217
|
+
| 4. RequirePermission | BLOCKING | All HTTP actions have `[RequirePermission]` |
|
|
218
|
+
| 5. Entity Configuration | BLOCKING | Table prefix, HasKey, HasIndex |
|
|
219
|
+
| 5b. Seeding Infrastructure | BLOCKING (first entity) | SeedConstants + DevDataSeeder + DI |
|
|
220
|
+
| 5c. SqlObjects Directory | BLOCKING (first entity) | SqlObjectHelper + Functions/ + .csproj EmbeddedResource |
|
|
221
|
+
| 6. Convention Validation | RECOMMENDED | `mcp__smartstack__validate_conventions` |
|
|
552
222
|
|
|
553
|
-
IF
|
|
223
|
+
IF any BLOCKING check fails: Fix before proceeding to step-05.
|
|
554
224
|
|
|
555
225
|
---
|
|
556
226
|
|
|
@@ -192,38 +192,9 @@ If the generated translations need customization (e.g., replacing generic title
|
|
|
192
192
|
|
|
193
193
|
## ROUTING RULES
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
**
|
|
198
|
-
|
|
199
|
-
```tsx
|
|
200
|
-
// ✅ CORRECT - Inside BusinessLayout (shell renders: header + AvatarMenu + sidebar)
|
|
201
|
-
<Route path="/business" element={<BusinessLayout />}>
|
|
202
|
-
<Route path="sales/products" element={<ProductsPage />} />
|
|
203
|
-
</Route>
|
|
204
|
-
|
|
205
|
-
// ❌ FORBIDDEN - Outside layout (NO shell, NO header, NO AvatarMenu!)
|
|
206
|
-
<Route path="/business/sales/products" element={<ProductsPage />} />
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Rule 2: Use nested routes (not flat)
|
|
210
|
-
|
|
211
|
-
**CRITICAL:** SmartStack requires NESTED routes within the layout:
|
|
212
|
-
|
|
213
|
-
```tsx
|
|
214
|
-
// ✅ CORRECT - Nested routes inside layout
|
|
215
|
-
<Route path="/business" element={<BusinessLayout />}>
|
|
216
|
-
<Route path="sales">
|
|
217
|
-
<Route index element={<Navigate to="products" replace />} />
|
|
218
|
-
<Route path="products" element={<ProductsPage />} />
|
|
219
|
-
<Route path="orders" element={<OrdersPage />} />
|
|
220
|
-
</Route>
|
|
221
|
-
</Route>
|
|
222
|
-
|
|
223
|
-
// ❌ FORBIDDEN - Flat routes (cause redirect issues + bypass layout)
|
|
224
|
-
<Route path="/business/sales" element={<Navigate to="products" />} />
|
|
225
|
-
<Route path="/business/sales/products" element={<ProductsPage />} />
|
|
226
|
-
```
|
|
195
|
+
See [references/frontend-verification.md](../references/frontend-verification.md) for detailed routing rules with code examples:
|
|
196
|
+
- **Rule 1:** Routes MUST be inside Layout wrappers (BusinessLayout, AdminLayout, UserLayout)
|
|
197
|
+
- **Rule 2:** Use NESTED routes (not flat) — flat routes bypass layout and break the shell
|
|
227
198
|
|
|
228
199
|
---
|
|
229
200
|
|
|
@@ -247,76 +218,16 @@ locales/
|
|
|
247
218
|
|
|
248
219
|
## POST-GENERATION VERIFICATION (MANDATORY)
|
|
249
220
|
|
|
250
|
-
**Before proceeding to step-06, run
|
|
251
|
-
|
|
252
|
-
### 1. CSS Variables Check (BLOCKING)
|
|
253
|
-
|
|
254
|
-
Scan all generated `.tsx` files for hardcoded Tailwind colors:
|
|
255
|
-
|
|
256
|
-
```
|
|
257
|
-
FORBIDDEN patterns: bg-blue-, bg-red-, bg-green-, bg-gray-, bg-amber-,
|
|
258
|
-
text-blue-, text-red-, text-green-, text-gray-, text-amber-,
|
|
259
|
-
border-blue-, border-red-, border-green-, border-gray-
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
If ANY hardcoded color is found → **FIX IT** using CSS variables from style-guide.md before continuing.
|
|
221
|
+
**Before proceeding to step-06, run all 7 checks on generated frontend files.**
|
|
263
222
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
If a grid/card view is generated, verify it uses `EntityCard` component (not custom divs).
|
|
273
|
-
|
|
274
|
-
### 4. i18n Check (BLOCKING)
|
|
275
|
-
|
|
276
|
-
Verify exactly **4 language files** exist with identical key structures:
|
|
277
|
-
- `fr/{entityCode}.json`
|
|
278
|
-
- `en/{entityCode}.json`
|
|
279
|
-
- `it/{entityCode}.json`
|
|
280
|
-
- `de/{entityCode}.json`
|
|
281
|
-
|
|
282
|
-
### 5. Route Check (BLOCKING)
|
|
283
|
-
|
|
284
|
-
Verify routes are:
|
|
285
|
-
- **INSIDE** the Layout wrapper (`BusinessLayout`, `AdminLayout`, or `UserLayout`)
|
|
286
|
-
- **NESTED** (not flat)
|
|
287
|
-
- Following path convention: `/{context}/{application}/{module}`
|
|
288
|
-
|
|
289
|
-
### 6. States Check
|
|
290
|
-
|
|
291
|
-
Verify the list page includes:
|
|
292
|
-
- Loading state (spinner)
|
|
293
|
-
- Error state (icon + message + retry button)
|
|
294
|
-
- Empty state (icon + message)
|
|
295
|
-
|
|
296
|
-
### 7. TypeScript Build Check (BLOCKING)
|
|
297
|
-
|
|
298
|
-
Run the frontend type check to verify all generated files compile:
|
|
299
|
-
|
|
300
|
-
```bash
|
|
301
|
-
cd web && npx tsc --noEmit 2>&1 | head -50
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
OR if the project uses a build script:
|
|
305
|
-
|
|
306
|
-
```bash
|
|
307
|
-
cd web && npm run build 2>&1 | head -80
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
IF type errors exist **in generated files**: Fix them before proceeding.
|
|
311
|
-
Common issues: missing imports, wrong interface names, incorrect prop types, missing hook return types.
|
|
312
|
-
|
|
313
|
-
IF type errors exist **in other pre-existing files**: NON-BLOCKING. Note them but proceed.
|
|
314
|
-
|
|
315
|
-
**Focus only on errors in files generated by this step:**
|
|
316
|
-
- `pages/{context}/{application}/{module}/*.tsx`
|
|
317
|
-
- `services/api/{entityCode}Api.ts`
|
|
318
|
-
- `types/{entityName}.types.ts`
|
|
319
|
-
- `hooks/use{EntityName}*.ts`
|
|
223
|
+
See [references/frontend-verification.md](../references/frontend-verification.md) for the complete checklist:
|
|
224
|
+
1. CSS Variables (BLOCKING) — no hardcoded Tailwind colors
|
|
225
|
+
2. API Client (BLOCKING) — use configured client, not raw axios
|
|
226
|
+
3. EntityCard — use EntityCard component for grid/card views
|
|
227
|
+
4. i18n (BLOCKING) — exactly 4 language files with identical keys
|
|
228
|
+
5. Route (BLOCKING) — inside Layout wrapper, nested, correct path convention
|
|
229
|
+
6. States — loading, error, empty states present
|
|
230
|
+
7. TypeScript Build (BLOCKING) — `npx tsc --noEmit` passes for generated files
|
|
320
231
|
|
|
321
232
|
---
|
|
322
233
|
|