@atlashub/smartstack-cli 4.51.0 → 4.53.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 +53 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/skills/apex/references/core-seed-data.md +15 -0
- package/templates/skills/apex/references/error-classification.md +27 -3
- package/templates/skills/apex/references/post-checks.md +3 -1
- package/templates/skills/apex/steps/step-00-init.md +57 -0
- package/templates/skills/apex/steps/step-03-execute.md +33 -5
- package/templates/skills/apex/steps/step-03b-layer1-seed.md +18 -0
- package/templates/skills/apex/steps/step-03d-layer3-frontend.md +3 -0
- package/templates/skills/apex/steps/step-04-examine.md +35 -0
- package/templates/skills/business-analyse/references/canonical-json-formats.md +200 -0
- package/templates/skills/business-analyse/steps/step-03-specify.md +94 -20
- package/templates/skills/business-analyse-design/steps/step-01-screens.md +41 -4
- package/templates/skills/business-analyse-develop/references/init-resume-recovery.md +54 -0
- package/templates/skills/business-analyse-develop/steps/step-00-init.md +10 -3
- package/templates/skills/business-analyse-develop/steps/step-01-task.md +14 -2
- package/templates/skills/business-analyse-develop/steps/step-04-check.md +12 -2
- package/templates/skills/business-analyse-handoff/references/entity-canonicalization.md +158 -0
- package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +26 -3
- package/templates/skills/business-analyse-handoff/steps/step-02-export.md +14 -0
- package/templates/skills/business-analyse-html/SKILL.md +4 -0
- package/templates/skills/business-analyse-html/references/data-build.md +24 -17
- package/templates/skills/business-analyse-html/references/data-mapping.md +79 -35
- package/templates/skills/business-analyse-html/references/output-modes.md +2 -1
- package/templates/skills/business-analyse-html/steps/step-01-collect.md +7 -2
- package/templates/skills/business-analyse-html/steps/step-02-build-data.md +155 -40
- package/templates/skills/business-analyse-html/steps/step-04-verify.md +22 -4
package/package.json
CHANGED
|
@@ -1003,6 +1003,21 @@ public class RolePermissionSeedEntry
|
|
|
1003
1003
|
|
|
1004
1004
|
## 6. IClientSeedDataProvider Implementation
|
|
1005
1005
|
|
|
1006
|
+
> **IMPORTANT — HasData vs Seed*Async: TWO DIFFERENT MECHANISMS**
|
|
1007
|
+
>
|
|
1008
|
+
> | Mechanism | Where | When | Purpose |
|
|
1009
|
+
> |-----------|-------|------|---------|
|
|
1010
|
+
> | **EF Core `HasData()`** | `*Configuration.cs` (Infrastructure) | At migration time | Seeds static reference data into tables via `INSERT` in migration SQL. Data is part of the migration — no runtime code needed. |
|
|
1011
|
+
> | **`IClientSeedDataProvider.Seed*Async()`** | `*SeedDataProvider.cs` (Infrastructure) | At runtime startup | Seeds navigation, roles, permissions, role-permissions into the **Core** schema. Runs AFTER `MigrateAsync()` in `Program.cs`. |
|
|
1012
|
+
>
|
|
1013
|
+
> **Common mistake:** Generating `HasData()` calls for navigation/permissions instead of `Seed*Async()` methods.
|
|
1014
|
+
> Navigation and permission data goes into the **Core** schema (`core.nav_*`, `core.auth_*`) which is managed
|
|
1015
|
+
> by SmartStack, not by the client's migration. Only `IClientSeedDataProvider` can write to Core tables at runtime.
|
|
1016
|
+
>
|
|
1017
|
+
> **ANTI-STUB WARNING:** Each of the 4 Seed methods MUST contain real `context.{DbSet}.Add()` calls.
|
|
1018
|
+
> If ANY method is just `return Task.CompletedTask;`, the module will be **invisible** in the UI (empty menu).
|
|
1019
|
+
> This happens when this reference file is evicted from context by compression — see step-03b safeguard.
|
|
1020
|
+
|
|
1006
1021
|
**File:** `Infrastructure/Persistence/Seeding/{AppPascalName}SeedDataProvider.cs`
|
|
1007
1022
|
|
|
1008
1023
|
### Critical Rules
|
|
@@ -100,6 +100,28 @@
|
|
|
100
100
|
|
|
101
101
|
---
|
|
102
102
|
|
|
103
|
+
### Category G: PRD Quality Error (FIX = fix PRD or re-run handoff)
|
|
104
|
+
|
|
105
|
+
> **These errors are NOT caused by code generation — they originate from invalid PRD data.**
|
|
106
|
+
> The handoff generated file paths with illegal characters (spaces, apostrophes, accents in entity names).
|
|
107
|
+
> Code generation faithfully reproduced the invalid paths → build failure.
|
|
108
|
+
|
|
109
|
+
| Error Pattern | Example | Fix |
|
|
110
|
+
|--------------|---------|-----|
|
|
111
|
+
| `error CS1001: Identifier expected` with file name containing spaces | `Type d'absence.cs` → CS1001 | Re-run `/business-analyse-handoff` with entity canonicalization |
|
|
112
|
+
| `error CS1513/CS1514` with file name containing apostrophes | `Congé.cs` → accent in identifier | Fix entity name in BA or re-run handoff |
|
|
113
|
+
| Path contains non-ASCII characters in `.cs` file names | `Département.cs` | Canonicalize: strip diacritics, PascalCase |
|
|
114
|
+
|
|
115
|
+
**Detection heuristic:** If the error file path contains spaces, apostrophes, or accented characters, it is a PRD quality error, not a code error. Do NOT attempt to fix the generated code — fix the PRD source.
|
|
116
|
+
|
|
117
|
+
**Fix procedure:**
|
|
118
|
+
1. Identify the invalid entity name from the error file path
|
|
119
|
+
2. Report to user: "PRD quality error — entity name '{name}' is not a valid C# identifier"
|
|
120
|
+
3. Either: manually canonicalize in the PRD file, or re-run `/business-analyse-handoff` (which now includes canonicalization)
|
|
121
|
+
4. Re-run `/apex -d` with the corrected PRD
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
103
125
|
## Decision Tree
|
|
104
126
|
|
|
105
127
|
When a build or runtime error occurs, follow this tree:
|
|
@@ -123,9 +145,11 @@ BUILD/RUNTIME ERROR
|
|
|
123
145
|
| YES -> Category E (edit config files)
|
|
124
146
|
|
|
|
125
147
|
+-- error CS#### (C# compiler error) ?
|
|
126
|
-
| YES ->
|
|
127
|
-
|
|
|
128
|
-
|
|
|
148
|
+
| YES -> Does the error file path contain spaces, apostrophes, or accents?
|
|
149
|
+
| YES -> Category G (PRD quality error — fix handoff, not code)
|
|
150
|
+
| NO -> Is the missing type in ANY project file?
|
|
151
|
+
| NO -> Category A (missing package)
|
|
152
|
+
| YES -> Category F (fix source code)
|
|
129
153
|
|
|
|
130
154
|
+-- Test failure (Assert/Expected) ?
|
|
131
155
|
YES -> Category F (fix source code, NOT tests)
|
|
@@ -90,7 +90,7 @@ bash references/checks/infrastructure-checks.sh
|
|
|
90
90
|
| C20 | WARNING | Section route completeness (NavigationSection → frontend route + permissions) | seed-checks.sh |
|
|
91
91
|
| C21 | WARNING | FORBIDDEN route patterns — /list and /detail/:id | seed-checks.sh |
|
|
92
92
|
| C22 | WARNING | Permission path segment count (2-4 dots expected) | seed-checks.sh |
|
|
93
|
-
| C23 | BLOCKING | IClientSeedDataProvider must have 4 methods + DI registration | seed-checks.sh |
|
|
93
|
+
| C23 | BLOCKING | IClientSeedDataProvider must have 4 methods with real implementation (not stubs) + DI registration | seed-checks.sh |
|
|
94
94
|
| C32 | CRITICAL | Translation seed data must have idempotency guard | seed-checks.sh |
|
|
95
95
|
| C33 | CRITICAL | Resource seed data must use actual section IDs from DB | seed-checks.sh |
|
|
96
96
|
| C34 | BLOCKING | NavRoute segments must use kebab-case for multi-word codes — MCP overlap | seed-checks.sh |
|
|
@@ -101,6 +101,8 @@ bash references/checks/infrastructure-checks.sh
|
|
|
101
101
|
| C47 | WARNING | Person Extension entities must not duplicate User fields | seed-checks.sh |
|
|
102
102
|
| C48 | CRITICAL | Person Extension service must Include(User) | seed-checks.sh |
|
|
103
103
|
| C53 | BLOCKING | Enum serialization — JsonStringEnumConverter required | seed-checks.sh |
|
|
104
|
+
| C57 | BLOCKING | SeedDataProvider Seed*Async methods must NOT be `return Task.CompletedTask` or empty body — stubs cause empty menu | seed-checks.sh |
|
|
105
|
+
| C58 | BLOCKING | File paths in filesToCreate must be valid C# identifiers — no spaces, apostrophes, or accents | seed-checks.sh |
|
|
104
106
|
|
|
105
107
|
### Architecture — Clean Architecture Layer Isolation (A1-A8)
|
|
106
108
|
|
|
@@ -94,6 +94,46 @@ if (prd.specificationFiles) {
|
|
|
94
94
|
|
|
95
95
|
Each layer step (step-03a through step-03d) will load its companion files at the start. This provides full BA specifications (entity attributes, BR formulas, UC steps, screen columns) without loading the entire spec corpus.
|
|
96
96
|
|
|
97
|
+
**PRD Quality Gate (delegate mode — BLOCKING):**
|
|
98
|
+
|
|
99
|
+
> Validate that PRD file paths are valid C# identifiers BEFORE starting execution.
|
|
100
|
+
> Invalid entity names (French with spaces/apostrophes/accents) cause CS1001 build errors
|
|
101
|
+
> that waste 3+ retry iterations before being correctly classified.
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
// Extract all file paths from PRD
|
|
105
|
+
const filesToCreate = prd.$version === '4.0.0' ? prd.expectedFiles : prd.implementation?.filesToCreate;
|
|
106
|
+
if (filesToCreate) {
|
|
107
|
+
const invalidPaths = [];
|
|
108
|
+
for (const [category, files] of Object.entries(filesToCreate)) {
|
|
109
|
+
for (const file of (files || [])) {
|
|
110
|
+
const filePath = file.path || file;
|
|
111
|
+
// Extract filename (without extension) from path
|
|
112
|
+
const fileName = filePath.split('/').pop().replace(/\.(cs|tsx|ts|json)$/, '');
|
|
113
|
+
// Check for illegal characters in C# identifiers
|
|
114
|
+
if (/[\s'àâäéèêëïîôùûüçÀÂÄÉÈÊËÏÎÔÙÛÜÇ]/.test(fileName)) {
|
|
115
|
+
invalidPaths.push({ category, path: filePath, fileName });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (invalidPaths.length > 0) {
|
|
121
|
+
console.error('BLOCKING — PRD QUALITY ERROR (not a code error):');
|
|
122
|
+
console.error('The following file paths contain illegal C# identifier characters:');
|
|
123
|
+
for (const p of invalidPaths) {
|
|
124
|
+
console.error(` ${p.category}: ${p.path} (invalid name: "${p.fileName}")`);
|
|
125
|
+
}
|
|
126
|
+
console.error('');
|
|
127
|
+
console.error('FIX: Re-run /business-analyse-handoff which now includes entity name canonicalization.');
|
|
128
|
+
console.error(' Or manually fix entity names in the PRD (strip accents, remove spaces/apostrophes, PascalCase).');
|
|
129
|
+
console.error('');
|
|
130
|
+
console.error('This is a PRD quality error (Category G), NOT a code generation error.');
|
|
131
|
+
console.error('Do NOT attempt to generate code from this PRD — it will fail with CS1001.');
|
|
132
|
+
STOP; // Do not proceed with invalid PRD
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
97
137
|
**Jump to:** section 3 (MCP verify) → section 6 (determine needs) → section 9 (summary)
|
|
98
138
|
|
|
99
139
|
---
|
|
@@ -248,6 +288,23 @@ needs_notification = {module_complexity} in ["crud-workflow","complex"] OR menti
|
|
|
248
288
|
|
|
249
289
|
Read latest task directory in `.claude/output/apex/`:
|
|
250
290
|
- **If state.json exists:** resume step-03 at next uncompleted layer (skip completed)
|
|
291
|
+
- **Delegate context recovery:** If `state.delegate_mode === true`:
|
|
292
|
+
1. Restore `{delegate_prd_path}` from `state.delegate_prd_path`
|
|
293
|
+
2. Restore `{app_name}`, `{module_code}`, `{sections}`, `{entities}` from state
|
|
294
|
+
3. Re-read PRD at `{delegate_prd_path}` to rebuild `{specification_loading_plan}`:
|
|
295
|
+
```javascript
|
|
296
|
+
const prd = readJSON(state.delegate_prd_path);
|
|
297
|
+
if (prd.specificationFiles) {
|
|
298
|
+
const sf = prd.specificationFiles;
|
|
299
|
+
specification_loading_plan = {
|
|
300
|
+
layer0_domain: [sf.entities],
|
|
301
|
+
layer1_seed: [sf.entities, sf.permissions],
|
|
302
|
+
layer2_backend: [sf.rules, sf.usecases],
|
|
303
|
+
layer3_frontend: [sf.screens, sf.usecases]
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
4. Set `{delegate_mode} = true` — companion spec loading will work in remaining layers
|
|
251
308
|
- **Else if 00-context.md exists:** restore step-00 state, re-derive post-step-00 from git + files
|
|
252
309
|
- **Else:** full re-derive from git history + files
|
|
253
310
|
|
|
@@ -46,19 +46,35 @@ Execute all layers (Layer 0 → Layer 1 → Layer 2 → Layer 3 → Layer 4).
|
|
|
46
46
|
BEFORE starting Layer N:
|
|
47
47
|
Verify these variables are still accessible:
|
|
48
48
|
{app_name}, {module_code}, {sections}, {entities}, {code_patterns}
|
|
49
|
+
IF delegate_mode: also verify {delegate_prd_path}, {specification_loading_plan}
|
|
49
50
|
|
|
50
51
|
IF any variable is missing or empty:
|
|
51
52
|
1. Read .claude/output/apex/{task_id}/state.json (if exists)
|
|
52
|
-
2. IF state.json
|
|
53
|
+
2. IF state.json has delegate context:
|
|
54
|
+
- {delegate_prd_path} = state.delegate_prd_path
|
|
55
|
+
- {delegate_mode} = state.delegate_mode
|
|
56
|
+
- Re-read PRD at {delegate_prd_path} to rebuild specification_loading_plan:
|
|
57
|
+
const prd = readJSON(delegate_prd_path);
|
|
58
|
+
if (prd.specificationFiles) {
|
|
59
|
+
specification_loading_plan = {
|
|
60
|
+
layer0_domain: [prd.specificationFiles.entities],
|
|
61
|
+
layer1_seed: [prd.specificationFiles.entities, prd.specificationFiles.permissions],
|
|
62
|
+
layer2_backend: [prd.specificationFiles.rules, prd.specificationFiles.usecases],
|
|
63
|
+
layer3_frontend: [prd.specificationFiles.screens, prd.specificationFiles.usecases]
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
- {app_name} = state.app_name || prd.project?.application || prd.metadata?.applicationCode
|
|
67
|
+
- {module_code} = state.module_code || prd.project?.module || prd.metadata?.moduleCode
|
|
68
|
+
3. IF state.json missing OR no delegate context → re-derive from filesystem:
|
|
53
69
|
- {app_name}: Glob("docs/business/*/") → first directory name
|
|
54
70
|
- {module_code}: Glob("src/**/Domain/Entities/*/") → target module directory
|
|
55
71
|
- {entities}: Glob("src/**/Domain/Entities/{module_code}/*.cs") → entity names
|
|
56
72
|
- {sections}: Glob("src/**/Seeding/Data/{module_code}/*NavigationSeedData.cs") → parse
|
|
57
73
|
- {code_patterns}: Read state.json or re-derive from DependencyInjection.cs
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
4. IF recovered: verify consistency with naming derivation rules (step-00 §4f)
|
|
75
|
+
5. IF Layer N-1 already completed: skip to Layer N directly
|
|
60
76
|
|
|
61
|
-
Cost: ~5 tool calls. Only triggered if context was compressed.
|
|
77
|
+
Cost: ~5-8 tool calls. Only triggered if context was compressed.
|
|
62
78
|
```
|
|
63
79
|
|
|
64
80
|
---
|
|
@@ -126,6 +142,7 @@ Layer 4: feat({module}): [devdata] test data for development # if applicable
|
|
|
126
142
|
## State Auto-Save (after each layer)
|
|
127
143
|
|
|
128
144
|
> **Automatic** — not dependent on `-s` flag. Enables reliable resume after context loss.
|
|
145
|
+
> **CRITICAL (audit ba-003):** Delegate context MUST be persisted for resume to work in delegate mode.
|
|
129
146
|
|
|
130
147
|
After each layer's build gate passes, write state to `.claude/output/apex/{task_id}/state.json`:
|
|
131
148
|
|
|
@@ -137,10 +154,21 @@ After each layer's build gate passes, write state to `.claude/output/apex/{task_
|
|
|
137
154
|
"files_created": ["Employee.cs", "EmployeeConfiguration.cs", "..."],
|
|
138
155
|
"build_gates": { "layer0": "pass", "layer1": "pass", "layer2": "pass" },
|
|
139
156
|
"commits": ["abc1234", "def5678", "ghi9012"],
|
|
140
|
-
"timestamp": "2026-03-06T14:30:00Z"
|
|
157
|
+
"timestamp": "2026-03-06T14:30:00Z",
|
|
158
|
+
"delegate_mode": true,
|
|
159
|
+
"delegate_prd_path": ".ralph/prd-employees.json",
|
|
160
|
+
"app_name": "HumanResources",
|
|
161
|
+
"module_code": "employee-management",
|
|
162
|
+
"sections": ["employees", "departments"],
|
|
163
|
+
"entities": ["Employee", "Department"]
|
|
141
164
|
}
|
|
142
165
|
```
|
|
143
166
|
|
|
167
|
+
> **Fields `delegate_mode`, `delegate_prd_path`, `app_name`, `module_code`, `sections`, `entities`**
|
|
168
|
+
> are persisted so that Context Recovery Protocol (above) can restore the full execution context
|
|
169
|
+
> after context compression or resume (`-r`). The `specification_loading_plan` is rebuilt from the
|
|
170
|
+
> PRD file at `delegate_prd_path` — no need to serialize it directly.
|
|
171
|
+
|
|
144
172
|
---
|
|
145
173
|
|
|
146
174
|
## Save Output (if save_mode)
|
|
@@ -42,6 +42,24 @@ TaskUpdate(taskId: progress_tracker_id,
|
|
|
42
42
|
|
|
43
43
|
> This layer is required. Seed data makes modules visible in the UI. Without it, the module exists in code but is invisible to users. Reference: `references/core-seed-data.md` (loaded above) for complete C# templates.
|
|
44
44
|
|
|
45
|
+
> **CONTEXT COMPRESSION SAFEGUARD (delegate mode):**
|
|
46
|
+
> In delegate mode (`-d`), `references/core-seed-data.md` may have been evicted from context by compression
|
|
47
|
+
> before Layer 1 begins (it was loaded at step-03 entry but is ~1464 lines).
|
|
48
|
+
>
|
|
49
|
+
> **CHECK:** Can you see Section 6 "IClientSeedDataProvider Implementation" from `core-seed-data.md` in your context?
|
|
50
|
+
> - **YES** → Proceed normally using the templates from that section.
|
|
51
|
+
> - **NO** → **Re-read** `references/core-seed-data.md` lines 1004-1296 NOW (the IClientSeedDataProvider template).
|
|
52
|
+
> This section contains the complete C# template for the provider class with all 4 Seed methods.
|
|
53
|
+
>
|
|
54
|
+
> **WARNING — ANTI-STUB RULE:**
|
|
55
|
+
> The SeedDataProvider MUST contain real implementation code. Each of the 4 methods
|
|
56
|
+
> (`SeedNavigationAsync`, `SeedRolesAsync`, `SeedPermissionsAsync`, `SeedRolePermissionsAsync`)
|
|
57
|
+
> MUST have actual entity creation logic with `context.{DbSet}.Add()` calls.
|
|
58
|
+
>
|
|
59
|
+
> **BLOCKING:** If ANY Seed method body is just `return Task.CompletedTask;` or `{ }` (empty),
|
|
60
|
+
> the seed data layer is INVALID. The module will be invisible in the UI (menu vide / empty menu).
|
|
61
|
+
> Re-read the template from `references/core-seed-data.md` Section 6 and generate proper implementation.
|
|
62
|
+
|
|
45
63
|
---
|
|
46
64
|
|
|
47
65
|
### Mode Detection: CREATE vs UPDATE
|
|
@@ -169,6 +169,9 @@ For each module:
|
|
|
169
169
|
3. Add the new namespace import + registration for all 4 languages
|
|
170
170
|
4. If config uses dynamic imports: add namespace to the `ns` array
|
|
171
171
|
5. Verify: `grep -q "{module_namespace}" src/**/i18n/config.ts` → must match
|
|
172
|
+
6. **I18n File/Import Alignment Check:** Verify that every locale JSON file on disk for this module
|
|
173
|
+
has a corresponding import in the i18n config index.ts. Glob `src/**/i18n/locales/*/` for module files,
|
|
174
|
+
then verify each is imported. Missing imports cause silent translation failures (keys show as raw strings).
|
|
172
175
|
- Permissions: Call MCP generate_permissions for the module permission root (2 segments: {app}.{module}),
|
|
173
176
|
then also call MCP generate_permissions for each section (3 segments: {app}.{module}.{section}).
|
|
174
177
|
- Section routes: Ensure navigation seed data has ComponentKey matching PageRegistry keys.
|
|
@@ -131,6 +131,41 @@ IF ANY cell = NO → BLOCKING — return to step-03b to fix
|
|
|
131
131
|
|
|
132
132
|
Execute all checks from `references/post-checks.md`. If any fails, fix in step-03 and re-validate.
|
|
133
133
|
|
|
134
|
+
### 6c. SeedDataProvider Content Verification (BLOCKING)
|
|
135
|
+
|
|
136
|
+
> **LESSON LEARNED (audit ba-003):** SeedDataProvider existed and had 4 methods (passed C23),
|
|
137
|
+
> but all methods were `return Task.CompletedTask` — stubs generated when `core-seed-data.md`
|
|
138
|
+
> was evicted from context by compression. Result: empty menu, 0 applications visible.
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
// Find the SeedDataProvider file
|
|
142
|
+
const providerFiles = Glob("**/Seeding/*SeedDataProvider.cs");
|
|
143
|
+
for (const providerFile of providerFiles) {
|
|
144
|
+
const content = readFile(providerFile);
|
|
145
|
+
|
|
146
|
+
// Check 1: No stub methods — each Seed*Async must have real implementation
|
|
147
|
+
const methods = ['SeedNavigationAsync', 'SeedRolesAsync', 'SeedPermissionsAsync', 'SeedRolePermissionsAsync'];
|
|
148
|
+
for (const method of methods) {
|
|
149
|
+
const methodRegex = new RegExp(`${method}[^{]*\\{([^}]*)\\}`, 's');
|
|
150
|
+
const match = content.match(methodRegex);
|
|
151
|
+
if (match) {
|
|
152
|
+
const body = match[1].trim();
|
|
153
|
+
if (body === 'return Task.CompletedTask;' || body === '' || body === 'return;') {
|
|
154
|
+
BLOCKING_ERROR(`${providerFile}: ${method} is a STUB (${body || 'empty body'}). ` +
|
|
155
|
+
`Re-read references/core-seed-data.md Section 6 and generate real implementation. ` +
|
|
156
|
+
`Stub seed methods cause EMPTY MENU — 0 applications visible in UI.`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Check 2: Must contain actual entity creation calls
|
|
162
|
+
if (!content.includes('.Add(') && !content.includes('.AddRange(')) {
|
|
163
|
+
BLOCKING_ERROR(`${providerFile}: No .Add() or .AddRange() calls found. ` +
|
|
164
|
+
`SeedDataProvider must actually insert seed data, not just return.`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
134
169
|
---
|
|
135
170
|
|
|
136
171
|
## 7. Acceptance Criteria POST-CHECK
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Canonical JSON Formats Reference
|
|
2
|
+
|
|
3
|
+
> **Purpose:** Single source of truth for all JSON file formats produced by the BA pipeline.
|
|
4
|
+
> **Used by:** `/business-analyse` (step-03), `/business-analyse-design` (step-01), `/business-analyse-html`, `/business-analyse-handoff`, `/business-analyse-develop`
|
|
5
|
+
> **Rule:** All producers MUST write canonical format. All consumers MUST accept canonical + deprecated fallbacks.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## entities.json
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"entities": [
|
|
14
|
+
{
|
|
15
|
+
"name": "Employee",
|
|
16
|
+
"description": "...",
|
|
17
|
+
"personRoleConfig": { "variant": "mandatory", "userFields": ["firstName", "lastName", "email"] },
|
|
18
|
+
"attributes": [
|
|
19
|
+
{ "name": "code", "type": "string", "required": true, "description": "..." },
|
|
20
|
+
{ "name": "userId", "type": "string", "required": true, "description": "FK auth_Users (ASP.NET Identity)" }
|
|
21
|
+
],
|
|
22
|
+
"versionedAttributes": [
|
|
23
|
+
{ "entity": "Salary", "attributes": ["grossAmount", "effectiveDate"], "reason": "..." }
|
|
24
|
+
],
|
|
25
|
+
"relationships": [
|
|
26
|
+
{ "target": "Department", "type": "ManyToOne", "description": "..." }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Convention guards:**
|
|
34
|
+
- Person entities → `personRoleConfig` + `userId` (string), NO firstName/lastName/email
|
|
35
|
+
- Versioned data → `versionedAttributes[]`, NOT inline fields
|
|
36
|
+
- FK naming → always `{entity}Id` suffix
|
|
37
|
+
- FK to auth_Users → type `string` (ASP.NET Identity), NOT `guid`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## usecases.json
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"useCases": [
|
|
46
|
+
{
|
|
47
|
+
"id": "UC-MODULE-001",
|
|
48
|
+
"name": "Créer un employé",
|
|
49
|
+
"sectionCode": "list",
|
|
50
|
+
"primaryActor": "Responsable RH",
|
|
51
|
+
"preconditions": ["..."],
|
|
52
|
+
"mainScenario": [
|
|
53
|
+
"L'utilisateur ouvre la page de création",
|
|
54
|
+
"Il remplit les champs obligatoires"
|
|
55
|
+
],
|
|
56
|
+
"alternativeScenarios": [
|
|
57
|
+
{ "name": "Données invalides", "steps": ["Le système affiche les erreurs"] }
|
|
58
|
+
],
|
|
59
|
+
"businessRules": ["BR-VAL-MODULE-001"],
|
|
60
|
+
"result": "L'entité est créée"
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
| Canonical key | Deprecated alternatives | Notes |
|
|
67
|
+
|---------------|------------------------|-------|
|
|
68
|
+
| `useCases` (root) | `usecases` | camelCase is canonical |
|
|
69
|
+
| `primaryActor` | `actor` | |
|
|
70
|
+
| `mainScenario` (string[]) | `steps` (object[] or string[]) | MUST be strings, never `{step, action}` objects |
|
|
71
|
+
| `alternativeScenarios` (object[]) | `alternativeFlows`, `alternative` (string) | Must be `[{name, steps}]` |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## rules.json
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"rules": [
|
|
80
|
+
{
|
|
81
|
+
"id": "BR-VAL-MODULE-001",
|
|
82
|
+
"name": "Validation date",
|
|
83
|
+
"category": "validation",
|
|
84
|
+
"sectionCode": "list",
|
|
85
|
+
"statement": "La date ne peut pas être dans le futur",
|
|
86
|
+
"example": "Date = 2027-01-01 → erreur",
|
|
87
|
+
"entities": ["Employee"],
|
|
88
|
+
"severity": "blocking"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
| Canonical key | Deprecated alternatives |
|
|
95
|
+
|---------------|------------------------|
|
|
96
|
+
| `rules` (root) | `businessRules` |
|
|
97
|
+
| `statement` | `description` |
|
|
98
|
+
| `id` | `name` (as identifier) |
|
|
99
|
+
|
|
100
|
+
Categories: `validation`, `calculation`, `workflow`, `security`, `data`, `notification`
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## permissions.json
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"roles": [
|
|
109
|
+
{ "role": "RH Admin", "description": "..." }
|
|
110
|
+
],
|
|
111
|
+
"permissionPaths": [
|
|
112
|
+
"HumanResources.Employees.Read",
|
|
113
|
+
"HumanResources.Employees.Create"
|
|
114
|
+
],
|
|
115
|
+
"matrix": {
|
|
116
|
+
"roleAssignments": [
|
|
117
|
+
{ "role": "RH Admin", "permissions": ["HumanResources.Employees.*"] }
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## screens.json
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"sections": [
|
|
130
|
+
{
|
|
131
|
+
"sectionCode": "list",
|
|
132
|
+
"sectionLabel": "Liste des employés",
|
|
133
|
+
"resources": [
|
|
134
|
+
{
|
|
135
|
+
"code": "employees-grid",
|
|
136
|
+
"type": "SmartTable",
|
|
137
|
+
"label": "Grille des employés",
|
|
138
|
+
"columns": [
|
|
139
|
+
{ "field": "code", "label": "Code", "type": "text", "sortable": true }
|
|
140
|
+
],
|
|
141
|
+
"filters": [
|
|
142
|
+
{ "field": "status", "type": "select", "label": "Statut" }
|
|
143
|
+
],
|
|
144
|
+
"actions": ["create", "export"],
|
|
145
|
+
"permission": "HumanResources.Employees.Read"
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
| Canonical key | Deprecated alternatives | Notes |
|
|
154
|
+
|---------------|------------------------|-------|
|
|
155
|
+
| `sections` (root) | `screens` (flat array) | `sections[]` with `resources[]` is canonical |
|
|
156
|
+
| `sectionCode` | `id`, `code` | |
|
|
157
|
+
| `sectionLabel` | `displayName`, `label` | |
|
|
158
|
+
| resource `type` | `layout`, `componentType` | Must be: SmartTable, SmartForm, SmartDashboard, SmartKanban, SmartCard, SmartFilter |
|
|
159
|
+
| column `field` | `code`, `name`, `id`, `fieldCode` | |
|
|
160
|
+
| column `label` | `displayName` | |
|
|
161
|
+
|
|
162
|
+
**DEPRECATED format (do NOT produce):**
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"screens": [
|
|
166
|
+
{ "screen": "employees-list", "section": "list", "componentType": "SmartTable", "columns": [...] }
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Consumer normalization pattern
|
|
174
|
+
|
|
175
|
+
All downstream consumers should normalize input using this priority chain:
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
// usecases
|
|
179
|
+
const rawUCs = data.useCases || data.usecases || [];
|
|
180
|
+
const uc = {
|
|
181
|
+
name: raw.name || raw.title || raw.id,
|
|
182
|
+
actor: raw.primaryActor || raw.actor,
|
|
183
|
+
steps: (raw.mainScenario || raw.steps || []).map(s =>
|
|
184
|
+
typeof s === 'string' ? s : (s.action || s.description || "")
|
|
185
|
+
),
|
|
186
|
+
alternatives: raw.alternativeScenarios || raw.alternativeFlows || []
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// screens
|
|
190
|
+
const sections = data.sections || [];
|
|
191
|
+
const flatScreens = data.screens || [];
|
|
192
|
+
// If flat format: wrap each screen as a section with 1 resource
|
|
193
|
+
|
|
194
|
+
// columns
|
|
195
|
+
const col = {
|
|
196
|
+
field: raw.field || raw.code || raw.name || raw.id,
|
|
197
|
+
label: raw.label || raw.displayName || raw.code,
|
|
198
|
+
type: raw.renderAs === "badge" ? "badge" : (raw.type || raw.dataType || "text")
|
|
199
|
+
};
|
|
200
|
+
```
|