@atlashub/smartstack-cli 4.43.0 → 4.45.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 +18 -14
- package/templates/skills/business-analyse/steps/step-00-init.md +0 -1
- package/templates/skills/business-analyse-handoff/SKILL.md +0 -1
- package/templates/skills/business-analyse-handoff/references/acceptance-criteria.md +33 -20
- package/templates/skills/business-analyse-handoff/steps/step-00-validate.md +18 -6
- package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +116 -221
- package/templates/skills/business-analyse-handoff/steps/step-02-export.md +0 -1
- package/templates/skills/business-analyse-review/steps/step-00-init.md +0 -1
- package/templates/skills/business-analyse-status/SKILL.md +0 -1
package/package.json
CHANGED
|
@@ -471,11 +471,11 @@ Perform these structural checks before every write:
|
|
|
471
471
|
- relationships[]: REQUIRED `target`, `type`, `description`
|
|
472
472
|
- FORBIDDEN: `values` (use `validation`), `rules` (use `validation`)
|
|
473
473
|
|
|
474
|
-
**analysis.
|
|
474
|
+
**analysis.rules** in rules.json — Root key: `rules[]` — REQUIRED: `id`, `name`, `category`, `statement`, `priority`
|
|
475
475
|
- OPTIONAL: `conditions[]`, `examples[]`, `testability`
|
|
476
476
|
- category values: `validation`, `calculation`, `workflow`, `security`, `data` (lowercase only)
|
|
477
|
-
- FORBIDDEN: `rule` (use `name`+`statement`), `condition` singular (use `conditions[]`)
|
|
478
|
-
- AUTO-MAP: `rule` → split into `name` (short) + `statement` (IF/THEN)
|
|
477
|
+
- FORBIDDEN: `rule` (use `name`+`statement`), `condition` singular (use `conditions[]`), `businessRules` as root key (use `rules`)
|
|
478
|
+
- AUTO-MAP: `rule` → split into `name` (short) + `statement` (IF/THEN), `businessRules` → rename to `rules`
|
|
479
479
|
|
|
480
480
|
**specification.useCases** in usecases.json — REQUIRED: `id`, `name`, `primaryActor`, `permission`, `preconditions[]`, `postconditions[]`, `mainScenario[]`
|
|
481
481
|
- OPTIONAL: `alternativeScenarios[]`, `errorScenarios[]`, `linkedRules[]`
|
|
@@ -489,14 +489,18 @@ Perform these structural checks before every write:
|
|
|
489
489
|
- FORBIDDEN: `name` (use `statement`), `linkedUCs` (use `linkedUseCases`), `linkedBRs` (use `linkedRules`)
|
|
490
490
|
- AUTO-MAP: `name` → `statement`, `linkedUCs` → `linkedUseCases`, `linkedBRs` → `linkedRules`
|
|
491
491
|
|
|
492
|
-
**specification.permissionMatrix** in permissions.json —
|
|
493
|
-
-
|
|
494
|
-
-
|
|
495
|
-
-
|
|
492
|
+
**specification.permissionMatrix** in permissions.json — Root keys: `permissionPaths[]`, `roles[]`, `matrix[]`
|
|
493
|
+
- permissionPaths[]: array of permission path strings (e.g., `"crm.contacts.read"`)
|
|
494
|
+
- roles[]: array of role definitions `{role, level}`
|
|
495
|
+
- matrix[]: array of `{role, permissions[]}` assignments
|
|
496
|
+
- FORBIDDEN: flat array format, `permissionSet` as wrapper, `actions` as root key
|
|
497
|
+
- AUTO-MAP: `permissionSet.permissions[]` → extract `.code`/`.path` into `permissionPaths[]`, `permissions[{code}]` → extract into `permissionPaths[]`
|
|
496
498
|
|
|
497
|
-
**specification.uiWireframes** in screens.json — REQUIRED: `screen`, `section`, `mockup`, `componentMapping[]`, `layout`
|
|
499
|
+
**specification.uiWireframes** in screens.json — Root key: `screens[]` — each screen REQUIRED: `screen`, `section`, `mockup`, `componentMapping[]`, `layout`
|
|
498
500
|
- componentMapping[]: `{wireframeElement, reactComponent}`
|
|
499
501
|
- layout: `{type, regions[]}` where regions[]: `{id, position, span?, components[]}`
|
|
502
|
+
- FORBIDDEN: `sections[].resources[]` as root structure (use `screens[]`)
|
|
503
|
+
- AUTO-MAP: `sections[].resources[]` → flatten into `screens[]`
|
|
500
504
|
|
|
501
505
|
**handoff** in handoff.json — REQUIRED: `complexity`, `filesToCreate`, `brToCodeMapping[]`, `apiEndpointSummary[]`, `prdFile`, `totalFiles`, `totalTasks`, `handedOffAt`
|
|
502
506
|
- filesToCreate: REQUIRED 8 categories: `domain[]`, `application[]`, `infrastructure[]`, `api[]`, `frontend[]`, `seedData[]`, `tests[]`, `documentation[]`
|
|
@@ -598,21 +602,21 @@ Versions are stored as separate directories. Each directory contains index.json
|
|
|
598
602
|
Before EVERY enrichSection() call for specification or handoff sections, validate referential integrity.
|
|
599
603
|
|
|
600
604
|
### After enrichSection("specification" or "usecases")
|
|
601
|
-
1. Build SET_BR from rules.json
|
|
605
|
+
1. Build SET_BR from rules.json rules[].id
|
|
602
606
|
2. For each useCases[].linkedRules[] → verify ∈ SET_BR
|
|
603
607
|
3. For each functionalRequirements[].linkedRules[] → verify ∈ SET_BR
|
|
604
608
|
4. Build SET_UC from usecases[].useCases[].id
|
|
605
609
|
5. For each functionalRequirements[].linkedUseCases[] → verify ∈ SET_UC
|
|
606
|
-
6. Build SET_PERM from permissions.json
|
|
607
|
-
7. For each
|
|
608
|
-
8. Build SET_SCREEN from screens.json
|
|
610
|
+
6. Build SET_PERM from permissions.json permissionPaths[]
|
|
611
|
+
7. For each matrix[].permissions[] → verify ∈ SET_PERM
|
|
612
|
+
8. Build SET_SCREEN from screens.json screens[].screen
|
|
609
613
|
9. For each sections[].wireframe → verify ∈ SET_SCREEN
|
|
610
614
|
|
|
611
615
|
### After enrichSection("handoff")
|
|
612
616
|
1. Build SET_FR from specification functionalRequirements[].id
|
|
613
617
|
2. Build SET_UC from specification useCases[].id
|
|
614
|
-
3. Build SET_SCREEN from specification
|
|
615
|
-
4. Build SET_BR from analysis
|
|
618
|
+
3. Build SET_SCREEN from specification screens[].screen
|
|
619
|
+
4. Build SET_BR from analysis rules[].id
|
|
616
620
|
5. For each filesToCreate.*[].linkedFRs[] → verify ∈ SET_FR
|
|
617
621
|
6. For each filesToCreate.*[].linkedUCs[] → verify ∈ SET_UC
|
|
618
622
|
7. For each filesToCreate.*[].linkedWireframes[] → verify ∈ SET_SCREEN
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
|
|
11
11
|
`/business-analyse` generates **separate JSON files** per module:
|
|
12
12
|
|
|
13
|
-
| File | Content | Root key |
|
|
14
|
-
|
|
15
|
-
| `index.json` | Metadata, file references, summary | `metadata`, `files`, `summary` |
|
|
16
|
-
| `entities.json` | Entity definitions | `entities[]` |
|
|
17
|
-
| `rules.json` | Business rules | `rules[]` |
|
|
18
|
-
| `usecases.json` | Use cases | `useCases[]` |
|
|
19
|
-
| `permissions.json` | Roles and permission matrix | `
|
|
20
|
-
| `screens.json` | UI screen specifications | `screens[]` |
|
|
13
|
+
| File | Content | Root key (canonical) | Accepted variants |
|
|
14
|
+
|------|---------|----------------------|-------------------|
|
|
15
|
+
| `index.json` | Metadata, file references, summary | `metadata`, `files`, `summary` | — |
|
|
16
|
+
| `entities.json` | Entity definitions | `entities[]` | — |
|
|
17
|
+
| `rules.json` | Business rules | `rules[]` | `businessRules[]` |
|
|
18
|
+
| `usecases.json` | Use cases | `useCases[]` | `usecases[]` (lowercase) |
|
|
19
|
+
| `permissions.json` | Roles and permission matrix | `permissionPaths[]` | `permissionSet.permissions[]`, `permissions[]`, `actions[]` |
|
|
20
|
+
| `screens.json` | UI screen specifications | `screens[]` | `sections[].resources[]` |
|
|
21
21
|
|
|
22
22
|
The validation script **assembles** these files before checking.
|
|
23
23
|
|
|
@@ -33,7 +33,7 @@ These verify data that `/business-analyse` produces:
|
|
|
33
33
|
|
|
34
34
|
| # | Criterion | Minimum | Source File | Blocking |
|
|
35
35
|
|---|-----------|---------|-------------|----------|
|
|
36
|
-
| AC-01 | Entities present |
|
|
36
|
+
| AC-01 | Entities present | 1 (or referencedEntities) | `entities.json > entities[]` | YES |
|
|
37
37
|
| AC-02 | Entity attributes have `type` field | ALL | `entities.json > entities[].attributes[].type` | YES |
|
|
38
38
|
| AC-03 | Use cases present | 2 | `usecases.json > useCases[]` | YES |
|
|
39
39
|
| AC-04 | Business rules present | 2 | `rules.json > rules[]` | YES |
|
|
@@ -85,19 +85,32 @@ const rulesData = loadFile('rules') || {};
|
|
|
85
85
|
const permissionsData = loadFile('permissions') || {};
|
|
86
86
|
const screensData = loadFile('screens') || {};
|
|
87
87
|
|
|
88
|
+
// NORMALISATION: tolerate ba-writer + LLM field name variants
|
|
88
89
|
const entities = entitiesData.entities || [];
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
const
|
|
90
|
+
const hasReferencedEntities = (entitiesData.referencedEntities || []).length > 0;
|
|
91
|
+
const useCases = usecasesData.useCases || usecasesData.usecases || [];
|
|
92
|
+
const rules = rulesData.rules || rulesData.businessRules || [];
|
|
93
|
+
|
|
94
|
+
// Permissions: canonical permissionPaths[] OR extract from nested structures
|
|
95
|
+
const permissions = permissionsData.permissionPaths
|
|
96
|
+
|| (permissionsData.permissionSet && permissionsData.permissionSet.permissions || []).map(function(p) { return p.code || p.path || ''; })
|
|
97
|
+
|| (permissionsData.permissions || []).map(function(p) { return typeof p === 'string' ? p : (p.code || p.path || ''); })
|
|
98
|
+
|| (permissionsData.actions || []).map(function(a) { return a.code || ''; })
|
|
99
|
+
|| [];
|
|
100
|
+
|
|
101
|
+
// Screens: canonical screens[] OR flatten sections[].resources[]
|
|
92
102
|
const screens = screensData.screens || [];
|
|
103
|
+
const sectionsAsScreens = (screensData.sections || []).reduce(function(acc, s) { return acc.concat(s.resources || []); }, []);
|
|
104
|
+
const allScreens = screens.length > 0 ? screens : sectionsAsScreens;
|
|
105
|
+
|
|
93
106
|
const status = index.metadata?.status || 'unknown';
|
|
94
107
|
|
|
95
108
|
const fails = [];
|
|
96
109
|
|
|
97
|
-
// AC-01: Entities >=
|
|
98
|
-
if (entities.length <
|
|
99
|
-
fails.push('AC-01: entities = ' + entities.length + ' (min:
|
|
100
|
-
console.error('FAIL: AC-01: entities >=
|
|
110
|
+
// AC-01: Entities >= 1 (exempt modules with referencedEntities - vue perso pattern)
|
|
111
|
+
if (entities.length < 1 && !hasReferencedEntities) {
|
|
112
|
+
fails.push('AC-01: entities = ' + entities.length + ' (min: 1)');
|
|
113
|
+
console.error('FAIL: AC-01: entities >= 1 = ' + entities.length + ' (min: 1, no referencedEntities)');
|
|
101
114
|
}
|
|
102
115
|
|
|
103
116
|
// AC-02: Entity attributes have type
|
|
@@ -122,9 +135,9 @@ if (rules.length < 2) {
|
|
|
122
135
|
}
|
|
123
136
|
|
|
124
137
|
// AC-05: Screens >= 1
|
|
125
|
-
if (
|
|
126
|
-
fails.push('AC-05: screens = ' +
|
|
127
|
-
console.error('FAIL: AC-05: screens >= 1 = ' +
|
|
138
|
+
if (allScreens.length < 1) {
|
|
139
|
+
fails.push('AC-05: screens = ' + allScreens.length + ' (min: 1)');
|
|
140
|
+
console.error('FAIL: AC-05: screens >= 1 = ' + allScreens.length + ' (min: 1)');
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
// AC-06: Permissions >= 1
|
|
@@ -145,7 +158,7 @@ if (fails.length > 0) {
|
|
|
145
158
|
process.exit(1);
|
|
146
159
|
}
|
|
147
160
|
console.log('PASS: All input acceptance criteria met (AC-01 to AC-07)');
|
|
148
|
-
console.log(' entities: ' + entities.length + ', useCases: ' + useCases.length + ', rules: ' + rules.length + ', screens: ' +
|
|
161
|
+
console.log(' entities: ' + entities.length + (hasReferencedEntities ? ' (+ referencedEntities)' : '') + ', useCases: ' + useCases.length + ', rules: ' + rules.length + ', screens: ' + allScreens.length + ', permissions: ' + permissions.length);
|
|
149
162
|
" "$MODULE_DIR"
|
|
150
163
|
```
|
|
151
164
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: step-00-validate
|
|
3
3
|
description: Detect input, validate BA readiness with flat-file support, AC gate
|
|
4
|
-
model: sonnet
|
|
5
4
|
next_step: steps/step-01-transform.md
|
|
6
5
|
---
|
|
7
6
|
|
|
@@ -78,13 +77,26 @@ For each module, load the separate JSON files referenced in `index.json > files`
|
|
|
78
77
|
// Module index.json contains file references:
|
|
79
78
|
// { "files": { "entities": { "path": "entities.json" }, "usecases": { "path": "usecases.json" }, ... } }
|
|
80
79
|
|
|
80
|
+
const entitiesData = READ(moduleDir + '/entities.json');
|
|
81
|
+
const usecasesData = READ(moduleDir + '/usecases.json');
|
|
82
|
+
const rulesData = READ(moduleDir + '/rules.json');
|
|
83
|
+
const permissionsData = READ(moduleDir + '/permissions.json');
|
|
84
|
+
const screensData = READ(moduleDir + '/screens.json');
|
|
85
|
+
|
|
86
|
+
// NORMALISATION: tolerate ba-writer + LLM field name variants
|
|
81
87
|
const moduleData = {
|
|
82
88
|
index: READ(moduleDir + '/index.json'),
|
|
83
|
-
entities:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
entities: entitiesData.entities || [],
|
|
90
|
+
hasReferencedEntities: (entitiesData.referencedEntities || []).length > 0,
|
|
91
|
+
useCases: usecasesData.useCases || usecasesData.usecases || [],
|
|
92
|
+
rules: rulesData.rules || rulesData.businessRules || [],
|
|
93
|
+
permissions: permissionsData.permissionPaths
|
|
94
|
+
|| (permissionsData.permissionSet?.permissions || []).map(p => p.code || p.path)
|
|
95
|
+
|| (permissionsData.permissions || []).map(p => typeof p === 'string' ? p : (p.code || p.path))
|
|
96
|
+
|| [],
|
|
97
|
+
screens: (screensData.screens || []).length > 0
|
|
98
|
+
? screensData.screens
|
|
99
|
+
: (screensData.sections || []).flatMap(s => s.resources || [])
|
|
88
100
|
};
|
|
89
101
|
```
|
|
90
102
|
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: step-01-transform
|
|
3
3
|
description: Build handoff data per module - 8 categories from flat BA files
|
|
4
|
-
model: sonnet
|
|
5
4
|
next_step: steps/step-02-export.md
|
|
6
5
|
---
|
|
7
6
|
|
|
8
|
-
> **Context files:** `references/handoff-file-templates.md` | `references/handoff-mappings.md` | `references/handoff-seeddata-generation.md` | `references/entity-domain-mapping.md`
|
|
9
|
-
|
|
10
7
|
# Step 01: Transform (Handoff Data Generation)
|
|
11
8
|
|
|
12
9
|
## MANDATORY EXECUTION RULES
|
|
13
10
|
|
|
14
11
|
- **ALWAYS** process modules in topological order (dependencies first)
|
|
12
|
+
- **ALWAYS** delegate each module to an **isolated Agent** (context isolation — CRITICAL for large projects)
|
|
15
13
|
- **ALWAYS** load data from **flat files** (entities.json, usecases.json, rules.json, screens.json, permissions.json)
|
|
16
14
|
- **ALWAYS** map to 8 categories (including "documentation")
|
|
17
15
|
- **ALWAYS** propagate personRoleConfig verbatim from entities
|
|
@@ -19,270 +17,167 @@ next_step: steps/step-02-export.md
|
|
|
19
17
|
- **ALWAYS** map entity to domain file path (1:1)
|
|
20
18
|
- **ALWAYS** include dependencies[] per file entry
|
|
21
19
|
- **NEVER** invent entities/BRs not in module JSON files
|
|
20
|
+
- **NEVER** load all module data in the main conversation (causes context overflow on 5+ modules)
|
|
22
21
|
- **ALWAYS** generate API endpoints from use cases + entities (BA does not produce apiEndpoints)
|
|
23
22
|
|
|
24
23
|
## YOUR TASK
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
Orchestrate the transform: determine module order, then delegate each module's transform to an Agent with isolated context. This prevents context accumulation across modules.
|
|
27
26
|
|
|
28
27
|
---
|
|
29
28
|
|
|
30
|
-
##
|
|
31
|
-
|
|
32
|
-
For each module, load data from separate files:
|
|
33
|
-
|
|
34
|
-
```javascript
|
|
35
|
-
// Module BA directory: docs/{AppCode}/{ModuleCode}/business-analyse/v{X.Y}/
|
|
36
|
-
const moduleDir = module.baDir; // resolved in step-00
|
|
29
|
+
## CONTEXT ISOLATION ARCHITECTURE
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Log missing files explicitly before falling back
|
|
46
|
-
if (!entitiesFile) console.warn("⚠ " + moduleDir + "/entities.json not found — using empty");
|
|
47
|
-
if (!usecasesFile) console.warn("⚠ " + moduleDir + "/usecases.json not found — using empty");
|
|
48
|
-
if (!rulesFile) console.warn("⚠ " + moduleDir + "/rules.json not found — using empty");
|
|
49
|
-
|
|
50
|
-
const entities = (entitiesFile?.entities) || [];
|
|
51
|
-
const useCases = (usecasesFile?.useCases) || [];
|
|
52
|
-
const rules = (rulesFile?.rules) || [];
|
|
53
|
-
const screens = (screensFile?.screens) || [];
|
|
31
|
+
```
|
|
32
|
+
Main conversation (orchestrator):
|
|
33
|
+
├─ Determine topological order
|
|
34
|
+
├─ FOR each module:
|
|
35
|
+
│ └─ Agent(ba-writer) ──► reads 5 files, builds handoff, writes result
|
|
36
|
+
│ (isolated context: ~500-1000 lines per module)
|
|
37
|
+
└─ Collect results, display summary
|
|
54
38
|
```
|
|
55
39
|
|
|
56
|
-
**
|
|
57
|
-
|
|
58
|
-
| Handoff needs | Source file | Root key |
|
|
59
|
-
|---------------|------------|----------|
|
|
60
|
-
| Entities, ValueObjects, Enums | `entities.json` | `entities[]` |
|
|
61
|
-
| Use cases | `usecases.json` | `useCases[]` |
|
|
62
|
-
| Business rules | `rules.json` | `rules[]` |
|
|
63
|
-
| Roles, permissions | `permissions.json` | `roles[]`, `matrix[]`, `permissionPaths[]` |
|
|
64
|
-
| Screens, sections, wireframes | `screens.json` | `screens[]` |
|
|
40
|
+
**WHY:** A 10-module project has ~10K lines of JSON data. Loading all at once exceeds Sonnet's effective context. Processing one module per Agent keeps each invocation under ~2K lines.
|
|
65
41
|
|
|
66
42
|
---
|
|
67
43
|
|
|
68
44
|
## EXECUTION SEQUENCE
|
|
69
45
|
|
|
70
|
-
|
|
46
|
+
### 1. Determine Module Processing Order
|
|
71
47
|
|
|
72
|
-
|
|
48
|
+
From step-00 data, extract the topological order of modules. Display:
|
|
73
49
|
|
|
74
|
-
```json
|
|
75
|
-
{
|
|
76
|
-
"complexity": "simple|medium|complex",
|
|
77
|
-
"complexityDetails": {
|
|
78
|
-
"entities": {count},
|
|
79
|
-
"useCases": {count},
|
|
80
|
-
"businessRules": {count},
|
|
81
|
-
"calculated": "{level} (entities<=X, UCs<=Y, BRs<=Z)"
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
50
|
```
|
|
51
|
+
Module processing order:
|
|
52
|
+
1. {module1} (0 dependencies)
|
|
53
|
+
2. {module2} (depends on: module1)
|
|
54
|
+
...
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 2. Process Each Module via Agent
|
|
85
58
|
|
|
59
|
+
For **EACH module** in topological order, use the **Agent tool** (subagent_type: `ba-writer`) with the following prompt structure:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
Transform module "{moduleCode}" for handoff.
|
|
63
|
+
|
|
64
|
+
## Input
|
|
65
|
+
- Module BA directory: {moduleDir}
|
|
66
|
+
- Application code: {appCode}
|
|
67
|
+
- Application name: {appName}
|
|
68
|
+
- Feature description: {featureDescription}
|
|
69
|
+
- Module index: {moduleDir}/index.json
|
|
70
|
+
|
|
71
|
+
## Instructions
|
|
72
|
+
Read the following 5 files from {moduleDir}:
|
|
73
|
+
1. entities.json → entities[]
|
|
74
|
+
2. usecases.json → useCases[]
|
|
75
|
+
3. rules.json → rules[]
|
|
76
|
+
4. permissions.json → roles[], matrix[], permissionPaths[]
|
|
77
|
+
5. screens.json → screens[]
|
|
78
|
+
|
|
79
|
+
Then build the handoff data following these rules:
|
|
80
|
+
|
|
81
|
+
### Complexity
|
|
86
82
|
| Criteria | Simple | Medium | Complex |
|
|
87
83
|
|----------|--------|--------|---------|
|
|
88
84
|
| Entities | <=3 | <=6 | >6 |
|
|
89
85
|
| Use Cases | <=5 | <=12 | >12 |
|
|
90
86
|
| Business Rules | <=10 | <=20 | >20 |
|
|
91
87
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// For each use case, derive the API endpoint:
|
|
100
|
-
// UC "Create Employee" -> POST /api/{app}/{module}
|
|
101
|
-
// UC "List Employees" -> GET /api/{app}/{module}
|
|
102
|
-
// UC "Update Employee" -> PUT /api/{app}/{module}/{id}
|
|
103
|
-
// UC "Delete Employee" -> DELETE /api/{app}/{module}/{id}
|
|
104
|
-
// UC "Get Employee" -> GET /api/{app}/{module}/{id}
|
|
105
|
-
|
|
106
|
-
// Use permission paths from permissions.json to determine operations
|
|
107
|
-
// Map CRUD operations to HTTP methods
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### 2b. Enrich Sections with UC/BR Links
|
|
111
|
-
|
|
112
|
-
Using `sectionCode` from usecases.json and rules.json, link each UC and BR to its section:
|
|
113
|
-
|
|
114
|
-
```javascript
|
|
115
|
-
// Build section-level UC/BR mapping
|
|
116
|
-
const sectionMap = {};
|
|
117
|
-
for (const section of screens) {
|
|
118
|
-
sectionMap[section.sectionCode || section.code] = {
|
|
119
|
-
useCases: useCases.filter(uc => uc.sectionCode === (section.sectionCode || section.code)).map(uc => uc.id),
|
|
120
|
-
businessRules: rules.filter(br => br.sectionCode === (section.sectionCode || section.code)).map(br => br.id)
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
// Attach to sections for PRD consumption
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
> This mapping enables business-analyse-develop's section-splitting to know which UCs/BRs belong to which section.
|
|
88
|
+
### API Endpoints (generate from use cases)
|
|
89
|
+
- UC "Create X" → POST /api/{app}/{module}
|
|
90
|
+
- UC "List X" → GET /api/{app}/{module}
|
|
91
|
+
- UC "Update X" → PUT /api/{app}/{module}/{id}
|
|
92
|
+
- UC "Delete X" → DELETE /api/{app}/{module}/{id}
|
|
93
|
+
- UC "Get X" → GET /api/{app}/{module}/{id}
|
|
94
|
+
- Use permission paths from permissions.json
|
|
127
95
|
|
|
128
|
-
###
|
|
96
|
+
### Section UC/BR Enrichment
|
|
97
|
+
Using sectionCode from usecases.json and rules.json, link each UC and BR to its section.
|
|
129
98
|
|
|
130
|
-
|
|
131
|
-
|
|
99
|
+
### File Mapping (8 Categories)
|
|
100
|
+
Read `references/handoff-file-templates.md` for complete JSON templates.
|
|
101
|
+
All backend paths MUST include {ApplicationName}/ hierarchy.
|
|
132
102
|
|
|
133
103
|
| Category | Source | Key rules |
|
|
134
104
|
|----------|--------|-----------|
|
|
135
|
-
| **Domain** |
|
|
136
|
-
| **Application** |
|
|
137
|
-
| **Infrastructure** |
|
|
105
|
+
| **Domain** | entities[] | Entities, ValueObjects, Enums |
|
|
106
|
+
| **Application** | useCases[] | Services, DTOs, Validators |
|
|
107
|
+
| **Infrastructure** | entities[] | EF Configurations, DbSet |
|
|
138
108
|
| **API** | Generated from useCases + entities | Controllers |
|
|
139
|
-
| **Frontend** |
|
|
140
|
-
| **SeedData** |
|
|
141
|
-
| **Tests** | All layers | Unit, Integration, Security
|
|
142
|
-
| **Documentation** | All layers | Technical docs
|
|
109
|
+
| **Frontend** | screens[] | Pages, Components, Hooks; split by file (NOT monolithic) |
|
|
110
|
+
| **SeedData** | entities + permissions | CORE + business (include category field) |
|
|
111
|
+
| **Tests** | All layers | Unit, Integration, Security |
|
|
112
|
+
| **Documentation** | All layers | Technical docs (can be empty []) |
|
|
143
113
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
- FK fields: `"fkFields": ["EmployeeId->Employee", "DepartmentId->Department"]`
|
|
147
|
-
- ALL pages use `/ui-components` skill
|
|
148
|
-
- Route wiring: separate entry in `filesToCreate.frontend`
|
|
114
|
+
Frontend: each page as separate entry, FK fields, ALL pages use /ui-components.
|
|
115
|
+
Routes: PascalCase module codes → kebab-case (NEVER include /business/ prefix).
|
|
149
116
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
117
|
+
### BR-to-Code Mapping
|
|
118
|
+
Read `references/handoff-mappings.md` for mapping rules.
|
|
119
|
+
For each rule: ruleId, title, module, severity, implementationPoints[].
|
|
153
120
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
- Can be empty `[]` if no documentation is planned at this stage
|
|
121
|
+
### personRoleConfig
|
|
122
|
+
If entity has personRoleConfig, copy verbatim into handoff.
|
|
157
123
|
|
|
158
|
-
###
|
|
124
|
+
### SeedData
|
|
125
|
+
Read `references/handoff-seeddata-generation.md` for core seed generation.
|
|
126
|
+
- category: "core" → Navigation, Permissions, Roles
|
|
127
|
+
- category: "business" → Domain-specific data
|
|
159
128
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
-
|
|
164
|
-
-
|
|
165
|
-
|
|
166
|
-
### 5. Propagate personRoleConfig (GAP #2 Fix)
|
|
167
|
-
|
|
168
|
-
For each entity in `entities.json > entities[]`:
|
|
169
|
-
- IF entity has `personRoleConfig` property:
|
|
170
|
-
- Copy verbatim into handoff entity data
|
|
171
|
-
|
|
172
|
-
### 6. Generate SeedData Core/Business (GAP #3 Fix)
|
|
173
|
-
|
|
174
|
-
Generate seed data from entities and permissions:
|
|
175
|
-
|
|
176
|
-
Each seedData entry MUST include a `category` field:
|
|
177
|
-
|
|
178
|
-
```json
|
|
179
|
-
{
|
|
180
|
-
"path": "src/Infrastructure/Persistence/Seeding/Data/NavigationApplicationSeedData.cs",
|
|
181
|
-
"type": "SeedData",
|
|
182
|
-
"category": "core",
|
|
183
|
-
"module": "shared"
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
- `category: "core"` -- Navigation, Permissions, Roles (mandatory infrastructure)
|
|
188
|
-
- `category: "business"` -- Domain-specific reference/lookup data
|
|
189
|
-
|
|
190
|
-
> **Reference:** See loaded context `handoff-seeddata-generation.md` for complete core seed generation.
|
|
191
|
-
|
|
192
|
-
### 7. Map Entity to Domain File (GAP #4 Fix)
|
|
193
|
-
|
|
194
|
-
> **Reference:** See loaded context `entity-domain-mapping.md` for complete mapping rules.
|
|
195
|
-
|
|
196
|
-
1:1 mapping from BA entity to Domain file:
|
|
197
|
-
|
|
198
|
-
| BA Element | Domain File Path |
|
|
199
|
-
|------------|-----------------|
|
|
200
|
-
| Entity | `src/Domain/Entities/{App}/{Module}/{EntityName}.cs` |
|
|
201
|
-
| ValueObject | `src/Domain/{Module}/ValueObjects/{VOName}.cs` |
|
|
202
|
-
| Enum | `src/Domain/{Module}/Enums/{EnumName}.cs` |
|
|
203
|
-
|
|
204
|
-
### 8. Add Dependencies per File Entry (GAP #7 Fix)
|
|
205
|
-
|
|
206
|
-
Each file entry includes `dependencies[]` ordered by layer:
|
|
129
|
+
### Entity Domain Mapping
|
|
130
|
+
Read `references/entity-domain-mapping.md` for mapping rules.
|
|
131
|
+
- Entity → src/Domain/Entities/{App}/{Module}/{EntityName}.cs
|
|
132
|
+
- ValueObject → src/Domain/{Module}/ValueObjects/{VOName}.cs
|
|
133
|
+
- Enum → src/Domain/{Module}/Enums/{EnumName}.cs
|
|
207
134
|
|
|
135
|
+
### Dependencies per File Entry
|
|
208
136
|
| Layer | Dependencies |
|
|
209
137
|
|-------|-------------|
|
|
210
|
-
| domain |
|
|
211
|
-
| infrastructure |
|
|
212
|
-
| application |
|
|
213
|
-
| api |
|
|
214
|
-
| seedData |
|
|
215
|
-
| frontend |
|
|
216
|
-
| tests |
|
|
217
|
-
| documentation |
|
|
138
|
+
| domain | [] |
|
|
139
|
+
| infrastructure | ["domain"] |
|
|
140
|
+
| application | ["domain"] |
|
|
141
|
+
| api | ["application"] |
|
|
142
|
+
| seedData | ["domain", "infrastructure"] |
|
|
143
|
+
| frontend | ["api"] |
|
|
144
|
+
| tests | ["domain", "application", "infrastructure", "api"] |
|
|
145
|
+
| documentation | [] |
|
|
146
|
+
|
|
147
|
+
### Write Result
|
|
148
|
+
Write via ba-writer.enrichModuleHandoff with the complete handoff payload:
|
|
149
|
+
- complexity, filesToCreate (8 categories), brToCodeMapping, apiEndpointSummary
|
|
150
|
+
- prdFile: ".ralph/prd-{moduleCode}.json"
|
|
151
|
+
- totalFiles, totalTasks, handedOffAt (ISO timestamp)
|
|
152
|
+
- featureDescription: {featureDescription}
|
|
153
|
+
|
|
154
|
+
### POST-CHECK (BLOCKING)
|
|
155
|
+
After writing, verify:
|
|
156
|
+
1. Handoff not empty
|
|
157
|
+
2. All 8 categories present
|
|
158
|
+
3. brToCodeMapping non-empty
|
|
159
|
+
4. Section resources have entity field
|
|
160
|
+
Display: "POST-CHECK PASS: {moduleCode} -- 8 categories, {brCount} BRs mapped"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 3. Display Progress
|
|
218
164
|
|
|
219
|
-
|
|
165
|
+
After each Agent completes, display:
|
|
220
166
|
|
|
221
167
|
```
|
|
222
|
-
|
|
223
|
-
1. moduleCode = modules[i].code
|
|
224
|
-
2. Build handoff payload:
|
|
225
|
-
- complexity (from step 1)
|
|
226
|
-
- filesToCreate (full 8-category structure, filtered for this module)
|
|
227
|
-
- brToCodeMapping (from step 4)
|
|
228
|
-
- apiEndpointSummary (from step 2)
|
|
229
|
-
- prdFile: ".ralph/prd-{moduleCode}.json"
|
|
230
|
-
- totalFiles: count from filesToCreate
|
|
231
|
-
- totalTasks: estimated from complexity
|
|
232
|
-
- handedOffAt: ISO timestamp
|
|
233
|
-
3. Propagate featureDescription from app-level index.json:
|
|
234
|
-
```javascript
|
|
235
|
-
handoffPayload.featureDescription = appIndex.metadata.featureDescription || null;
|
|
236
|
-
```
|
|
237
|
-
4. Write via ba-writer.enrichModuleHandoff({ moduleFeatureId, handoffData })
|
|
238
|
-
5. Display: "handoff {i+1}/{N}: {moduleCode} ({fileCount} files)"
|
|
168
|
+
handoff {i+1}/{N}: {moduleCode} ({fileCount} files) ✓
|
|
239
169
|
```
|
|
240
170
|
|
|
241
|
-
###
|
|
171
|
+
### 4. Display Summary
|
|
242
172
|
|
|
243
|
-
Run the **output** AC script from `references/acceptance-criteria.md`:
|
|
244
|
-
|
|
245
|
-
```bash
|
|
246
|
-
MODULE_JSON="{module_index_json_path}"
|
|
247
|
-
node -e "
|
|
248
|
-
// ... (output AC script from references/acceptance-criteria.md)
|
|
249
|
-
" "$MODULE_JSON"
|
|
250
173
|
```
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
if (!handoff || Object.keys(handoff).length === 0) {
|
|
259
|
-
BLOCKING_ERROR("Module {moduleCode}: handoff is empty");
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// 2. All 8 categories present (AC-08)
|
|
263
|
-
const categories = ['domain', 'application', 'infrastructure', 'api', 'frontend', 'seedData', 'tests', 'documentation'];
|
|
264
|
-
const missing = categories.filter(cat => !handoff.filesToCreate[cat]);
|
|
265
|
-
if (missing.length > 0) {
|
|
266
|
-
BLOCKING_ERROR("Module {moduleCode}: missing categories: " + missing.join(', '));
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// 3. BR-to-code mapping non-empty (AC-09)
|
|
270
|
-
if (!handoff.brToCodeMapping || handoff.brToCodeMapping.length === 0) {
|
|
271
|
-
BLOCKING_ERROR("Module {moduleCode}: brToCodeMapping is empty");
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// 4. Validate section resources have entity field (enables section-splitting)
|
|
275
|
-
const sections = screens || [];
|
|
276
|
-
for (const section of sections) {
|
|
277
|
-
for (const resource of (section.resources || [])) {
|
|
278
|
-
if (!resource.entity) {
|
|
279
|
-
BLOCKING_ERROR("Module {moduleCode}, section {section.code}: resource {resource.code} missing 'entity' field");
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// 5. Display pass
|
|
285
|
-
console.log("POST-CHECK PASS: {moduleCode} -- 8 categories, {brCount} BRs mapped, {sections.length} sections validated");
|
|
174
|
+
================================================================
|
|
175
|
+
TRANSFORM COMPLETE
|
|
176
|
+
================================================================
|
|
177
|
+
Modules processed: {N}/{N}
|
|
178
|
+
Total files mapped: {totalFiles}
|
|
179
|
+
Global complexity: {highest_complexity}
|
|
180
|
+
================================================================
|
|
286
181
|
```
|
|
287
182
|
|
|
288
183
|
---
|