@atlashub/smartstack-cli 3.16.0 → 3.18.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 +74 -42
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +752 -53
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/agents/gitflow/finish.md +21 -3
- package/templates/agents/gitflow/start.md +14 -4
- package/templates/skills/application/templates-backend.md +12 -1
- package/templates/skills/business-analyse/SKILL.md +4 -4
- package/templates/skills/business-analyse/html/ba-interactive.html +11 -5
- package/templates/skills/business-analyse/html/src/scripts/05-render-specs.js +11 -5
- package/templates/skills/business-analyse/references/deploy-data-build.md +25 -9
- package/templates/skills/business-analyse/references/validation-checklist.md +29 -2
- package/templates/skills/business-analyse/steps/step-00-init.md +23 -5
- package/templates/skills/business-analyse/steps/step-03a2-analysis.md +21 -3
- package/templates/skills/business-analyse/steps/step-03b-ui.md +31 -1
- package/templates/skills/business-analyse/steps/step-03d-validate.md +41 -4
- package/templates/skills/business-analyse/steps/step-05b-deploy.md +9 -7
- package/templates/skills/business-analyse/steps/step-05c-ralph-readiness.md +222 -40
- package/templates/skills/ralph-loop/SKILL.md +41 -1
- package/templates/skills/ralph-loop/references/category-rules.md +106 -1
- package/templates/skills/ralph-loop/references/compact-loop.md +85 -24
- package/templates/skills/ralph-loop/references/core-seed-data.md +48 -0
- package/templates/skills/ralph-loop/steps/step-00-init.md +30 -54
- package/templates/skills/ralph-loop/steps/step-01-task.md +102 -1
- package/templates/skills/ralph-loop/steps/step-04-check.md +87 -40
package/package.json
CHANGED
|
@@ -77,10 +77,26 @@ git fetch origin develop:refs/remotes/origin/develop --force --quiet
|
|
|
77
77
|
|
|
78
78
|
### 4. Version Bump (Release/Hotfix)
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
After merge-back to develop, invoke `/version-bump` to set the next development version:
|
|
81
|
+
|
|
82
|
+
| Finished type | Next version | Example |
|
|
83
|
+
|---------------|-------------|---------|
|
|
84
|
+
| Release X.Y.Z | X.(Y+1).0 | 2.8.0 → 2.9.0 |
|
|
85
|
+
| Hotfix X.Y.Z | X.Y.(Z+1) | 2.8.1 → 2.8.2 |
|
|
86
|
+
|
|
81
87
|
```bash
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
# Calculate NEXT_VERSION from the released version
|
|
89
|
+
# Then call: /version-bump $NEXT_VERSION
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This updates **all** version sources in sync:
|
|
93
|
+
- `Directory.Build.props` → `<VersionPrefix>X.Y.Z</VersionPrefix>`
|
|
94
|
+
- `web/smartstack-web/package.json` → `"version": "X.Y.Z"`
|
|
95
|
+
- `.claude/gitflow/config.json` → `versioning.current`
|
|
96
|
+
|
|
97
|
+
Then commit and push:
|
|
98
|
+
```bash
|
|
99
|
+
git add Directory.Build.props web/smartstack-web/package.json .claude/gitflow/config.json
|
|
84
100
|
git commit -m "$(cat <<'EOF'
|
|
85
101
|
chore: bump version to $NEXT_VERSION for development
|
|
86
102
|
|
|
@@ -90,6 +106,8 @@ EOF
|
|
|
90
106
|
git push origin develop
|
|
91
107
|
```
|
|
92
108
|
|
|
109
|
+
> **IMPORTANT**: Do NOT use `npm version` directly. Always use `/version-bump` for unified versioning.
|
|
110
|
+
|
|
93
111
|
### 5. Cleanup Worktree + Branch
|
|
94
112
|
|
|
95
113
|
```bash
|
|
@@ -75,14 +75,24 @@ git fetch origin $FULL_BRANCH:refs/remotes/origin/$FULL_BRANCH --force --quiet
|
|
|
75
75
|
|
|
76
76
|
**Port allocation:** Hash branch name for unique ports (API: 5200+, Web: 5300+)
|
|
77
77
|
|
|
78
|
-
### 7. Version Bump (Release only)
|
|
78
|
+
### 7. Version Bump (Release/Hotfix only)
|
|
79
|
+
|
|
80
|
+
For `release/*` and `hotfix/*` branches, invoke the `/version-bump` skill to synchronize all version files:
|
|
79
81
|
|
|
80
82
|
```bash
|
|
81
|
-
#
|
|
82
|
-
|
|
83
|
-
# OR update .csproj <Version> tag
|
|
83
|
+
# Extract version from branch name: release/2.8.0 → 2.8.0, hotfix/2.8.1 → 2.8.1
|
|
84
|
+
VERSION=$(echo "$FULL_BRANCH" | sed 's|^[^/]*/||')
|
|
84
85
|
```
|
|
85
86
|
|
|
87
|
+
Then call: `/version-bump $VERSION`
|
|
88
|
+
|
|
89
|
+
This updates **all** version sources in sync:
|
|
90
|
+
- `Directory.Build.props` → `<VersionPrefix>X.Y.Z</VersionPrefix>`
|
|
91
|
+
- `web/smartstack-web/package.json` → `"version": "X.Y.Z"`
|
|
92
|
+
- `.claude/gitflow/config.json` → `versioning.current`
|
|
93
|
+
|
|
94
|
+
> **IMPORTANT**: Do NOT use `npm version` or edit `.csproj` directly. Always use `/version-bump` for unified versioning.
|
|
95
|
+
|
|
86
96
|
### 8. Summary
|
|
87
97
|
|
|
88
98
|
```
|
|
@@ -82,6 +82,12 @@ public interface I$MODULE_PASCALService
|
|
|
82
82
|
|
|
83
83
|
## TEMPLATE: SERVICE IMPLEMENTATION
|
|
84
84
|
|
|
85
|
+
> **TENANT ISOLATION RULES (BLOCKING):**
|
|
86
|
+
> - ALL queries MUST include `.Where(x => x.TenantId == _currentUser.TenantId)`
|
|
87
|
+
> - ALL entity creation MUST pass `_currentUser.TenantId` as first parameter to `Entity.Create()`
|
|
88
|
+
> - NEVER use `new Entity { }` without `TenantId =` — always prefer the factory method
|
|
89
|
+
> - NEVER use `Guid.Empty` as a placeholder — resolve the actual value from `_currentUser`
|
|
90
|
+
|
|
85
91
|
```csharp
|
|
86
92
|
// src/SmartStack.Infrastructure/Services/$CONTEXT_PASCAL/$APPLICATION_PASCAL/$MODULE_PASCAL/$MODULE_PASCALService.cs
|
|
87
93
|
|
|
@@ -114,7 +120,8 @@ public class $MODULE_PASCALService : I$MODULE_PASCALService
|
|
|
114
120
|
CancellationToken cancellationToken = default)
|
|
115
121
|
{
|
|
116
122
|
var query = _context.$ENTITY_PLURAL
|
|
117
|
-
.AsNoTracking()
|
|
123
|
+
.AsNoTracking()
|
|
124
|
+
.Where(x => x.TenantId == _currentUser.TenantId); // MANDATORY: tenant isolation
|
|
118
125
|
|
|
119
126
|
// Apply filters
|
|
120
127
|
if (!string.IsNullOrWhiteSpace(parameters.SearchTerm))
|
|
@@ -167,6 +174,7 @@ public class $MODULE_PASCALService : I$MODULE_PASCALService
|
|
|
167
174
|
{
|
|
168
175
|
var entity = await _context.$ENTITY_PLURAL
|
|
169
176
|
.AsNoTracking()
|
|
177
|
+
.Where(x => x.TenantId == _currentUser.TenantId) // MANDATORY: tenant isolation
|
|
170
178
|
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
|
171
179
|
|
|
172
180
|
if (entity == null)
|
|
@@ -188,6 +196,7 @@ public class $MODULE_PASCALService : I$MODULE_PASCALService
|
|
|
188
196
|
CancellationToken cancellationToken = default)
|
|
189
197
|
{
|
|
190
198
|
var entity = $ENTITY_PASCAL.Create(
|
|
199
|
+
_currentUser.TenantId, // MANDATORY: tenant isolation — always first parameter
|
|
191
200
|
request.Name,
|
|
192
201
|
request.Description);
|
|
193
202
|
|
|
@@ -216,6 +225,7 @@ public class $MODULE_PASCALService : I$MODULE_PASCALService
|
|
|
216
225
|
CancellationToken cancellationToken = default)
|
|
217
226
|
{
|
|
218
227
|
var entity = await _context.$ENTITY_PLURAL
|
|
228
|
+
.Where(x => x.TenantId == _currentUser.TenantId) // MANDATORY: tenant isolation
|
|
219
229
|
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken)
|
|
220
230
|
?? throw new NotFoundException("$ENTITY_PASCAL", id);
|
|
221
231
|
|
|
@@ -245,6 +255,7 @@ public class $MODULE_PASCALService : I$MODULE_PASCALService
|
|
|
245
255
|
CancellationToken cancellationToken = default)
|
|
246
256
|
{
|
|
247
257
|
var entity = await _context.$ENTITY_PLURAL
|
|
258
|
+
.Where(x => x.TenantId == _currentUser.TenantId) // MANDATORY: tenant isolation
|
|
248
259
|
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
|
249
260
|
|
|
250
261
|
if (entity == null)
|
|
@@ -209,7 +209,7 @@ When step-00 detects that the description matches an existing application:
|
|
|
209
209
|
| 04c | `steps/step-04c-decide.md` | Opus | Final approval, write consolidation, proceed to handoff |
|
|
210
210
|
| 05a | `steps/step-05a-handoff.md` | Sonnet | Handoff: file mapping (7 categories), BR-to-code mapping, API summary, write handoff |
|
|
211
211
|
| 05b | `steps/step-05b-deploy.md` | Sonnet | Deploy: prd.json, progress.txt, manifest, ba-interactive.html |
|
|
212
|
-
| 05c | `steps/step-05c-ralph-readiness.md` |
|
|
212
|
+
| 05c | `steps/step-05c-ralph-readiness.md` | Opus | ULTRATHINK quality review + ralph readiness gate (MANDATORY) |
|
|
213
213
|
| 06 | `steps/step-06-review.md` | Opus | Apply review corrections, create new version, regenerate all artifacts |
|
|
214
214
|
|
|
215
215
|
</step_files>
|
|
@@ -252,10 +252,10 @@ Load ONLY relevant categories based on feature type:
|
|
|
252
252
|
| -------- | ----------------------------------- | ------------ |
|
|
253
253
|
| schema | `schemas/feature-schema.json` | All steps |
|
|
254
254
|
| spec | `templates/tpl-frd.md` | 02 |
|
|
255
|
-
| handoff | `templates/tpl-handoff.md` |
|
|
255
|
+
| handoff | `templates/tpl-handoff.md` | 05a |
|
|
256
256
|
| suggestions | `patterns/suggestion-catalog.md` | 01 |
|
|
257
|
-
| interactive | `html/ba-interactive.html` | 03d (incremental),
|
|
258
|
-
| mapping | `references/html-data-mapping.md` | 03d,
|
|
257
|
+
| interactive | `html/ba-interactive.html` | 03d (incremental), 05b (final deploy) |
|
|
258
|
+
| mapping | `references/html-data-mapping.md` | 03d, 05b (FEATURE_DATA + EMBEDDED_ARTIFACTS mapping) |
|
|
259
259
|
|
|
260
260
|
</template_files>
|
|
261
261
|
|
|
@@ -3074,20 +3074,26 @@ function renderModuleMockups(code) {
|
|
|
3074
3074
|
</div>` : ''}
|
|
3075
3075
|
${(wf.elements || []).length > 0 ? `
|
|
3076
3076
|
<div class="wireframe-metadata">
|
|
3077
|
-
<div><strong>Elements:</strong> ${wf.elements.join(', ')}</div>
|
|
3077
|
+
<div><strong>Elements:</strong> ${wf.elements.map(e => typeof e === 'string' ? e : (e.type || e.label || e.id || '')).filter(Boolean).join(', ')}</div>
|
|
3078
3078
|
</div>` : ''}
|
|
3079
|
-
${(
|
|
3079
|
+
${(() => {
|
|
3080
|
+
const cm = wf.componentMapping;
|
|
3081
|
+
const mappings = Array.isArray(cm) ? cm
|
|
3082
|
+
: (typeof cm === 'object' && cm !== null) ? Object.entries(cm).map(([k,v]) => ({wireframeElement: k, reactComponent: v}))
|
|
3083
|
+
: [];
|
|
3084
|
+
return mappings.length > 0 ? `
|
|
3080
3085
|
<details class="wireframe-details">
|
|
3081
3086
|
<summary>Mapping composants SmartStack</summary>
|
|
3082
3087
|
<table class="mapping-table">
|
|
3083
3088
|
<thead><tr><th>Element maquette</th><th>Composant React</th></tr></thead>
|
|
3084
3089
|
<tbody>
|
|
3085
|
-
${
|
|
3086
|
-
|
|
3090
|
+
${mappings.map(m =>
|
|
3091
|
+
'<tr><td>' + (m.wireframeElement || '') + '</td><td><code>' + (m.reactComponent || '') + '</code></td></tr>'
|
|
3087
3092
|
).join('')}
|
|
3088
3093
|
</tbody>
|
|
3089
3094
|
</table>
|
|
3090
|
-
</details>` : ''
|
|
3095
|
+
</details>` : '';
|
|
3096
|
+
})()}
|
|
3091
3097
|
<div class="wireframe-comment">
|
|
3092
3098
|
<label style="font-size:0.8rem;color:var(--text-muted);display:block;margin-bottom:0.3rem;">Commentaire / Feedback :</label>
|
|
3093
3099
|
<textarea class="form-textarea"
|
|
@@ -392,20 +392,26 @@ function renderModuleMockups(code) {
|
|
|
392
392
|
</div>` : ''}
|
|
393
393
|
${(wf.elements || []).length > 0 ? `
|
|
394
394
|
<div class="wireframe-metadata">
|
|
395
|
-
<div><strong>Elements:</strong> ${wf.elements.join(', ')}</div>
|
|
395
|
+
<div><strong>Elements:</strong> ${wf.elements.map(e => typeof e === 'string' ? e : (e.type || e.label || e.id || '')).filter(Boolean).join(', ')}</div>
|
|
396
396
|
</div>` : ''}
|
|
397
|
-
${(
|
|
397
|
+
${(() => {
|
|
398
|
+
const cm = wf.componentMapping;
|
|
399
|
+
const mappings = Array.isArray(cm) ? cm
|
|
400
|
+
: (typeof cm === 'object' && cm !== null) ? Object.entries(cm).map(([k,v]) => ({wireframeElement: k, reactComponent: v}))
|
|
401
|
+
: [];
|
|
402
|
+
return mappings.length > 0 ? `
|
|
398
403
|
<details class="wireframe-details">
|
|
399
404
|
<summary>Mapping composants SmartStack</summary>
|
|
400
405
|
<table class="mapping-table">
|
|
401
406
|
<thead><tr><th>Element maquette</th><th>Composant React</th></tr></thead>
|
|
402
407
|
<tbody>
|
|
403
|
-
${
|
|
404
|
-
|
|
408
|
+
${mappings.map(m =>
|
|
409
|
+
'<tr><td>' + (m.wireframeElement || '') + '</td><td><code>' + (m.reactComponent || '') + '</code></td></tr>'
|
|
405
410
|
).join('')}
|
|
406
411
|
</tbody>
|
|
407
412
|
</table>
|
|
408
|
-
</details>` : ''
|
|
413
|
+
</details>` : '';
|
|
414
|
+
})()}
|
|
409
415
|
<div class="wireframe-comment">
|
|
410
416
|
<label style="font-size:0.8rem;color:var(--text-muted);display:block;margin-bottom:0.3rem;">Commentaire / Feedback :</label>
|
|
411
417
|
<textarea class="form-textarea"
|
|
@@ -42,7 +42,19 @@ const FEATURE_DATA = {
|
|
|
42
42
|
"{moduleCode}": {
|
|
43
43
|
useCases: module.specification.useCases || [],
|
|
44
44
|
businessRules: module.analysis.businessRules || [],
|
|
45
|
-
|
|
45
|
+
// ENTITY SAFETY NET: map fields[] → attributes[] if agent deviated from canonical format
|
|
46
|
+
entities: (module.analysis.entities || []).map(ent => ({
|
|
47
|
+
name: ent.name,
|
|
48
|
+
description: ent.description || "",
|
|
49
|
+
attributes: (ent.attributes || []).length > 0
|
|
50
|
+
? ent.attributes.map(a => ({ name: a.name, description: a.description || "" }))
|
|
51
|
+
: (ent.fields || []).map(f => ({ name: f.name, description: f.description || f.type || "" })),
|
|
52
|
+
relationships: (ent.relationships || []).length > 0
|
|
53
|
+
? ent.relationships.map(r =>
|
|
54
|
+
typeof r === 'string' ? r : `${r.target} (${r.type}) - ${r.description || ""}`)
|
|
55
|
+
: (ent.fields || []).filter(f => f.foreignKey)
|
|
56
|
+
.map(f => `${f.foreignKey.table} (N:1) - ${f.description || f.name}`)
|
|
57
|
+
})),
|
|
46
58
|
permissions: module.specification.permissions || [],
|
|
47
59
|
apiEndpoints: module.specification.apiEndpoints || []
|
|
48
60
|
}
|
|
@@ -85,15 +97,19 @@ const EMBEDDED_ARTIFACTS = {
|
|
|
85
97
|
// PER-MODULE keyed object (NOT a flat array)
|
|
86
98
|
// FOR EACH module: extract from specification.uiWireframes[]
|
|
87
99
|
[moduleCode]: moduleFeature.specification.uiWireframes.map(wf => ({
|
|
88
|
-
screen: wf.screen
|
|
89
|
-
section: wf.section,
|
|
90
|
-
format: wf.mockupFormat || "ascii",
|
|
91
|
-
content: wf.mockup,
|
|
100
|
+
screen: wf.screen || wf.name || wf.id || "", // SAFETY NET: fallback name/id → screen
|
|
101
|
+
section: wf.section || "", // e.g. "list"
|
|
102
|
+
format: wf.mockupFormat || "ascii", // RENAME: mockupFormat → format
|
|
103
|
+
content: wf.mockup, // RENAME: mockup → content (ASCII art string)
|
|
92
104
|
description: wf.description || "",
|
|
93
|
-
elements: wf.elements || [],
|
|
94
|
-
actions: wf.actions || [],
|
|
95
|
-
|
|
96
|
-
|
|
105
|
+
elements: wf.elements || [], // [{ id, type, label }] or ["DataGrid", ...]
|
|
106
|
+
actions: wf.actions || [], // [{ trigger, action }] or ["filter", ...]
|
|
107
|
+
// SAFETY NET: convert object → array format if agent used { "Header": "PageHeader" } instead of [{ wireframeElement, reactComponent }]
|
|
108
|
+
componentMapping: Array.isArray(wf.componentMapping) ? wf.componentMapping
|
|
109
|
+
: typeof wf.componentMapping === 'object' && wf.componentMapping !== null
|
|
110
|
+
? Object.entries(wf.componentMapping).map(([k, v]) => ({ wireframeElement: k, reactComponent: v }))
|
|
111
|
+
: [],
|
|
112
|
+
layout: typeof wf.layout === 'object' ? wf.layout : null, // SAFETY NET: ignore string layout ("grid")
|
|
97
113
|
permissionsRequired: wf.permissionsRequired || []
|
|
98
114
|
}))
|
|
99
115
|
},
|
|
@@ -32,6 +32,18 @@ const checklist = {
|
|
|
32
32
|
details: "Standalone entities should be rare in business modules"
|
|
33
33
|
},
|
|
34
34
|
|
|
35
|
+
entitySchemaCompliance: {
|
|
36
|
+
check: "All entities use canonical format: attributes[] (not fields[]), relationships[] array present",
|
|
37
|
+
status: specification.entities.every(e =>
|
|
38
|
+
Array.isArray(e.attributes) && e.attributes.length > 0 &&
|
|
39
|
+
!e.fields && !e.tableName && !e.primaryKey
|
|
40
|
+
) ? "PASS" : "FAIL",
|
|
41
|
+
blocking: true,
|
|
42
|
+
details: "Entities with 'fields' instead of 'attributes' break HTML data model display and PRD extraction. " +
|
|
43
|
+
"Check: every entity must have attributes[] (not fields[]), every entity must have relationships[], " +
|
|
44
|
+
"no entity should have tableName or primaryKey (technical fields belong in implementation, not analysis)"
|
|
45
|
+
},
|
|
46
|
+
|
|
35
47
|
// SECTION 2: BUSINESS RULES (BLOCKING)
|
|
36
48
|
businessRules: {
|
|
37
49
|
minimum: 4,
|
|
@@ -133,6 +145,21 @@ const checklist = {
|
|
|
133
145
|
details: "EVERY section MUST have a wireframe (ASCII/SVG)"
|
|
134
146
|
},
|
|
135
147
|
|
|
148
|
+
wireframeSchemaCompliance: {
|
|
149
|
+
check: "All wireframes have required fields: screen, section, mockupFormat, elements[], componentMapping[], layout (object), permissionsRequired[]",
|
|
150
|
+
status: specification.uiWireframes.every(wf =>
|
|
151
|
+
wf.screen && wf.section && wf.mockupFormat &&
|
|
152
|
+
Array.isArray(wf.elements) && wf.elements.length > 0 &&
|
|
153
|
+
Array.isArray(wf.componentMapping) && wf.componentMapping.length > 0 &&
|
|
154
|
+
typeof wf.layout === 'object' && wf.layout !== null &&
|
|
155
|
+
Array.isArray(wf.permissionsRequired)
|
|
156
|
+
) ? "PASS" : "FAIL",
|
|
157
|
+
blocking: true,
|
|
158
|
+
details: "Wireframes missing metadata render as empty frames in HTML documentation. " +
|
|
159
|
+
"Check: screen (not name/id), section, mockupFormat, elements[] non-empty, " +
|
|
160
|
+
"componentMapping[] as array of {wireframeElement, reactComponent}, layout as object (not string)"
|
|
161
|
+
},
|
|
162
|
+
|
|
136
163
|
navigation: {
|
|
137
164
|
check: "Module has ≥1 navigation entry",
|
|
138
165
|
status: specification.navigation.entries.length >= 1 ? "PASS" : "FAIL",
|
|
@@ -261,11 +288,11 @@ ELSE:
|
|
|
261
288
|
|
|
262
289
|
| Category | Checks | Passed | Failed | Warnings |
|
|
263
290
|
|----------|--------|--------|--------|----------|
|
|
264
|
-
| Data Model |
|
|
291
|
+
| Data Model | 4 | {n} | {n} | {n} |
|
|
265
292
|
| Business Rules | 3 | {n} | {n} | {n} |
|
|
266
293
|
| Use Cases & FRs | 4 | {n} | {n} | {n} |
|
|
267
294
|
| Permissions | 3 | {n} | {n} | {n} |
|
|
268
|
-
| UI & Navigation |
|
|
295
|
+
| UI & Navigation | 4 | {n} | {n} | {n} |
|
|
269
296
|
| I18N & Messages | 3 | {n} | {n} | {n} |
|
|
270
297
|
| Seed Data | 2 | {n} | {n} | {n} |
|
|
271
298
|
| API Endpoints | 2 | {n} | {n} | {n} |
|
|
@@ -374,12 +374,30 @@ If initialization was interrupted:
|
|
|
374
374
|
|
|
375
375
|
1. Check `.business-analyse/config.json` for currentFeature
|
|
376
376
|
2. If feature ID exists, search for feature.json in `docs/business/`
|
|
377
|
-
3. If found, check `metadata.workflow.lastCompletedStep`:
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
377
|
+
3. If found, check status and `metadata.workflow.lastCompletedStep`:
|
|
378
|
+
|
|
379
|
+
**Status-based resume routing (check in this order):**
|
|
380
|
+
|
|
381
|
+
- If status = `"handed-off"` AND `ba-interactive.html` missing:
|
|
382
|
+
→ Resume at `step-05b-deploy.md` (deploy artifacts + HTML)
|
|
383
|
+
→ Display: "Handoff complete but HTML/artifacts missing — deploying..."
|
|
384
|
+
|
|
381
385
|
- If status = `"handed-off"` AND `.ralph/prd-*.json` files missing:
|
|
382
386
|
→ Resume at `step-05b-deploy.md` (only deploy artifacts needed)
|
|
383
|
-
→ Display: "Handoff complete but
|
|
387
|
+
→ Display: "Handoff complete but PRD files missing — deploying..."
|
|
388
|
+
|
|
389
|
+
- If status = `"consolidated"` OR lastCompletedStep = `"step-04-consolidation"`:
|
|
390
|
+
→ Resume directly at `step-05a-handoff.md` (skip steps 00-04)
|
|
391
|
+
→ Display: "Resuming from consolidation — proceeding to handoff..."
|
|
392
|
+
|
|
393
|
+
- If status = `"specified"` AND `metadata.workflow.allModulesSpecified === true`:
|
|
394
|
+
→ Resume at `step-04a-collect.md` (consolidation phase)
|
|
395
|
+
→ Display: "All modules specified — resuming at consolidation..."
|
|
396
|
+
|
|
397
|
+
- If status = `"specified"` AND `metadata.workflow.completedModules.length > 0` AND `metadata.workflow.completedModules.length < metadata.workflow.moduleOrder.length`:
|
|
398
|
+
→ Resume at `step-03a1-setup.md` (continue specifying remaining modules)
|
|
399
|
+
→ Display: "Resuming module specification ({completedCount}/{totalCount})..."
|
|
400
|
+
|
|
384
401
|
- Otherwise: offer to resume from last completed step
|
|
402
|
+
|
|
385
403
|
4. If not found, create fresh feature.json
|
|
@@ -60,6 +60,20 @@ Define entities for this module (business attributes, not technical):
|
|
|
60
60
|
> ```
|
|
61
61
|
> **FORBIDDEN fields in attributes:** Do NOT use `type`, `values`, `rules`.
|
|
62
62
|
> Use `description` to explain what the attribute is, `validation` for format/constraint rules, `unique` as boolean.
|
|
63
|
+
>
|
|
64
|
+
> **FORBIDDEN FORMAT — DO NOT USE (technical/database schema):**
|
|
65
|
+
> ```json
|
|
66
|
+
> {
|
|
67
|
+
> "name": "Project",
|
|
68
|
+
> "tableName": "rh_projects",
|
|
69
|
+
> "primaryKey": "id",
|
|
70
|
+
> "fields": [
|
|
71
|
+
> { "name": "code", "type": "UUID", "required": true }
|
|
72
|
+
> ]
|
|
73
|
+
> }
|
|
74
|
+
> ```
|
|
75
|
+
> **Why forbidden:** `tableName`, `primaryKey` are technical fields that do NOT belong in analysis. `fields[]` is NOT recognized by the build pipeline — only `attributes[]` is. `type` with SQL types (UUID, string, timestamp) belongs in implementation, not analysis. Using this format causes **empty entity data in the HTML documentation** and **broken PRD extraction**.
|
|
76
|
+
> The canonical format uses `attributes[]` (not `fields[]`), `relationships[]` (not FK inside fields), and NO technical fields (tableName, primaryKey).
|
|
63
77
|
|
|
64
78
|
#### 6c. Process Flow
|
|
65
79
|
|
|
@@ -130,9 +144,13 @@ Before proceeding to step-03b-ui.md, VERIFY:
|
|
|
130
144
|
|
|
131
145
|
1. **Module feature.json exists** at expected path (`docs/business/{app}/{module}/business-analyse/v{X.Y}/feature.json`)
|
|
132
146
|
2. **Module feature.json has analysis section** with `entities[]` (at least 1) and `businessRules[]` (at least 1)
|
|
133
|
-
3. **
|
|
134
|
-
|
|
135
|
-
|
|
147
|
+
3. **Entity schema compliance (BLOCKING)** — EVERY entity has `attributes[]` (NOT `fields[]`) and `relationships[]` arrays.
|
|
148
|
+
Quick check: `analysis.entities.every(e => Array.isArray(e.attributes) && e.attributes.length >= 1)`
|
|
149
|
+
IF any entity has `fields[]` instead of `attributes[]` → STRUCTURAL ERROR, fix before proceeding.
|
|
150
|
+
IF any entity has `tableName` or `primaryKey` → STRUCTURAL ERROR, these are technical fields that do not belong in analysis.
|
|
151
|
+
4. **Module status in master** = "in-progress" (set by section 2 above)
|
|
152
|
+
5. **Master modules[].featureJsonPath** for this module ≠ null (set by ba-writer.create)
|
|
153
|
+
6. **Sections identified** with clear roles and entities assigned
|
|
136
154
|
|
|
137
155
|
**IF any check fails → FIX before proceeding.** Do NOT load step-03b-ui with incomplete data.
|
|
138
156
|
|
|
@@ -167,9 +167,36 @@ Example for a list section:
|
|
|
167
167
|
Store in specification.uiWireframes[] (**MANDATORY** for every section):
|
|
168
168
|
|
|
169
169
|
See [references/ui-resource-cards.md](../references/ui-resource-cards.md) for exact JSON format of `specification.uiWireframes[]`.
|
|
170
|
-
**REQUIRED fields:** `screen`, `mockup`, `elements`, `section`, `componentMapping`, `layout` are ALL mandatory.
|
|
170
|
+
**REQUIRED fields:** `screen`, `mockup`, `mockupFormat`, `elements`, `section`, `actions`, `componentMapping`, `layout`, `permissionsRequired` are ALL mandatory.
|
|
171
171
|
A wireframe without `componentMapping` or `layout` will FAIL validation in step 9.
|
|
172
172
|
|
|
173
|
+
> **STRUCTURE CARD: specification.uiWireframes[]** — ALL fields are MANDATORY. Do NOT omit any.
|
|
174
|
+
> ```json
|
|
175
|
+
> {
|
|
176
|
+
> "screen": "{module}-{section}", // MANDATORY — unique screen ID (NOT "name" or "id")
|
|
177
|
+
> "section": "list|detail|create|approve|...", // MANDATORY — section code
|
|
178
|
+
> "description": "Description en français",
|
|
179
|
+
> "mockupFormat": "ascii", // MANDATORY — "ascii" or "svg"
|
|
180
|
+
> "mockup": "┌───...┘", // MANDATORY — ASCII art string
|
|
181
|
+
> "elements": [ // MANDATORY — array of element objects
|
|
182
|
+
> { "id": "elem-grid", "type": "SmartTable", "label": "Grille" }
|
|
183
|
+
> ],
|
|
184
|
+
> "actions": [ // MANDATORY — user interactions
|
|
185
|
+
> { "trigger": "Click row", "action": "Navigate to detail" }
|
|
186
|
+
> ],
|
|
187
|
+
> "componentMapping": [ // MANDATORY — array of mapping objects
|
|
188
|
+
> { "wireframeElement": "DataGrid", "reactComponent": "SmartTable" }
|
|
189
|
+
> ],
|
|
190
|
+
> "layout": { // MANDATORY — object with regions (NOT a string)
|
|
191
|
+
> "type": "page",
|
|
192
|
+
> "regions": [{ "id": "main", "position": "main", "span": 12, "components": [...] }]
|
|
193
|
+
> },
|
|
194
|
+
> "permissionsRequired": ["read"] // MANDATORY — required permissions
|
|
195
|
+
> }
|
|
196
|
+
> ```
|
|
197
|
+
> **FORBIDDEN FORMAT:** wireframe with only `name` + `mockup` + `layout: "grid"` (string).
|
|
198
|
+
> Every wireframe MUST have ALL fields above. Missing metadata causes empty frames in the HTML documentation.
|
|
199
|
+
|
|
173
200
|
> **IF client rejects a mockup:** Revise and re-propose until validated. Do NOT proceed without client approval on the layout.
|
|
174
201
|
|
|
175
202
|
### 3b-bis. Wireframe-to-Component Mapping
|
|
@@ -250,6 +277,9 @@ Before proceeding to step-03c-compile.md, VERIFY:
|
|
|
250
277
|
6. **State machines defined** (if module has status fields) in `specification.lifeCycles[]`
|
|
251
278
|
7. **Form field completeness** — SmartForm fields[] covers ALL entity attributes except system/audit fields
|
|
252
279
|
8. **Navigation entries for all sections** — Every section (including dashboard) has a corresponding entry in `specification.navigation.entries[]`
|
|
280
|
+
9. **Wireframe structural compliance (BLOCKING)** — ALL wireframes have: `screen` (not just `name`), `section`, `mockupFormat`, `elements[]` (non-empty array of objects), `actions[]`, `componentMapping[]` (array of {wireframeElement, reactComponent}), `layout` (object with regions, NOT a string), `permissionsRequired[]`
|
|
281
|
+
Quick check: `uiWireframes.every(wf => wf.screen && wf.section && wf.mockupFormat && Array.isArray(wf.elements) && wf.elements.length > 0 && typeof wf.layout === 'object' && wf.layout !== null)`
|
|
282
|
+
IF any wireframe fails → FIX before proceeding. DO NOT load step-03c with degraded wireframes.
|
|
253
283
|
|
|
254
284
|
**IF any check fails → FIX before proceeding.** Do NOT load step-03c-compile with incomplete data.
|
|
255
285
|
|
|
@@ -41,7 +41,9 @@ Validate the module specification for completeness and consistency, write to fea
|
|
|
41
41
|
| functionalRequirements | 4 | PASS/FAIL |
|
|
42
42
|
| permissionMatrix | 1 resource × 2 roles | PASS/FAIL |
|
|
43
43
|
| entities | 1 | PASS/FAIL |
|
|
44
|
+
| entitySchemaFormat | attributes[] not fields[] (BLOCKING) | PASS/FAIL |
|
|
44
45
|
| wireframes | 1 per section (BLOCKING) | PASS/FAIL |
|
|
46
|
+
| wireframeSchema | All required fields present (BLOCKING) | PASS/FAIL |
|
|
45
47
|
| gherkinScenarios | 2 per UC | PASS/FAIL |
|
|
46
48
|
| validations | 1 | PASS/FAIL |
|
|
47
49
|
| messages | 4 | PASS/FAIL |
|
|
@@ -65,6 +67,8 @@ Validate the module specification for completeness and consistency, write to fea
|
|
|
65
67
|
- BR-{CATEGORY}-NNN format
|
|
66
68
|
- Entity names PascalCase
|
|
67
69
|
- Field names camelCase
|
|
70
|
+
- Entity attribute format: `attributes[]` with {name, description}, NOT `fields[]` with {name, type} — entities must NOT have tableName or primaryKey
|
|
71
|
+
- Wireframe structure: `screen` (not `name`), `componentMapping` is array of {wireframeElement, reactComponent} (not plain key-value object), `layout` is object with regions (not string)
|
|
68
72
|
- Permission paths dot-separated lowercase
|
|
69
73
|
|
|
70
74
|
#### 9d. Decision
|
|
@@ -132,9 +136,9 @@ ba-writer.enrichSection({
|
|
|
132
136
|
|
|
133
137
|
**Execute the comprehensive validation checklist:**
|
|
134
138
|
|
|
135
|
-
Run the
|
|
136
|
-
- Data Model (
|
|
137
|
-
- Permissions (3 checks) | UI & Navigation (
|
|
139
|
+
Run the 27-check validation process across 10 categories:
|
|
140
|
+
- Data Model (4 checks) | Business Rules (3 checks) | Use Cases & FRs (4 checks)
|
|
141
|
+
- Permissions (3 checks) | UI & Navigation (4 checks) | I18N & Messages (3 checks)
|
|
138
142
|
- Seed Data (2 checks) | API Endpoints (2 checks) | Validations (1 check) | Gherkin (1 check)
|
|
139
143
|
|
|
140
144
|
```javascript
|
|
@@ -161,6 +165,24 @@ ELSE:
|
|
|
161
165
|
|
|
162
166
|
---
|
|
163
167
|
|
|
168
|
+
### 9g. Anti-Premature-Completion Guard (MANDATORY)
|
|
169
|
+
|
|
170
|
+
> **CRITICAL — NEVER say "the analysis is complete" or "ready for /ralph-loop" at this point.**
|
|
171
|
+
> Step-03d is the END of SPECIFICATION, NOT the end of the BA workflow.
|
|
172
|
+
> Steps 04a → 04b → 04c (consolidation) + 05a → 05b → 05c (handoff) are STILL REQUIRED.
|
|
173
|
+
> Without handoff, /ralph-loop will generate an INCOMPLETE PRD (no frontend, no tests).
|
|
174
|
+
|
|
175
|
+
**FORBIDDEN phrases in step-03d output:**
|
|
176
|
+
- "L'analyse métier est complète" / "The business analysis is complete"
|
|
177
|
+
- "Prêt pour /ralph-loop" / "Ready for /ralph-loop"
|
|
178
|
+
- "Vous pouvez maintenant lancer /ralph-loop"
|
|
179
|
+
- Any variation suggesting the BA is finished or /ralph-loop can be invoked
|
|
180
|
+
|
|
181
|
+
**REQUIRED phrasing:**
|
|
182
|
+
- "Module {name} spécifié. {Remaining} modules restants." (if more modules)
|
|
183
|
+
- "Tous les modules spécifiés. Passage à la consolidation (étapes 04a-04c)..." (if last module)
|
|
184
|
+
- NEVER mention /ralph-loop — only step-05c (ralph readiness) validates the handoff
|
|
185
|
+
|
|
164
186
|
### 10. Module Summary with Roles & Permissions
|
|
165
187
|
|
|
166
188
|
Display comprehensive summary:
|
|
@@ -282,8 +304,23 @@ IF currentModuleIndex < moduleOrder.length:
|
|
|
282
304
|
Load: steps/step-03a1-setup.md
|
|
283
305
|
|
|
284
306
|
IF currentModuleIndex >= moduleOrder.length:
|
|
285
|
-
Display: "═══ Tous les modules spécifiés! Passage à la consolidation... ═══"
|
|
307
|
+
Display: "═══ Tous les modules spécifiés! Passage à la consolidation (04a→04c) puis handoff (05a→05c)... ═══"
|
|
308
|
+
Display: "⚠ NE PAS lancer /ralph-loop — la consolidation et le handoff sont encore nécessaires."
|
|
286
309
|
ba-writer.updateStatus({feature_id}, "specified")
|
|
310
|
+
|
|
311
|
+
// CHECKPOINT: Save progress BEFORE transition (protects against context exhaustion)
|
|
312
|
+
ba-writer.enrichSection({
|
|
313
|
+
featureId: {feature_id},
|
|
314
|
+
section: "metadata.workflow",
|
|
315
|
+
data: {
|
|
316
|
+
lastCompletedStep: "step-03d-validate",
|
|
317
|
+
allModulesSpecified: true
|
|
318
|
+
}
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
// MANDATORY TRANSITION — DO NOT STOP HERE
|
|
322
|
+
// If context is near exhaustion, the checkpoint above ensures the user
|
|
323
|
+
// can resume with /business-analyse and it will route to step-04a automatically.
|
|
287
324
|
Load: steps/step-04a-collect.md
|
|
288
325
|
```
|
|
289
326
|
|
|
@@ -360,10 +360,9 @@ Effort: {total_days} days ({total_hours} hours)
|
|
|
360
360
|
1. Ouvrir ba-interactive.html dans le navigateur
|
|
361
361
|
2. Partager avec les stakeholders pour validation
|
|
362
362
|
3. Si retours --> relancer /business-analyse pour une nouvelle itération
|
|
363
|
-
4. Validation
|
|
363
|
+
4. Validation qualité ULTRATHINK (automatique):
|
|
364
364
|
|
|
365
|
-
|
|
366
|
-
la complétude et l'intégrité avant développement
|
|
365
|
+
→ Lancement automatique de step-05c-ralph-readiness.md...
|
|
367
366
|
|
|
368
367
|
5. Une fois validé, lancer le développement:
|
|
369
368
|
|
|
@@ -376,16 +375,19 @@ Effort: {total_days} days ({total_hours} hours)
|
|
|
376
375
|
|
|
377
376
|
## NEXT STEP
|
|
378
377
|
|
|
379
|
-
**
|
|
378
|
+
**MANDATORY:** Load `steps/step-05c-ralph-readiness.md` — ULTRATHINK quality review & readiness gate.
|
|
379
|
+
|
|
380
|
+
> **This step is NON-NEGOTIABLE.** The BA skill MUST run step-05c before completing.
|
|
381
|
+
> DO NOT skip this step. DO NOT display a "done" message without running step-05c first.
|
|
380
382
|
|
|
381
383
|
This validation ensures:
|
|
382
|
-
-
|
|
384
|
+
- ULTRATHINK deep quality review of the entire BA output
|
|
385
|
+
- All module handoffs are complete and content is coherent
|
|
383
386
|
- PRD files are structurally valid
|
|
384
387
|
- Cross-module references are resolvable
|
|
388
|
+
- Specification quality meets production standards
|
|
385
389
|
- No blocking issues before development
|
|
386
390
|
|
|
387
|
-
User can skip validation and proceed directly to /ralph-loop, but validation is strongly recommended to catch issues early.
|
|
388
|
-
|
|
389
391
|
---
|
|
390
392
|
|
|
391
393
|
## MODE SUPPORT & TROUBLESHOOTING
|