@atlashub/smartstack-cli 3.0.0 → 3.2.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/.documentation/agents.html +1 -371
- package/.documentation/cli-commands.html +1 -1
- package/.documentation/commands.html +1 -1
- package/.documentation/efcore.html +1 -1
- package/.documentation/gitflow.html +1 -1
- package/.documentation/hooks.html +27 -66
- package/.documentation/index.html +166 -166
- package/.documentation/init.html +6 -7
- package/.documentation/installation.html +1 -1
- package/.documentation/prd-json-v2.0.0.md +396 -0
- package/.documentation/ralph-loop.html +1 -9
- package/.documentation/test-web.html +15 -39
- package/.documentation/testing-ba-e2e.md +462 -0
- package/dist/index.js +23 -16
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/templates/agents/gitflow/merge.md +56 -6
- package/templates/agents/gitflow/pr.md +70 -9
- package/templates/project/appsettings.json.template +8 -2
- package/templates/skills/business-analyse/SKILL.md +34 -17
- package/templates/skills/business-analyse/html/ba-interactive.html +147 -84
- package/templates/skills/business-analyse/questionnaire.md +20 -15
- package/templates/skills/business-analyse/steps/step-00-init.md +80 -57
- package/templates/skills/business-analyse/steps/step-03-specify.md +57 -0
- package/templates/skills/business-analyse/steps/step-05-handoff.md +480 -14
- package/templates/skills/business-analyse/steps/step-06-extract.md +131 -3
- package/templates/skills/gitflow/steps/step-pr.md +17 -5
- package/templates/skills/ralph-loop/SKILL.md +158 -33
- package/templates/skills/ralph-loop/steps/step-01-task.md +160 -18
- package/templates/skills/ralph-loop/steps/step-02-execute.md +408 -23
- package/templates/skills/ralph-loop/steps/step-03-commit.md +82 -0
- package/templates/skills/ralph-loop/steps/step-04-check.md +305 -9
- package/templates/skills/ralph-loop/steps/step-05-report.md +115 -0
|
@@ -67,13 +67,27 @@ Lire le fichier passe en argument : {extract_path}
|
|
|
67
67
|
"businessRules": [{ "id": "", "name": "", "category": "", "statement": "", "example": "" }],
|
|
68
68
|
"entities": [{ "name": "", "description": "", "attributes": [{ "name": "", "description": "" }], "relationships": [] }],
|
|
69
69
|
"permissions": [],
|
|
70
|
-
"notes": ""
|
|
71
|
-
"mockupNotes": ""
|
|
70
|
+
"notes": ""
|
|
72
71
|
}
|
|
73
72
|
},
|
|
74
73
|
"consolidation": {
|
|
75
74
|
"interactions": [],
|
|
76
|
-
"e2eFlows": [{ "name": "", "steps": [{ "module": "", "action": "" }], "actors": "" }]
|
|
75
|
+
"e2eFlows": [{ "name": "", "steps": [{ "module": "", "action": "" }], "actors": "", "diagram": "" }]
|
|
76
|
+
},
|
|
77
|
+
"artifacts": {
|
|
78
|
+
"wireframes": {
|
|
79
|
+
"{moduleCode}": [
|
|
80
|
+
{ "screen": "", "section": "", "format": "ascii|svg", "content": "", "description": "",
|
|
81
|
+
"elements": [], "actions": [], "componentMapping": [], "layout": {}, "permissionsRequired": [] }
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
"e2eFlows": [
|
|
85
|
+
{ "name": "", "diagram": "", "steps": [], "actors": "", "modules": "" }
|
|
86
|
+
],
|
|
87
|
+
"dependencyGraph": {
|
|
88
|
+
"nodes": [{ "id": "", "label": "", "type": "" }],
|
|
89
|
+
"edges": [{ "from": "", "to": "", "description": "" }]
|
|
90
|
+
}
|
|
77
91
|
}
|
|
78
92
|
}
|
|
79
93
|
```
|
|
@@ -407,6 +421,113 @@ ba-writer.enrichSection({
|
|
|
407
421
|
ba-writer.updateStatus({feature_id}, "consolidated")
|
|
408
422
|
```
|
|
409
423
|
|
|
424
|
+
### 6-bis. Extraire et reconstituer les artefacts visuels (NEW)
|
|
425
|
+
|
|
426
|
+
> **NEW in v6.2:** Visual artifacts (wireframes, E2E diagrams, dependency graph) are now extracted from the exported JSON and reconstituted into feature.json.
|
|
427
|
+
|
|
428
|
+
**IF** `artifacts` exists in exported JSON:
|
|
429
|
+
|
|
430
|
+
#### Extract wireframes per module
|
|
431
|
+
|
|
432
|
+
Pour chaque module dans `artifacts.wireframes`:
|
|
433
|
+
|
|
434
|
+
```
|
|
435
|
+
FOR EACH moduleCode IN artifacts.wireframes:
|
|
436
|
+
moduleWireframes = artifacts.wireframes[moduleCode]
|
|
437
|
+
|
|
438
|
+
// Locate the module feature.json
|
|
439
|
+
moduleFeature = ba-reader.findModuleFeature({feature_id}, moduleCode)
|
|
440
|
+
|
|
441
|
+
// Map wireframes to specification.uiWireframes[]
|
|
442
|
+
uiWireframes = moduleWireframes.map(wf => ({
|
|
443
|
+
"screen": wf.screen,
|
|
444
|
+
"section": wf.section,
|
|
445
|
+
"mockupFormat": wf.format,
|
|
446
|
+
"mockup": wf.content,
|
|
447
|
+
"description": wf.description || "",
|
|
448
|
+
"elements": wf.elements || [],
|
|
449
|
+
"actions": wf.actions || [],
|
|
450
|
+
"permissionsRequired": wf.permissionsRequired || [],
|
|
451
|
+
"componentMapping": wf.componentMapping || [],
|
|
452
|
+
"layout": wf.layout || null
|
|
453
|
+
}))
|
|
454
|
+
|
|
455
|
+
// Write to module feature.json (enriching specification section)
|
|
456
|
+
ba-writer.enrichSection({
|
|
457
|
+
featureId: moduleFeature.id,
|
|
458
|
+
section: "specification",
|
|
459
|
+
data: { uiWireframes: uiWireframes }
|
|
460
|
+
})
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
**Validation:** For each wireframe:
|
|
464
|
+
- `screen` must be unique within module
|
|
465
|
+
- `mockupFormat` must be "ascii" or "svg"
|
|
466
|
+
- `mockup` content must not be empty
|
|
467
|
+
- `componentMapping` array must have at least one entry
|
|
468
|
+
- `layout` object must have `type` and `regions` if present
|
|
469
|
+
|
|
470
|
+
#### Extract E2E flow diagrams
|
|
471
|
+
|
|
472
|
+
IF `artifacts.e2eFlows` exists:
|
|
473
|
+
|
|
474
|
+
```
|
|
475
|
+
e2eFlows = artifacts.e2eFlows.map(flow => ({
|
|
476
|
+
"name": flow.name,
|
|
477
|
+
"modules": flow.modules.split(" → ").map(m => m.trim()), // "OrderManagement → Invoicing" → ["OrderManagement", "Invoicing"]
|
|
478
|
+
"steps": flow.steps || [],
|
|
479
|
+
"diagram": flow.diagram, // NEW: ASCII diagram preserved
|
|
480
|
+
"actors": flow.actors.split(", ").map(a => a.trim())
|
|
481
|
+
}))
|
|
482
|
+
|
|
483
|
+
// Merge with existing e2eFlows from consolidation.e2eFlows
|
|
484
|
+
ba-writer.enrichSection({
|
|
485
|
+
featureId: {feature_id},
|
|
486
|
+
section: "consolidation",
|
|
487
|
+
data: { e2eFlows: e2eFlows }
|
|
488
|
+
})
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
**Validation:** For each E2E flow:
|
|
492
|
+
- `diagram` must not be empty if present
|
|
493
|
+
- `modules` array must match modules defined in master feature.json
|
|
494
|
+
- `steps` must have at least 2 entries (cross-module flow)
|
|
495
|
+
|
|
496
|
+
#### Extract dependency graph (optional)
|
|
497
|
+
|
|
498
|
+
IF `artifacts.dependencyGraph` exists:
|
|
499
|
+
|
|
500
|
+
```
|
|
501
|
+
dependencyGraph = {
|
|
502
|
+
"nodes": artifacts.dependencyGraph.nodes.map(n => ({
|
|
503
|
+
"id": n.id,
|
|
504
|
+
"label": n.label || n.id,
|
|
505
|
+
"type": n.type || "data-centric"
|
|
506
|
+
})),
|
|
507
|
+
"edges": artifacts.dependencyGraph.edges.map(e => ({
|
|
508
|
+
"from": e.from,
|
|
509
|
+
"to": e.to,
|
|
510
|
+
"description": e.description || ""
|
|
511
|
+
}))
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Write to master feature.json
|
|
515
|
+
ba-writer.enrichSection({
|
|
516
|
+
featureId: {feature_id},
|
|
517
|
+
section: "decomposition",
|
|
518
|
+
data: { dependencyGraph: dependencyGraph }
|
|
519
|
+
})
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
**Post-extraction summary:**
|
|
523
|
+
|
|
524
|
+
```
|
|
525
|
+
✓ Artefacts visuels extraits:
|
|
526
|
+
- Wireframes: {total_wireframe_count} across {module_count} modules
|
|
527
|
+
- E2E diagrams: {e2e_flow_count}
|
|
528
|
+
- Dependency graph: {node_count} nodes, {edge_count} edges
|
|
529
|
+
```
|
|
530
|
+
|
|
410
531
|
### 7. Resume de l'extraction
|
|
411
532
|
|
|
412
533
|
Afficher un resume comparatif :
|
|
@@ -432,11 +553,18 @@ Afficher un resume comparatif :
|
|
|
432
553
|
| Regles metier | {total} | analysis.businessRules |
|
|
433
554
|
| Entites | {total} | analysis.entities |
|
|
434
555
|
| Parcours E2E | {count} | consolidation.e2eFlows |
|
|
556
|
+
| Maquettes (wireframes) | {total} | specification.uiWireframes[] |
|
|
557
|
+
| Diagrammes E2E | {count} | consolidation.e2eFlows[].diagram |
|
|
435
558
|
|
|
436
559
|
Fichiers generes :
|
|
437
560
|
- docs/business/{app}/business-analyse/v1.0/feature.json (master)
|
|
438
561
|
- docs/business/{app}/{module}/business-analyse/v1.0/feature.json (par module)
|
|
439
562
|
|
|
563
|
+
Artefacts visuels preserves :
|
|
564
|
+
- Toutes les maquettes ASCII/SVG validees lors de la specification
|
|
565
|
+
- Tous les diagrammes E2E pour les flux cross-module
|
|
566
|
+
- Graphe de dependances entre modules
|
|
567
|
+
|
|
440
568
|
═══════════════════════════════════════════════════════════════
|
|
441
569
|
```
|
|
442
570
|
|
|
@@ -38,13 +38,25 @@ fi
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
CURRENT=$(git rev-parse --abbrev-ref HEAD)
|
|
41
|
+
BRANCH_TYPE=$(echo $CURRENT | cut -d'/' -f1)
|
|
42
|
+
|
|
43
|
+
# CRITICAL: Verify config was loaded
|
|
44
|
+
if [ -z "$GF_MAIN_BRANCH" ] || [ -z "$GF_DEVELOP_BRANCH" ]; then
|
|
45
|
+
echo "❌ GitFlow config not loaded properly"
|
|
46
|
+
echo "→ Variables GF_MAIN_BRANCH and GF_DEVELOP_BRANCH are empty"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
# Determine target branch based on type (using config values)
|
|
51
|
+
case "$BRANCH_TYPE" in
|
|
52
|
+
feature) TARGET_BRANCH="$GF_DEVELOP_BRANCH" ;;
|
|
53
|
+
release) TARGET_BRANCH="$GF_MAIN_BRANCH" ;;
|
|
54
|
+
hotfix) TARGET_BRANCH="$GF_MAIN_BRANCH" ;;
|
|
55
|
+
*) TARGET_BRANCH="$GF_DEVELOP_BRANCH" ;;
|
|
47
56
|
esac
|
|
57
|
+
|
|
58
|
+
echo "✓ Branch: $CURRENT (type: $BRANCH_TYPE)"
|
|
59
|
+
echo "✓ Target: $TARGET_BRANCH"
|
|
48
60
|
```
|
|
49
61
|
|
|
50
62
|
### 3. Check Prerequisites
|
|
@@ -10,27 +10,38 @@ Execute the Ralph Weegund technique - an iterative development methodology where
|
|
|
10
10
|
</objective>
|
|
11
11
|
|
|
12
12
|
<quick_start>
|
|
13
|
-
**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
**Three ways to start Ralph Loop:**
|
|
14
|
+
|
|
15
|
+
1. **From Business Analysis (RECOMMENDED - NEW v6.1):**
|
|
16
|
+
```bash
|
|
17
|
+
/business-analyse MyFeature
|
|
18
|
+
# At the end, choose "Ralph Loop" → automatic launch
|
|
19
|
+
# No arguments needed - prd.json already generated
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
2. **Manual start with existing prd.json:**
|
|
23
|
+
```bash
|
|
24
|
+
/ralph-loop
|
|
25
|
+
# Ralph detects .ralph/prd.json and resumes automatically
|
|
26
|
+
# Works after BA handoff or previous Ralph session
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
3. **Direct task (no BA):**
|
|
30
|
+
```bash
|
|
31
|
+
/ralph-loop implement user authentication
|
|
32
|
+
# Ralph creates prd.json on the fly
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**With options:**
|
|
20
36
|
|
|
21
37
|
```bash
|
|
38
|
+
# Completion promise
|
|
22
39
|
/ralph-loop -c "COMPLETE" refactor the cache layer
|
|
23
|
-
```
|
|
24
40
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
```bash
|
|
41
|
+
# Max iterations
|
|
28
42
|
/ralph-loop -m 20 -c "TESTS PASS" add comprehensive tests
|
|
29
|
-
```
|
|
30
43
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
```bash
|
|
44
|
+
# Verbose mode
|
|
34
45
|
/ralph-loop -v -c "DONE" fix all linting errors
|
|
35
46
|
```
|
|
36
47
|
|
|
@@ -39,6 +50,7 @@ Execute the Ralph Weegund technique - an iterative development methodology where
|
|
|
39
50
|
- `-m N` (max): Maximum iterations before auto-stop
|
|
40
51
|
- `-c TEXT` (complete): Completion promise text
|
|
41
52
|
- `-v` (verbose): Detailed logging
|
|
53
|
+
- `-r` (resume): Resume from previous state
|
|
42
54
|
|
|
43
55
|
See `<parameters>` for complete flag list.
|
|
44
56
|
</quick_start>
|
|
@@ -99,33 +111,144 @@ The same prompt is fed to Claude repeatedly. The "self-referential" aspect comes
|
|
|
99
111
|
5. Claude sees previous work in the files
|
|
100
112
|
6. Iteratively improves until completion promise is output
|
|
101
113
|
|
|
114
|
+
**Iterative Development Cycle (per task):**
|
|
115
|
+
```
|
|
116
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
117
|
+
│ RALPH LOOP - CYCLE │
|
|
118
|
+
├─────────────────────────────────────────────────────────────┤
|
|
119
|
+
│ │
|
|
120
|
+
│ 1. ANALYSE → Load next task from prd.json │
|
|
121
|
+
│ (UC, FR, BR, wireframes, acceptance) │
|
|
122
|
+
│ │
|
|
123
|
+
│ 2. DÉVELOPPEMENT → Generate code for task │
|
|
124
|
+
│ ├─ Backend: Entity, Service, Repository, Controller │
|
|
125
|
+
│ ├─ Tests: Unit tests (xUnit) + non-regression │
|
|
126
|
+
│ ├─ Frontend: Page, Component, Hook (match wireframe) │
|
|
127
|
+
│ ├─ Tests: Frontend tests (React Testing Library) │
|
|
128
|
+
│ ├─ SeedData: CORE RBAC (5 entries) + business data │
|
|
129
|
+
│ └─ Docs: Inline comments + tooltips + i18n keys │
|
|
130
|
+
│ │
|
|
131
|
+
│ 3. VALIDATION → Commit changes + MCP conventions check │
|
|
132
|
+
│ (validate_conventions, check_migrations) │
|
|
133
|
+
│ │
|
|
134
|
+
│ 4. TEST → Run tests (dotnet test + npm test) │
|
|
135
|
+
│ ├─ Unit tests │
|
|
136
|
+
│ ├─ Integration tests │
|
|
137
|
+
│ ├─ Security tests (tenant isolation) │
|
|
138
|
+
│ └─ E2E tests (critical flows) │
|
|
139
|
+
│ │
|
|
140
|
+
│ 5. CORRECTION → If tests fail: │
|
|
141
|
+
│ ├─ Analyze error logs │
|
|
142
|
+
│ ├─ Fix root cause │
|
|
143
|
+
│ ├─ Commit fix │
|
|
144
|
+
│ └─ Return to step 4 │
|
|
145
|
+
│ │
|
|
146
|
+
│ 6. NEXT TASK → Mark task as completed, loop to step 1 │
|
|
147
|
+
│ │
|
|
148
|
+
│ 🎯 Goal: 100% tests pass before moving to next task │
|
|
149
|
+
│ 📊 Coverage: 95-100% (tests auto-generated) │
|
|
150
|
+
│ │
|
|
151
|
+
└─────────────────────────────────────────────────────────────┘
|
|
152
|
+
```
|
|
153
|
+
|
|
102
154
|
**Completion signal:**
|
|
103
155
|
```
|
|
104
156
|
<promise>{completion_promise}</promise>
|
|
105
157
|
```
|
|
106
158
|
|
|
107
159
|
The loop only stops when this exact tag is output or max iterations reached.
|
|
160
|
+
|
|
161
|
+
**What Ralph generates per task:**
|
|
162
|
+
- **Backend code**: Entities (Domain), Services (Application), Repositories (Infrastructure), Controllers (API)
|
|
163
|
+
- **Unit tests**: xUnit tests for domain logic, services, repositories
|
|
164
|
+
- **Integration tests**: Controller tests with WebApplicationFactory
|
|
165
|
+
- **Frontend code**: React pages, components, custom hooks (matching BA wireframes)
|
|
166
|
+
- **Frontend tests**: React Testing Library for components and pages
|
|
167
|
+
- **SeedData**: 5 CORE entries (Navigation, Permissions, Roles, Tenants, Users) + business reference data
|
|
168
|
+
- **Documentation**: Inline code comments, user-facing tooltips, i18n translation keys
|
|
169
|
+
- **Security tests**: Tenant isolation, permission checks, OWASP validations
|
|
170
|
+
|
|
171
|
+
**prd.json structure (input from BA):**
|
|
172
|
+
The prd.json is generated by `/business-analyse` via `ss derive-prd` command. It contains:
|
|
173
|
+
- **feature**: Feature description (from BA)
|
|
174
|
+
- **tasks[]**: Task breakdown by category (domain, application, infrastructure, api, frontend, i18n, test, validation)
|
|
175
|
+
- Each task has: id, description, category, dependencies, acceptance_criteria, linkedFRs, linkedUCs, linkedBRs
|
|
176
|
+
- Frontend tasks include: linkedWireframes (screen IDs from BA mockups), wireframeAcceptanceCriteria
|
|
177
|
+
- SeedData tasks specify: category (core|business), source (specification.seedDataCore or seedDataBusiness)
|
|
178
|
+
- **source**: Traceability to feature.json path (source of truth)
|
|
179
|
+
- **metadata**: Project context (branch, namespace, module order)
|
|
180
|
+
- **config**: max_iterations, completion_promise, current_iteration
|
|
181
|
+
|
|
182
|
+
Ralph reads prd.json to know WHAT to generate, then generates it, tests it, fixes it, and moves to the next task.
|
|
108
183
|
</ralph_concept>
|
|
109
184
|
|
|
110
185
|
<workflow>
|
|
111
186
|
**Standard flow (single module):**
|
|
112
|
-
1. Parse flags and task description
|
|
113
|
-
2. Verify MCP servers are available (MANDATORY)
|
|
114
|
-
3. Initialize .ralph/ structure and state files
|
|
115
|
-
4. Load current task from prd.json
|
|
116
|
-
5. Execute
|
|
117
|
-
6. Commit changes, update progress
|
|
118
|
-
7. Check completion
|
|
119
|
-
8.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
187
|
+
1. Parse flags and task description (step-00)
|
|
188
|
+
2. Verify MCP servers are available (step-00, MANDATORY)
|
|
189
|
+
3. Initialize .ralph/ structure and state files (step-00)
|
|
190
|
+
4. Load current task from prd.json — create task breakdown if new (step-01, READ ONCE)
|
|
191
|
+
5. Execute first task (step-02, READ ONCE)
|
|
192
|
+
6. Commit changes, update progress (step-03, READ ONCE)
|
|
193
|
+
7. Check completion → enter COMPACT LOOP (step-04)
|
|
194
|
+
8. **COMPACT LOOP** (step-04 section 5, NO re-reading step files):
|
|
195
|
+
- Find eligible tasks → batch by category (max 5)
|
|
196
|
+
- Execute batch inline (generate code)
|
|
197
|
+
- Run tests (dotnet test + npm test)
|
|
198
|
+
- If tests fail: analyze → fix → re-test (loop until 100% pass)
|
|
199
|
+
- Commit batch (only when tests pass)
|
|
200
|
+
- Re-check completion → loop or finish
|
|
201
|
+
9. When complete: generate final report (step-05)
|
|
202
|
+
|
|
203
|
+
**Multi-module flow (from BA handoff - NEW v6.1: automatic launch):**
|
|
204
|
+
1-3. Same as standard flow (or launched automatically from `/business-analyse`)
|
|
123
205
|
4. Detect `prd-*.json` files → create `modules-queue.json`
|
|
124
206
|
5. Copy current module's prd to `prd.json`
|
|
125
|
-
6. Execute all tasks for current module
|
|
126
|
-
|
|
127
|
-
|
|
207
|
+
6. Execute all tasks for current module via COMPACT LOOP:
|
|
208
|
+
- Process tasks by category (domain → seeddata → application → infrastructure → api → frontend → i18n → tests)
|
|
209
|
+
- For each task: generate → test → fix (if needed) → re-test → commit (when pass)
|
|
210
|
+
- Each task generates: backend code + tests + frontend code + tests + seeddata + docs
|
|
211
|
+
- Each frontend task respects wireframes from BA (specification.uiWireframes[])
|
|
212
|
+
- Continue until ALL tasks of module = completed
|
|
213
|
+
7. When module complete: advance to next module in queue (step-04 section 3)
|
|
214
|
+
8. Repeat steps 5-7 for each module (step-01 is re-read ONLY for module transitions)
|
|
128
215
|
9. When all modules done: generate cross-module report
|
|
216
|
+
|
|
217
|
+
**Note:** When launched from `/business-analyse` (v6.1+), Ralph Loop receives:
|
|
218
|
+
- `.ralph/prd-{module}.json` for each module (generated by `ss derive-prd`)
|
|
219
|
+
- Each prd contains: tasks breakdown with UC/FR/BR/wireframes/acceptance criteria
|
|
220
|
+
- Task categories: domain, application, infrastructure, api, frontend, i18n, test, validation
|
|
221
|
+
- Each task linked to: functional requirements (FR), use cases (UC), business rules (BR)
|
|
222
|
+
- Frontend tasks include: linkedWireframes[] (screen IDs from BA mockups)
|
|
223
|
+
- SeedData tasks specify: category (core 5 entries MANDATORY + business data)
|
|
224
|
+
- `.ralph/progress.txt` with comprehensive task tracker (hierarchical: module → layer → tasks)
|
|
225
|
+
- Module order from BA's topological dependency graph (dependencies first)
|
|
226
|
+
- No arguments needed - fully configured by BA handoff
|
|
227
|
+
|
|
228
|
+
**Task execution cycle (per task):**
|
|
229
|
+
```
|
|
230
|
+
LOAD TASK → GENERATE CODE → COMMIT → RUN TESTS → [FAIL?] → ANALYZE ERROR → FIX → RE-TEST → [PASS!] → NEXT TASK
|
|
231
|
+
↑___________________________________________|
|
|
232
|
+
(loop until 100% tests pass)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**What gets generated per module:**
|
|
236
|
+
1. **Domain layer**: Entities, Value Objects, Enums, Domain Exceptions
|
|
237
|
+
2. **SeedData layer**: 5 CORE entries (Navigation, Permissions, Roles, Tenants, Users) + business reference data
|
|
238
|
+
3. **Application layer**: Services, DTOs, Validators, Query Handlers
|
|
239
|
+
4. **Infrastructure layer**: Repositories, DbContext, Specifications
|
|
240
|
+
5. **API layer**: Controllers, Error Handlers, Validation Responses
|
|
241
|
+
6. **Frontend layer**: Pages (matching wireframes), Components, Custom Hooks, Forms
|
|
242
|
+
7. **I18n layer**: Translation keys (fr, en, it, de) for UI labels
|
|
243
|
+
8. **Tests layer**: Unit tests (Domain, Application), Integration tests (API), Security tests (tenant isolation), E2E tests (critical flows)
|
|
244
|
+
|
|
245
|
+
**Acceptance criteria per task:**
|
|
246
|
+
- Code compiles (dotnet build + npm build)
|
|
247
|
+
- Tests pass (dotnet test + npm test)
|
|
248
|
+
- MCP conventions validated (validate_conventions)
|
|
249
|
+
- Wireframes respected (frontend pages match BA mockups from specification.uiWireframes[])
|
|
250
|
+
- Business rules implemented (BR-to-code mapping from BA)
|
|
251
|
+
- Security enforced (tenant isolation, RBAC permissions)
|
|
129
252
|
</workflow>
|
|
130
253
|
|
|
131
254
|
<state_variables>
|
|
@@ -279,12 +402,14 @@ Before ANY work, verify MCP servers:
|
|
|
279
402
|
|
|
280
403
|
<execution_rules>
|
|
281
404
|
|
|
282
|
-
- **Load
|
|
283
|
-
- **VERIFY MCP FIRST** - Never skip MCP validation
|
|
284
|
-
- **
|
|
285
|
-
- **COMMIT AFTER EACH
|
|
405
|
+
- **Load step files ONCE** - Step files are read only on FIRST iteration. After that, use the COMPACT LOOP in step-04 section 5.
|
|
406
|
+
- **VERIFY MCP FIRST** - Never skip MCP validation at init
|
|
407
|
+
- **BATCH same-category tasks** - Execute up to 5 tasks of the same category per iteration (reduces loop iterations from 30+ to ~8)
|
|
408
|
+
- **COMMIT AFTER EACH BATCH** - One commit per batch, not per individual task
|
|
286
409
|
- **UPDATE progress.txt** - Persist learnings
|
|
287
410
|
- **NEVER fake completion** - Only output promise when truly done
|
|
411
|
+
- **NEVER STOP THE LOOP** - The loop is AUTONOMOUS. DO NOT pause between iterations. DO NOT wait for user input. Only stop on: completion, max iterations, dead-end, or explicit user interruption. Stopping for any other reason wastes context and causes re-reads.
|
|
412
|
+
- **COMPACT OUTPUT** - During loop iterations, use 1-2 lines per task. Save verbose output for the final report.
|
|
288
413
|
</execution_rules>
|
|
289
414
|
|
|
290
415
|
<success_criteria>
|
|
@@ -6,6 +6,36 @@ next_step: steps/step-02-execute.md
|
|
|
6
6
|
|
|
7
7
|
# Step 1: Load Task
|
|
8
8
|
|
|
9
|
+
> **MODULE TRANSITION CHECK (MANDATORY):**
|
|
10
|
+
> Before applying the "Only Read Once" rule, check for module transition marker:
|
|
11
|
+
|
|
12
|
+
```javascript
|
|
13
|
+
const moduleChangedPath = '.ralph/module-changed.json';
|
|
14
|
+
const moduleTransition = fileExists(moduleChangedPath);
|
|
15
|
+
|
|
16
|
+
if (moduleTransition) {
|
|
17
|
+
const transitionData = readJSON(moduleChangedPath);
|
|
18
|
+
console.log(`🔄 Module transition detected: ${transitionData.fromModule} → ${transitionData.toModule}`);
|
|
19
|
+
console.log(` Reloading step-01 to initialize new module...`);
|
|
20
|
+
|
|
21
|
+
// Delete flag (consume it)
|
|
22
|
+
deleteFile(moduleChangedPath);
|
|
23
|
+
|
|
24
|
+
// PROCEED with step-01 execution (skip "Only Read Once" rule below)
|
|
25
|
+
// This is the EXCEPTION case for multi-module workflows
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
> **CONTEXT OPTIMIZATION:** This file is normally read ONCE per module (first iteration).
|
|
30
|
+
> After the first full iteration (step-01 → step-02 → step-03 → step-04),
|
|
31
|
+
> ALL subsequent iterations within the SAME module MUST use the COMPACT LOOP in step-04-check.md section 5.
|
|
32
|
+
> **DO NOT re-read this file for iterations > 1 of the same module.**
|
|
33
|
+
>
|
|
34
|
+
> **EXCEPTION:** When transitioning between modules (multi-module workflows), step-01 MUST be re-read
|
|
35
|
+
> to load the next module's PRD. This is signaled by `.ralph/module-changed.json` file (checked above).
|
|
36
|
+
>
|
|
37
|
+
> If you are re-reading this file on iteration > 1 AND no module transition detected, STOP and go to step-04 section 5 instead.
|
|
38
|
+
|
|
9
39
|
## YOUR TASK:
|
|
10
40
|
|
|
11
41
|
Load the current task from prd.json or create initial task breakdown with categories, dependencies, and acceptance criteria.
|
|
@@ -18,7 +48,10 @@ Load the current task from prd.json or create initial task breakdown with catego
|
|
|
18
48
|
|
|
19
49
|
### 0. Multi-Module Queue Check
|
|
20
50
|
|
|
21
|
-
|
|
51
|
+
**✅ ALWAYS check for modules-queue.json, even on iteration > 1:**
|
|
52
|
+
|
|
53
|
+
> **CRITICAL:** This section MUST execute even when step-01 is re-read for module transitions.
|
|
54
|
+
> The module-changed.json flag (checked above) ensures this section runs when needed.
|
|
22
55
|
|
|
23
56
|
```javascript
|
|
24
57
|
const queuePath = '.ralph/modules-queue.json';
|
|
@@ -28,22 +61,52 @@ if (hasQueue) {
|
|
|
28
61
|
const queue = readJSON(queuePath);
|
|
29
62
|
const currentModule = queue.modules[queue.currentIndex];
|
|
30
63
|
|
|
31
|
-
console.log(`
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
64
|
+
console.log(`
|
|
65
|
+
╔══════════════════════════════════════════════════════════════════╗
|
|
66
|
+
║ Multi-Module Workflow Detected ║
|
|
67
|
+
╠══════════════════════════════════════════════════════════════════╣
|
|
68
|
+
║ Current Module: ${currentModule.code} (${queue.currentIndex + 1}/${queue.totalModules}) ║
|
|
69
|
+
║ Status: ${currentModule.status} ║
|
|
70
|
+
║ PRD File: ${currentModule.prdFile} ║
|
|
71
|
+
╚══════════════════════════════════════════════════════════════════╝
|
|
72
|
+
`);
|
|
73
|
+
|
|
74
|
+
// ✅ FIX #3: RESTORE multi-module state variables
|
|
75
|
+
// These variables persist across step files and are critical for multi-module coordination
|
|
76
|
+
{modules_queue} = queue;
|
|
77
|
+
{current_module} = currentModule.code;
|
|
78
|
+
|
|
79
|
+
// ✅ Load or verify current module's PRD is in .ralph/prd.json
|
|
80
|
+
// On module transition, step-04 already loaded it, but we verify here
|
|
81
|
+
const currentPrd = readJSON('.ralph/prd.json');
|
|
82
|
+
|
|
83
|
+
// Verify PRD matches current module (sanity check)
|
|
84
|
+
if (currentPrd.metadata && currentPrd.metadata.moduleCode !== currentModule.code) {
|
|
85
|
+
console.log(`⚠️ PRD mismatch detected. Loading correct PRD for module ${currentModule.code}...`);
|
|
86
|
+
|
|
87
|
+
// Load current module's PRD
|
|
88
|
+
const modulePrd = readJSON(currentModule.prdFile);
|
|
89
|
+
|
|
90
|
+
// Transform PrdJson format to Ralph v2 if needed
|
|
91
|
+
if (modulePrd.project && modulePrd.requirements && !modulePrd.$version) {
|
|
92
|
+
// This is a PrdJson format from ss derive-prd → transform to Ralph v2
|
|
93
|
+
const transformedPrd = transformPrdJsonToRalphV2(modulePrd, currentModule.code);
|
|
94
|
+
writeJSON('.ralph/prd.json', transformedPrd);
|
|
95
|
+
console.log(`✅ Transformed and loaded PRD for module: ${currentModule.code}`);
|
|
96
|
+
} else {
|
|
97
|
+
// Already Ralph v2 format
|
|
98
|
+
writeJSON('.ralph/prd.json', modulePrd);
|
|
99
|
+
console.log(`✅ Loaded PRD for module: ${currentModule.code}`);
|
|
100
|
+
}
|
|
41
101
|
} else {
|
|
42
|
-
|
|
43
|
-
writeJSON('.ralph/prd.json', modulePrd);
|
|
102
|
+
console.log(`✅ PRD already loaded for module: ${currentModule.code}`);
|
|
44
103
|
}
|
|
45
104
|
|
|
46
|
-
console.log(`
|
|
105
|
+
console.log(`State restored: modules_queue and current_module set`);
|
|
106
|
+
} else {
|
|
107
|
+
// Single-module workflow
|
|
108
|
+
{modules_queue} = null;
|
|
109
|
+
{current_module} = null;
|
|
47
110
|
}
|
|
48
111
|
```
|
|
49
112
|
|
|
@@ -76,23 +139,37 @@ function transformPrdJsonToRalphV2(prdJson, moduleCode) {
|
|
|
76
139
|
const filesToCreate = prdJson.implementation?.filesToCreate || {};
|
|
77
140
|
|
|
78
141
|
// 1. Generate tasks from implementation.filesToCreate (primary source)
|
|
142
|
+
// CRITICAL: Frontend and i18n tasks are CONSOLIDATED into ONE module-level task each.
|
|
143
|
+
// These use MCP scaffolding tools, NOT manual file-by-file generation.
|
|
79
144
|
const lastIdByCategory = {};
|
|
145
|
+
const frontendFiles = []; // Collect frontend files for consolidated task
|
|
146
|
+
const i18nFiles = []; // Collect i18n files for consolidated task
|
|
80
147
|
|
|
81
148
|
for (const layer of layerOrder) {
|
|
82
149
|
const files = filesToCreate[layer.key] || [];
|
|
150
|
+
|
|
151
|
+
// FRONTEND & I18N: Collect files, do NOT create individual tasks
|
|
152
|
+
if (layer.category === "frontend") {
|
|
153
|
+
frontendFiles.push(...files);
|
|
154
|
+
continue; // Skip individual task creation
|
|
155
|
+
}
|
|
156
|
+
|
|
83
157
|
for (const fileSpec of files) {
|
|
158
|
+
// Check if this is an i18n file (category "infrastructure" but path contains i18n)
|
|
159
|
+
if (fileSpec.path?.includes('i18n/') || fileSpec.path?.includes('/locales/')) {
|
|
160
|
+
i18nFiles.push(fileSpec);
|
|
161
|
+
continue; // Skip individual task creation
|
|
162
|
+
}
|
|
163
|
+
|
|
84
164
|
const depIds = [];
|
|
85
165
|
// Depend on last task in same category (sequential within layer)
|
|
86
166
|
if (lastIdByCategory[layer.category]) {
|
|
87
167
|
depIds.push(lastIdByCategory[layer.category]);
|
|
88
168
|
}
|
|
89
|
-
// Cross-layer: api depends on last application task
|
|
169
|
+
// Cross-layer: api depends on last application task
|
|
90
170
|
if (layer.category === "api" && lastIdByCategory["application"]) {
|
|
91
171
|
depIds.push(lastIdByCategory["application"]);
|
|
92
172
|
}
|
|
93
|
-
if (layer.category === "frontend" && lastIdByCategory["api"]) {
|
|
94
|
-
depIds.push(lastIdByCategory["api"]);
|
|
95
|
-
}
|
|
96
173
|
if (layer.category === "test" && lastIdByCategory["api"]) {
|
|
97
174
|
depIds.push(lastIdByCategory["api"]);
|
|
98
175
|
}
|
|
@@ -131,6 +208,71 @@ function transformPrdJsonToRalphV2(prdJson, moduleCode) {
|
|
|
131
208
|
}
|
|
132
209
|
}
|
|
133
210
|
|
|
211
|
+
// 1b. Create CONSOLIDATED frontend task (ONE task per module, uses MCP tools)
|
|
212
|
+
if (frontendFiles.length > 0) {
|
|
213
|
+
const apiDepId = lastIdByCategory["api"] || lastIdByCategory["application"];
|
|
214
|
+
const allLinkedUCs = [...new Set(frontendFiles.flatMap(f => f.linkedUCs || []))];
|
|
215
|
+
const allLinkedWireframes = [...new Set(frontendFiles.flatMap(f => f.linkedWireframes || []))];
|
|
216
|
+
const allPaths = frontendFiles.map(f => f.path);
|
|
217
|
+
|
|
218
|
+
tasks.push({
|
|
219
|
+
id: taskId,
|
|
220
|
+
description: `[frontend] Generate COMPLETE frontend for module ${moduleCode} via MCP scaffold tools (${frontendFiles.length} files: pages, components, hooks, API client)`,
|
|
221
|
+
status: "pending",
|
|
222
|
+
category: "frontend",
|
|
223
|
+
dependencies: apiDepId ? [apiDepId] : [],
|
|
224
|
+
acceptance_criteria: [
|
|
225
|
+
"MCP scaffold_api_client called → API client + types generated",
|
|
226
|
+
"MCP scaffold_routes called → routes.tsx updated with nested routes inside Layout wrapper",
|
|
227
|
+
"Pages match wireframes: " + allLinkedWireframes.join(", "),
|
|
228
|
+
"SmartTable for lists (NOT HTML tables), EntityCard for grids (NOT custom divs)",
|
|
229
|
+
"CSS variables ONLY (NO hardcoded Tailwind colors like bg-blue-600)",
|
|
230
|
+
"useNavigate + useParams for routing, NOT window.location",
|
|
231
|
+
"Loading/error/empty states on all pages",
|
|
232
|
+
"4-language i18n keys (fr, en, it, de)",
|
|
233
|
+
"npm run typecheck passes"
|
|
234
|
+
].join("; "),
|
|
235
|
+
started_at: null,
|
|
236
|
+
completed_at: null,
|
|
237
|
+
iteration: null,
|
|
238
|
+
commit_hash: null,
|
|
239
|
+
files_changed: { created: allPaths, modified: [] },
|
|
240
|
+
validation: null,
|
|
241
|
+
error: null,
|
|
242
|
+
module: moduleCode,
|
|
243
|
+
_frontendMeta: {
|
|
244
|
+
wireframes: allLinkedWireframes,
|
|
245
|
+
linkedUCs: allLinkedUCs,
|
|
246
|
+
filesToCreate: frontendFiles
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
lastIdByCategory["frontend"] = taskId;
|
|
251
|
+
taskId++;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// 1c. Create CONSOLIDATED i18n task (ONE task per module)
|
|
255
|
+
if (i18nFiles.length > 0) {
|
|
256
|
+
tasks.push({
|
|
257
|
+
id: taskId,
|
|
258
|
+
description: `[i18n] Generate i18n translations for module ${moduleCode} (4 languages: fr, en, it, de)`,
|
|
259
|
+
status: "pending",
|
|
260
|
+
category: "i18n",
|
|
261
|
+
dependencies: lastIdByCategory["frontend"] ? [lastIdByCategory["frontend"]] : [],
|
|
262
|
+
acceptance_criteria: "4 JSON files (fr, en, it, de) with identical keys; all UI labels translated",
|
|
263
|
+
started_at: null,
|
|
264
|
+
completed_at: null,
|
|
265
|
+
iteration: null,
|
|
266
|
+
commit_hash: null,
|
|
267
|
+
files_changed: { created: i18nFiles.map(f => f.path), modified: [] },
|
|
268
|
+
validation: null,
|
|
269
|
+
error: null,
|
|
270
|
+
module: moduleCode
|
|
271
|
+
});
|
|
272
|
+
lastIdByCategory["i18n"] = taskId;
|
|
273
|
+
taskId++;
|
|
274
|
+
}
|
|
275
|
+
|
|
134
276
|
// 2. Add IClientSeedDataProvider task for client projects (ExtensionsDbContext)
|
|
135
277
|
// This is MANDATORY - without it, core seed data (navigation, permissions, roles) is dead code
|
|
136
278
|
const hasClientSeedData = filesToCreate["seedData"]?.some(f =>
|