@atlashub/smartstack-cli 3.33.0 → 3.35.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 +5 -1
- package/.documentation/apex.html +644 -0
- package/.documentation/business-analyse.html +81 -1
- package/.documentation/cli-commands.html +5 -1
- package/.documentation/commands.html +5 -1
- package/.documentation/efcore.html +5 -1
- package/.documentation/gitflow.html +5 -1
- package/.documentation/hooks.html +5 -1
- package/.documentation/index.html +60 -2
- package/.documentation/init.html +414 -1
- package/.documentation/installation.html +5 -1
- package/.documentation/ralph-loop.html +365 -216
- package/.documentation/test-web.html +5 -1
- package/dist/index.js +32 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +7 -24
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -2
- package/templates/agents/ba-writer.md +142 -15
- package/templates/mcp-scaffolding/controller.cs.hbs +5 -1
- package/templates/skills/apex/SKILL.md +9 -3
- package/templates/skills/apex/_shared.md +49 -4
- package/templates/skills/{ralph-loop → apex}/references/core-seed-data.md +20 -11
- package/templates/skills/{ralph-loop → apex}/references/error-classification.md +2 -1
- package/templates/skills/apex/references/post-checks.md +463 -3
- package/templates/skills/apex/references/smartstack-api.md +76 -8
- package/templates/skills/apex/references/smartstack-frontend.md +74 -1
- package/templates/skills/apex/references/smartstack-layers.md +21 -3
- package/templates/skills/apex/steps/step-00-init.md +121 -1
- package/templates/skills/apex/steps/step-01-analyze.md +58 -0
- package/templates/skills/apex/steps/step-02-plan.md +36 -0
- package/templates/skills/apex/steps/step-03-execute.md +114 -7
- package/templates/skills/apex/steps/step-04-examine.md +116 -2
- package/templates/skills/business-analyse/SKILL.md +31 -20
- package/templates/skills/business-analyse/_module-loop.md +68 -9
- package/templates/skills/business-analyse/_shared.md +80 -21
- package/templates/skills/business-analyse/questionnaire/00-application.md +4 -2
- package/templates/skills/business-analyse/questionnaire/00b-project.md +85 -0
- package/templates/skills/business-analyse/references/deploy-modes.md +69 -0
- package/templates/skills/business-analyse/references/team-orchestration.md +158 -7
- package/templates/skills/business-analyse/schemas/application-schema.json +15 -1
- package/templates/skills/business-analyse/schemas/project-schema.json +490 -0
- package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +2 -1
- package/templates/skills/business-analyse/steps/step-00-init.md +220 -38
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +184 -5
- package/templates/skills/business-analyse/steps/step-01b-applications.md +423 -0
- package/templates/skills/business-analyse/steps/step-02-decomposition.md +23 -6
- package/templates/skills/business-analyse/steps/step-03c-compile.md +14 -2
- package/templates/skills/business-analyse/steps/step-03d-validate.md +32 -7
- package/templates/skills/business-analyse/steps/step-04a-collect.md +111 -0
- package/templates/skills/business-analyse/steps/step-05a-handoff.md +296 -103
- package/templates/skills/business-analyse/steps/step-05b-deploy.md +46 -14
- package/templates/skills/documentation/SKILL.md +92 -2
- package/templates/skills/ralph-loop/SKILL.md +14 -17
- package/templates/skills/ralph-loop/references/category-rules.md +63 -683
- package/templates/skills/ralph-loop/references/compact-loop.md +188 -428
- package/templates/skills/ralph-loop/references/section-splitting.md +439 -0
- package/templates/skills/ralph-loop/references/team-orchestration.md +13 -14
- package/templates/skills/ralph-loop/steps/step-01-task.md +27 -0
- package/templates/skills/ralph-loop/steps/step-02-execute.md +80 -691
- package/templates/skills/ralph-loop/steps/step-03-commit.md +38 -79
- package/templates/skills/ralph-loop/steps/step-04-check.md +39 -58
- package/templates/skills/ralph-loop/steps/step-05-report.md +31 -123
- package/scripts/health-check.sh +0 -168
- package/scripts/postinstall.js +0 -18
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: step-01b-applications
|
|
3
|
+
description: Application identity confirmation (single-app) or full application decomposition (multi-app)
|
|
4
|
+
model: opus
|
|
5
|
+
next_step: steps/step-02-decomposition.md
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
> **Context files:** `_shared.md`
|
|
9
|
+
|
|
10
|
+
# Step 1b: Application Identity & Decomposition
|
|
11
|
+
|
|
12
|
+
## MANDATORY EXECUTION RULES
|
|
13
|
+
|
|
14
|
+
- ALWAYS use ULTRATHINK mode
|
|
15
|
+
- ALL communication in `{language}`
|
|
16
|
+
- This step ALWAYS runs. It has two modes:
|
|
17
|
+
- **Single-app mode** (`workflow.mode !== "project"`): Lightweight application identity confirmation — name, code, context, route, icon, table prefix validation, application roles recap. Creates the `seedDataCore.navigationApplications` entry.
|
|
18
|
+
- **Multi-app mode** (`workflow.mode === "project"`): Full application decomposition as defined in sections 1-7 below.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## MODE GATE
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
IF workflow.mode === "project":
|
|
26
|
+
→ Execute FULL multi-app flow (sections 1-7 below)
|
|
27
|
+
ELSE:
|
|
28
|
+
→ Execute LIGHTWEIGHT single-app identity (sections 0a-0f below)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## SINGLE-APP PATH (sections 0a-0f)
|
|
34
|
+
|
|
35
|
+
> This path runs when `workflow.mode !== "project"` (single application, most common case).
|
|
36
|
+
> It confirms the application-level identity (Level 2 of the navigation hierarchy) before proceeding to module decomposition.
|
|
37
|
+
|
|
38
|
+
### 0a. Read Application Context
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
appFeature = ba-reader.findFeature({feature_id})
|
|
42
|
+
→ Read metadata: application, context, tablePrefix
|
|
43
|
+
→ Read cadrage: applicationRoles, coverageMatrix, globalScope
|
|
44
|
+
→ Read cadrage.codebaseContext (if exists)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 0b. Derive Application Identity
|
|
48
|
+
|
|
49
|
+
From the cadrage data, derive the formal application identity:
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
applicationCode = toPascalCase(metadata.application) // e.g., "HumanResources"
|
|
53
|
+
applicationLabel = metadata.application // e.g., "Ressources Humaines" (human-readable)
|
|
54
|
+
context = metadata.context // "business" (validated in step-00)
|
|
55
|
+
applicationRoute = `/${context}/${toKebabCase(applicationCode)}` // e.g., "/business/human-resources"
|
|
56
|
+
applicationIcon = suggestIconFromDomain(applicationCode) // e.g., "users" for HR, "shopping-cart" for Sales
|
|
57
|
+
tablePrefix = metadata.tablePrefix // e.g., "rh_" (already defined in step-01)
|
|
58
|
+
sort = 1 // First (and only) application
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Icon suggestion heuristics:**
|
|
62
|
+
| Domain pattern | Suggested icon |
|
|
63
|
+
|---------------|---------------|
|
|
64
|
+
| HR, Employee, Staff, Personnel | `users` |
|
|
65
|
+
| Sales, Commerce, Revenue | `shopping-cart` |
|
|
66
|
+
| Finance, Accounting, Budget | `wallet` |
|
|
67
|
+
| Inventory, Stock, Warehouse | `package` |
|
|
68
|
+
| CRM, Customer, Client | `contact` |
|
|
69
|
+
| Project, Task, Planning | `clipboard-list` |
|
|
70
|
+
| Support, Ticket, Help | `headphones` |
|
|
71
|
+
| Reporting, Analytics, Dashboard | `bar-chart-2` |
|
|
72
|
+
| Other | `layout-grid` |
|
|
73
|
+
|
|
74
|
+
### 0c. Confirm Application Identity (BLOCKING)
|
|
75
|
+
|
|
76
|
+
Display the application identity:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
{language == "fr"
|
|
80
|
+
? "## Identité de l'application\n\nVoici l'identité de votre application dans la hiérarchie de navigation SmartStack :"
|
|
81
|
+
: "## Application Identity\n\nHere is your application's identity in the SmartStack navigation hierarchy:"}
|
|
82
|
+
|
|
83
|
+
| {language == "fr" ? "Niveau" : "Level"} | {language == "fr" ? "Valeur" : "Value"} |
|
|
84
|
+
|-------|-------|
|
|
85
|
+
| Context | `{context}` |
|
|
86
|
+
| Application Code | `{applicationCode}` |
|
|
87
|
+
| Application Name | `{applicationLabel}` |
|
|
88
|
+
| Route | `{applicationRoute}` |
|
|
89
|
+
| Icon | `{applicationIcon}` |
|
|
90
|
+
| Table Prefix | `{tablePrefix}` |
|
|
91
|
+
| Sort Order | `{sort}` |
|
|
92
|
+
|
|
93
|
+
{language == "fr"
|
|
94
|
+
? "### Rôles applicatifs\n\nCes rôles seront hérités par tous les modules :"
|
|
95
|
+
: "### Application Roles\n\nThese roles will be inherited by all modules:"}
|
|
96
|
+
|
|
97
|
+
| Role | Level | Permission Pattern |
|
|
98
|
+
|------|-------|--------------------|
|
|
99
|
+
{for each role in cadrage.applicationRoles: role.role | role.level | {context}.{kebab(applicationCode)}.* }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Ask via AskUserQuestion:
|
|
103
|
+
```
|
|
104
|
+
question: "{language == 'fr' ? 'Cette identité d\'application est-elle correcte ?' : 'Is this application identity correct?'}"
|
|
105
|
+
header: "Application"
|
|
106
|
+
options:
|
|
107
|
+
- label: "{language == 'fr' ? 'Oui, parfait' : 'Yes, perfect'}"
|
|
108
|
+
description: "{language == 'fr' ? 'Code, route, icône et rôles sont corrects' : 'Code, route, icon and roles are correct'}"
|
|
109
|
+
- label: "{language == 'fr' ? 'Modifier' : 'Modify'}"
|
|
110
|
+
description: "{language == 'fr' ? 'Changer le code, la route, l\'icône ou les rôles' : 'Change code, route, icon or roles'}"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**IF "Modify":**
|
|
114
|
+
→ Ask which field(s) to change via follow-up AskUserQuestion
|
|
115
|
+
→ Apply changes
|
|
116
|
+
→ Re-display and re-confirm (loop until validated)
|
|
117
|
+
|
|
118
|
+
### 0d. Build Application SeedData Entries
|
|
119
|
+
|
|
120
|
+
Create the `navigationApplications` entry (Level 2 hierarchy entry):
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"navigationApplications": [
|
|
125
|
+
{
|
|
126
|
+
"code": "{applicationCode}",
|
|
127
|
+
"label": "{applicationLabel}",
|
|
128
|
+
"icon": "{applicationIcon}",
|
|
129
|
+
"route": "{applicationRoute}",
|
|
130
|
+
"sort": 1
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Create the `applicationRoles` entries (from cadrage.applicationRoles):
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"applicationRoles": [
|
|
141
|
+
{ "code": "admin", "name": "{applicationLabel} Admin", "permissions": "*" },
|
|
142
|
+
{ "code": "manager", "name": "{applicationLabel} Manager", "permissions": "CRU" },
|
|
143
|
+
{ "code": "contributor", "name": "{applicationLabel} Contributor", "permissions": "CR" },
|
|
144
|
+
{ "code": "viewer", "name": "{applicationLabel} Viewer", "permissions": "R" }
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
> **NOTE:** The roles map from `cadrage.applicationRoles` levels. If the cadrage defined custom roles beyond the standard 4, include them here too.
|
|
150
|
+
|
|
151
|
+
### 0e. Write Application Identity to Feature.json
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
ba-writer.enrichSection({
|
|
155
|
+
featureId: {feature_id},
|
|
156
|
+
section: "metadata",
|
|
157
|
+
data: {
|
|
158
|
+
applicationCode: "{applicationCode}",
|
|
159
|
+
applicationRoute: "{applicationRoute}",
|
|
160
|
+
applicationIcon: "{applicationIcon}"
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
> **NOTE:** The full `seedDataCore` arrays (`navigationApplications`, `applicationRoles`) will be written in step-03c when compiling the first module's specification. Here we only persist the identity fields in metadata so they are available to step-02 and step-03.
|
|
166
|
+
|
|
167
|
+
### 0f. Summary and Continue
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
{language == "fr"
|
|
171
|
+
? "✅ Application **{applicationCode}** identifiée\n\n- Route : `{applicationRoute}`\n- Icône : `{applicationIcon}`\n- Préfixe : `{tablePrefix}`\n- Rôles : {roleCount} rôles applicatifs définis\n\n→ Prochaine étape : décomposition en modules"
|
|
172
|
+
: "✅ Application **{applicationCode}** identified\n\n- Route: `{applicationRoute}`\n- Icon: `{applicationIcon}`\n- Prefix: `{tablePrefix}`\n- Roles: {roleCount} application roles defined\n\n→ Next step: module decomposition"}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
→ Load `steps/step-02-decomposition.md`
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## MULTI-APP PATH (sections 1-7)
|
|
180
|
+
|
|
181
|
+
> This path runs when `workflow.mode === "project"` (multi-application mode).
|
|
182
|
+
> It takes the candidate applications identified during cadrage and formalizes them.
|
|
183
|
+
|
|
184
|
+
### 1. Load Project Context
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
projectFeature = ba-reader.findProjectFeature()
|
|
188
|
+
globalRoles = projectFeature.cadrage.globalRoles (if defined)
|
|
189
|
+
globalScope = projectFeature.cadrage.globalScope
|
|
190
|
+
|
|
191
|
+
// Candidate applications: PRE-IDENTIFIED from step-00 prompt analysis + enriched by step-01 cadrage
|
|
192
|
+
candidateApps = projectFeature.metadata.candidateApplications
|
|
193
|
+
// These candidates already have: name, description, modules[], context, dependencies[]
|
|
194
|
+
// They may also include transversal apps extracted from shared modules (step-01 section 5b)
|
|
195
|
+
|
|
196
|
+
IF candidateApps is null or empty:
|
|
197
|
+
// Fallback: derive from coverage matrix (legacy path)
|
|
198
|
+
candidateApps = projectFeature.cadrage.coverageMatrix grouped by domain
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 2. Application Identity (per candidate)
|
|
202
|
+
|
|
203
|
+
For EACH candidate application from the cadrage analysis:
|
|
204
|
+
|
|
205
|
+
#### 2a. Confirm Application Name and Context
|
|
206
|
+
|
|
207
|
+
Display proposed application:
|
|
208
|
+
```
|
|
209
|
+
{language == "fr"
|
|
210
|
+
? "### Application : {suggestedName}\n\n**Contexte de navigation :** {suggestedContext}\n**Description :** {description based on coverage matrix items}"
|
|
211
|
+
: "### Application: {suggestedName}\n\n**Navigation context:** {suggestedContext}\n**Description:** {description based on coverage matrix items}"}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Ask via AskUserQuestion:
|
|
215
|
+
```
|
|
216
|
+
question: "{language == 'fr' ? 'Cette application et son contexte vous conviennent-ils ?' : 'Does this application and its context suit you?'}"
|
|
217
|
+
header: "{appName}"
|
|
218
|
+
options:
|
|
219
|
+
- label: "{language == 'fr' ? 'Oui, parfait' : 'Yes, perfect'}"
|
|
220
|
+
description: "{language == 'fr' ? 'Nom et contexte corrects' : 'Name and context are correct'}"
|
|
221
|
+
- label: "{language == 'fr' ? 'Modifier' : 'Modify'}"
|
|
222
|
+
description: "{language == 'fr' ? 'Changer le nom, le contexte ou la description' : 'Change name, context, or description'}"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
#### 2b. Table Prefix (per application)
|
|
226
|
+
|
|
227
|
+
Each application MUST have its own unique table prefix.
|
|
228
|
+
|
|
229
|
+
1. Derive suggested prefix from application name (2-5 lowercase letters + `_`)
|
|
230
|
+
2. Validate:
|
|
231
|
+
- Format: `^[a-z]{2,5}_$`
|
|
232
|
+
- No collision with platform prefixes: `auth_`, `nav_`, `usr_`, `ai_`, `cfg_`, `wkf_`, `support_`, `entra_`, `ref_`, `loc_`, `lic_`, `tenant_`
|
|
233
|
+
- No collision with other applications in this project
|
|
234
|
+
3. Ask via AskUserQuestion for confirmation
|
|
235
|
+
|
|
236
|
+
#### 2c. Application-Specific Roles
|
|
237
|
+
|
|
238
|
+
Based on global roles from cadrage + application-specific needs:
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
{language == "fr"
|
|
242
|
+
? "### Rôles pour {appName}\n\nVoici les rôles hérités des rôles globaux, adaptés à cette application :"
|
|
243
|
+
: "### Roles for {appName}\n\nHere are the roles inherited from global roles, adapted for this application:"}
|
|
244
|
+
|
|
245
|
+
| Role | Level | Permission Pattern |
|
|
246
|
+
|------|-------|--------------------|
|
|
247
|
+
{for each role: name | admin/manager/contributor/viewer | context.app.* pattern}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Ask via AskUserQuestion if additional roles are needed for this specific application.
|
|
251
|
+
|
|
252
|
+
#### 2d. Application Scope
|
|
253
|
+
|
|
254
|
+
Extract the subset of global scope that applies to this application:
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
applicationScope = {
|
|
258
|
+
mustHave: globalScope.mustHave.filter(item => belongsToApp(item, appCode)),
|
|
259
|
+
shouldHave: globalScope.shouldHave.filter(item => belongsToApp(item, appCode)),
|
|
260
|
+
couldHave: globalScope.couldHave.filter(item => belongsToApp(item, appCode))
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Display and confirm with user.
|
|
265
|
+
|
|
266
|
+
### 3. Inter-Application Dependency Analysis
|
|
267
|
+
|
|
268
|
+
After all applications are defined:
|
|
269
|
+
|
|
270
|
+
1. **Identify dependencies:** For each pair of applications:
|
|
271
|
+
- Shared entities (e.g., Employee defined in HR, referenced by Self-Service)
|
|
272
|
+
- Event flows (e.g., HR publishes "EmployeeCreated", Self-Service subscribes)
|
|
273
|
+
- Authentication delegation (e.g., Self-Service uses HR's employee data for auth)
|
|
274
|
+
- Data dependencies (e.g., Self-Service reads HR data)
|
|
275
|
+
|
|
276
|
+
2. **Build dependency graph:**
|
|
277
|
+
```
|
|
278
|
+
applicationDependencyGraph = {
|
|
279
|
+
edges: [
|
|
280
|
+
{ from: "EmployeeSelfService", to: "HumanResources", type: "data-dependency", description: "Reads employee data" }
|
|
281
|
+
],
|
|
282
|
+
topologicalOrder: ["HumanResources", "EmployeeSelfService"],
|
|
283
|
+
layers: [
|
|
284
|
+
{ layer: 0, applications: ["HumanResources"] },
|
|
285
|
+
{ layer: 1, applications: ["EmployeeSelfService"] }
|
|
286
|
+
]
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
3. **Cycle detection:** If circular dependencies detected → BLOCKING ERROR
|
|
291
|
+
- Display the cycle
|
|
292
|
+
- Ask user to resolve (merge applications or remove dependency)
|
|
293
|
+
|
|
294
|
+
### 4. Client Checkpoint (BLOCKING)
|
|
295
|
+
|
|
296
|
+
Display the full application structure:
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
{language == "fr"
|
|
300
|
+
? "### Structure du projet\n\nVoici les applications identifiées :"
|
|
301
|
+
: "### Project Structure\n\nHere are the identified applications:"}
|
|
302
|
+
|
|
303
|
+
| # | Application | Contexte | Préfixe | Rôles | Dépendances |
|
|
304
|
+
|---|-------------|----------|---------|-------|-------------|
|
|
305
|
+
{for each app: index | name | context | prefix | role count | dependency list}
|
|
306
|
+
|
|
307
|
+
{language == "fr"
|
|
308
|
+
? "### Ordre de traitement\n\nLes applications seront traitées dans cet ordre (fondations d'abord) :"
|
|
309
|
+
: "### Processing Order\n\nApplications will be processed in this order (foundations first):"}
|
|
310
|
+
|
|
311
|
+
{for each layer: "Layer {n}: {app1}, {app2}, ..."}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Ask via AskUserQuestion:
|
|
315
|
+
```
|
|
316
|
+
question: "{language == 'fr' ? 'Cette structure de projet vous convient-elle ?' : 'Does this project structure suit you?'}"
|
|
317
|
+
header: "Validation"
|
|
318
|
+
options:
|
|
319
|
+
- label: "{language == 'fr' ? 'Oui, continuer' : 'Yes, continue'}"
|
|
320
|
+
description: "{language == 'fr' ? 'Passer à la décomposition en modules' : 'Proceed to module decomposition'}"
|
|
321
|
+
- label: "{language == 'fr' ? 'Modifier' : 'Modify'}"
|
|
322
|
+
description: "{language == 'fr' ? 'Ajouter, supprimer ou modifier des applications' : 'Add, remove, or modify applications'}"
|
|
323
|
+
- label: "{language == 'fr' ? 'Fusionner en une seule' : 'Merge into one'}"
|
|
324
|
+
description: "{language == 'fr' ? 'Finalement, c\'est une seule application avec plusieurs modules' : 'Actually, this is one application with multiple modules'}"
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**IF "Merge into one":**
|
|
328
|
+
→ Convert back to single-application mode
|
|
329
|
+
→ Delete project-level feature.json
|
|
330
|
+
→ Create application-level feature.json with all scope items
|
|
331
|
+
→ Execute single-app path (sections 0a-0f above)
|
|
332
|
+
|
|
333
|
+
### 5. Create Per-Application Feature.json Files
|
|
334
|
+
|
|
335
|
+
For EACH application in topological order:
|
|
336
|
+
|
|
337
|
+
```
|
|
338
|
+
ba-writer.createApplicationFeature({
|
|
339
|
+
id: generate_feature_id(),
|
|
340
|
+
version: "1.0",
|
|
341
|
+
scope: "application",
|
|
342
|
+
status: "draft",
|
|
343
|
+
metadata: {
|
|
344
|
+
application: {app.code},
|
|
345
|
+
applicationCode: {toPascalCase(app.code)},
|
|
346
|
+
applicationRoute: {`/${app.context}/${toKebabCase(app.code)}`},
|
|
347
|
+
applicationIcon: {app.icon},
|
|
348
|
+
context: {app.context},
|
|
349
|
+
language: {language},
|
|
350
|
+
featureDescription: {app.description},
|
|
351
|
+
workflowType: "new",
|
|
352
|
+
analysisMode: "interactive",
|
|
353
|
+
mcpAvailable: true,
|
|
354
|
+
tablePrefix: {app.tablePrefix},
|
|
355
|
+
projectRef: {project_id},
|
|
356
|
+
workflow: {
|
|
357
|
+
mode: "application",
|
|
358
|
+
moduleOrder: [],
|
|
359
|
+
currentModuleIndex: 0,
|
|
360
|
+
completedModules: [],
|
|
361
|
+
currentModule: null
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
})
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Store the created feature.json path in the project feature.json `applications[].featureJsonPath`.
|
|
368
|
+
|
|
369
|
+
### 6. Write to Project Feature.json
|
|
370
|
+
|
|
371
|
+
```
|
|
372
|
+
ba-writer.enrichApplicationRegistry({
|
|
373
|
+
projectId: {project_id},
|
|
374
|
+
applications: [
|
|
375
|
+
{
|
|
376
|
+
code: {app1.code},
|
|
377
|
+
name: {app1.name},
|
|
378
|
+
context: {app1.context},
|
|
379
|
+
tablePrefix: {app1.tablePrefix},
|
|
380
|
+
icon: {app1.icon},
|
|
381
|
+
route: {app1.route},
|
|
382
|
+
description: {app1.description},
|
|
383
|
+
applicationRoles: [{...}],
|
|
384
|
+
scope: { mustHave: [...], shouldHave: [...], couldHave: [...] },
|
|
385
|
+
modules: [],
|
|
386
|
+
dependencies: [{...}],
|
|
387
|
+
status: "pending",
|
|
388
|
+
featureJsonPath: {app1.featureJsonPath},
|
|
389
|
+
estimatedComplexity: {app1.estimatedComplexity}
|
|
390
|
+
},
|
|
391
|
+
// ... more applications
|
|
392
|
+
],
|
|
393
|
+
applicationDependencyGraph: {
|
|
394
|
+
edges: [...],
|
|
395
|
+
topologicalOrder: [...],
|
|
396
|
+
layers: [...]
|
|
397
|
+
}
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
ba-writer.updateStatus({project_id}, "decomposed")
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### 7. Display Summary
|
|
404
|
+
|
|
405
|
+
```
|
|
406
|
+
{language == "fr"
|
|
407
|
+
? "### Décomposition en applications terminée\n\n"
|
|
408
|
+
: "### Application decomposition complete\n\n"}
|
|
409
|
+
|
|
410
|
+
| Application | Contexte | Préfixe | Route | Feature ID |
|
|
411
|
+
|-------------|----------|---------|-------|------------|
|
|
412
|
+
{for each app: name | context | prefix | route | FEAT-NNN}
|
|
413
|
+
|
|
414
|
+
{language == "fr"
|
|
415
|
+
? "→ Prochaine étape : décomposition en modules pour **{firstApp}** (application {1}/{total})"
|
|
416
|
+
: "→ Next step: module decomposition for **{firstApp}** (application {1}/{total})"}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## NEXT STEP
|
|
422
|
+
|
|
423
|
+
Load: `./step-02-decomposition.md` (for the first application in topological order, or the single application)
|
|
@@ -28,12 +28,27 @@ Decompose the application scope into ordered modules. Identify dependencies betw
|
|
|
28
28
|
### 1. Read Cadrage Results
|
|
29
29
|
|
|
30
30
|
```
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
// Determine context source based on workflow mode
|
|
32
|
+
IF workflow.mode === "project":
|
|
33
|
+
projectFeature = ba-reader.findProjectFeature()
|
|
34
|
+
currentAppCode = projectFeature.metadata.workflow.currentApplication
|
|
35
|
+
currentApp = projectFeature.applications.find(a => a.code === currentAppCode)
|
|
36
|
+
appFeature = ba-reader.findFeature(currentApp.featureJsonPath)
|
|
37
|
+
|
|
38
|
+
// Scope decomposition to current application only
|
|
39
|
+
→ Read appFeature.cadrage.globalScope (application-specific scope from step-01b)
|
|
40
|
+
→ Read appFeature.cadrage.stakeholders (filtered to this application)
|
|
41
|
+
→ Read appFeature.cadrage.applicationRoles
|
|
42
|
+
→ Read appFeature.metadata.workflow.mode
|
|
43
|
+
|
|
44
|
+
Display: "═══ Module decomposition for application: {currentApp.name} ({currentAppIndex + 1}/{total}) ═══"
|
|
45
|
+
ELSE:
|
|
46
|
+
ba-reader.findFeature({feature_id})
|
|
47
|
+
→ Read cadrage.globalScope (mustHave, shouldHave, couldHave)
|
|
48
|
+
→ Read cadrage.stakeholders (roles, tasks, pain points)
|
|
49
|
+
→ Read cadrage.applicationRoles
|
|
50
|
+
→ Read cadrage.codebaseContext (existing modules found)
|
|
51
|
+
→ Read metadata.workflow.mode
|
|
37
52
|
```
|
|
38
53
|
|
|
39
54
|
IF status already "decomposed":
|
|
@@ -368,3 +383,5 @@ When `workflow.mode = "module"` or only 1 scope item identified:
|
|
|
368
383
|
|
|
369
384
|
> **FORBIDDEN:** Asking any question between decomposition summary and step-03 load.
|
|
370
385
|
> The client checkpoint was at step 6. Do NOT add another one.
|
|
386
|
+
|
|
387
|
+
> **PROJECT MODE NOTE:** In project mode, this step runs once per application. After all modules for the current application are specified (via the module loop in step-03d), the application loop in `_module-loop.md` will advance to the next application and re-load this step for module decomposition of the next application. Module registries and dependency graphs are written to the APPLICATION-level feature.json (not the project level). The project-level feature.json tracks application status via `ba-writer.updateApplicationStatus()`.
|
|
@@ -301,11 +301,20 @@ for (const entry of specification.navigation.entries) {
|
|
|
301
301
|
|
|
302
302
|
#### 8f. SeedData Core
|
|
303
303
|
|
|
304
|
-
|
|
304
|
+
9 MANDATORY typed arrays — each with structured objects, NOT flat strings or objects.
|
|
305
305
|
|
|
306
306
|
> **STRUCTURE CARD: specification.seedDataCore**
|
|
307
307
|
> ```json
|
|
308
308
|
> {
|
|
309
|
+
> "navigationApplications": [
|
|
310
|
+
> { "code": "{app}", "label": "{Application Name}", "icon": "{icon}", "route": "/business/{app-kebab}", "sort": 1 }
|
|
311
|
+
> ],
|
|
312
|
+
> "applicationRoles": [
|
|
313
|
+
> { "code": "admin", "name": "{App} Admin", "permissions": "*" },
|
|
314
|
+
> { "code": "manager", "name": "{App} Manager", "permissions": "CRU" },
|
|
315
|
+
> { "code": "contributor", "name": "{App} Contributor", "permissions": "CR" },
|
|
316
|
+
> { "code": "viewer", "name": "{App} Viewer", "permissions": "R" }
|
|
317
|
+
> ],
|
|
309
318
|
> "navigationModules": [
|
|
310
319
|
> { "code": "{module}", "label": "{Module Name}", "icon": "list", "route": "/business/{app}/{module}", "parentCode": "{app}", "sort": 1 }
|
|
311
320
|
> ],
|
|
@@ -339,7 +348,8 @@ for (const entry of specification.navigation.entries) {
|
|
|
339
348
|
> ]
|
|
340
349
|
> }
|
|
341
350
|
> ```
|
|
342
|
-
> **MANDATORY:** All
|
|
351
|
+
> **MANDATORY:** All 9 arrays must be present. Each element must be an object, NOT a string.
|
|
352
|
+
> **NOTE:** `navigationApplications` and `applicationRoles` are populated from the application identity confirmed in step-01b. They are written ONCE for the first module processed and remain empty `[]` for subsequent modules.
|
|
343
353
|
> **CRITICAL:** `navigationSections` and `navigationResources` are DERIVED from `specification.sections[]` — use the transform algorithm below (section 8f-bis).
|
|
344
354
|
> **IMPORTANT:** `create` and `edit` are NEVER sections — they are action pages reached via buttons. Do NOT include them in `navigationSections`. Only include actual sidebar sections (list, dashboard, approve, import, etc.) and hidden route sections (detail).
|
|
345
355
|
> **FORBIDDEN:** Do NOT use `navigationModule` (singular string), `permissions` as flat string array, `rolePermissions` as flat object, `permissionsConstants` as comma-separated string.
|
|
@@ -388,6 +398,8 @@ ba-writer.enrichSection({
|
|
|
388
398
|
section: "specification",
|
|
389
399
|
data: {
|
|
390
400
|
seedDataCore: {
|
|
401
|
+
navigationApplications: [ ... ], // FROM step-01b identity (only for first module, else [])
|
|
402
|
+
applicationRoles: [ ... ], // FROM cadrage.applicationRoles (only for first module, else [])
|
|
391
403
|
navigationModules: [ ... ],
|
|
392
404
|
navigationSections: navigationSections, // DERIVED
|
|
393
405
|
navigationResources: navigationResources, // DERIVED
|
|
@@ -73,7 +73,7 @@ Validate the module specification for completeness and consistency, write to fea
|
|
|
73
73
|
| messages | 4 | `specification.messages.length >= 4` | PASS/FAIL |
|
|
74
74
|
| messageFormat | `message` field present (BLOCKING) | `specification.messages.every(m => m.message)` | PASS/FAIL |
|
|
75
75
|
| lifeCycles | 1 (if entity has status) | `specification.lifeCycles.length >= 1` (if any entity has status/state field) | PASS/FAIL |
|
|
76
|
-
| seedDataCore |
|
|
76
|
+
| seedDataCore | 9 arrays present with content | See detailed check below | PASS/FAIL (BLOCKING) |
|
|
77
77
|
| apiEndpoints | 1 | `specification.apiEndpoints.length >= 1` | PASS/FAIL |
|
|
78
78
|
| i18nKeys | present | `specification.i18nKeys !== undefined && specification.i18nKeys !== null` | PASS/FAIL |
|
|
79
79
|
| navigationIcons | non-null | `specification.seedDataCore.navigationModules.every(m => m.icon !== null)` | PASS/FAIL |
|
|
@@ -81,7 +81,11 @@ Validate the module specification for completeness and consistency, write to fea
|
|
|
81
81
|
**seedDataCore detailed check (BLOCKING):**
|
|
82
82
|
```javascript
|
|
83
83
|
const sdc = specification.seedDataCore;
|
|
84
|
+
const currentModuleIndex = metadata.workflow?.currentModuleIndex || 0;
|
|
84
85
|
const checks = [
|
|
86
|
+
// navigationApplications and applicationRoles: required for first module (index 0), can be empty for subsequent modules
|
|
87
|
+
{ key: "navigationApplications", actual: sdc.navigationApplications?.length || 0, min: currentModuleIndex === 0 ? 1 : 0 },
|
|
88
|
+
{ key: "applicationRoles", actual: sdc.applicationRoles?.length || 0, min: currentModuleIndex === 0 ? 1 : 0 },
|
|
85
89
|
{ key: "navigationModules", actual: sdc.navigationModules?.length || 0, min: 1 },
|
|
86
90
|
{ key: "navigationSections", actual: sdc.navigationSections?.length || 0, min: 1 }, // EVERY module needs ≥1 section
|
|
87
91
|
{ key: "navigationResources", actual: sdc.navigationResources?.length || 0, min: 1 },
|
|
@@ -548,8 +552,6 @@ IF currentModuleIndex < moduleOrder.length:
|
|
|
548
552
|
Load: steps/step-03a1-setup.md
|
|
549
553
|
|
|
550
554
|
IF currentModuleIndex >= moduleOrder.length:
|
|
551
|
-
Display: "═══ Tous les modules spécifiés! Passage à la consolidation (04a→04c) puis handoff (05a→05c)... ═══"
|
|
552
|
-
Display: "⚠ NE PAS lancer /ralph-loop — la consolidation et le handoff sont encore nécessaires."
|
|
553
555
|
ba-writer.updateStatus({feature_id}, "specified")
|
|
554
556
|
|
|
555
557
|
// CHECKPOINT: Save progress BEFORE transition (protects against context exhaustion)
|
|
@@ -562,10 +564,33 @@ IF currentModuleIndex >= moduleOrder.length:
|
|
|
562
564
|
}
|
|
563
565
|
})
|
|
564
566
|
|
|
565
|
-
//
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
567
|
+
// CHECK: Are we in project mode (multi-application)?
|
|
568
|
+
IF workflow.mode === "project":
|
|
569
|
+
// APPLICATION LOOP: Check if more applications remain
|
|
570
|
+
projectFeature = ba-reader.findProjectFeature()
|
|
571
|
+
ba-writer.updateApplicationStatus(projectId, currentApp.code, "specified")
|
|
572
|
+
ba-writer.advanceApplicationLoop(projectId)
|
|
573
|
+
|
|
574
|
+
IF projectFeature.metadata.workflow.currentApplicationIndex + 1 < projectFeature.metadata.workflow.applicationOrder.length:
|
|
575
|
+
nextApp = projectFeature.metadata.workflow.applicationOrder[currentApplicationIndex + 1]
|
|
576
|
+
Display: "═══ Application {currentApp.name} terminée ({N}/{total}). Prochaine : {nextApp} ═══"
|
|
577
|
+
Display: "⚠ NE PAS lancer /ralph-loop — d'autres applications et la consolidation sont encore nécessaires."
|
|
578
|
+
// Load step-02 for next application's module decomposition
|
|
579
|
+
Load: steps/step-02-decomposition.md
|
|
580
|
+
ELSE:
|
|
581
|
+
Display: "═══ Toutes les applications spécifiées! Passage à la consolidation cross-application... ═══"
|
|
582
|
+
Display: "⚠ NE PAS lancer /ralph-loop — la consolidation et le handoff sont encore nécessaires."
|
|
583
|
+
ba-writer.updateStatus(projectId, "specified")
|
|
584
|
+
Load: steps/step-04a-collect.md
|
|
585
|
+
ELSE:
|
|
586
|
+
// SINGLE APPLICATION: Current behavior
|
|
587
|
+
Display: "═══ Tous les modules spécifiés! Passage à la consolidation (04a→04c) puis handoff (05a→05c)... ═══"
|
|
588
|
+
Display: "⚠ NE PAS lancer /ralph-loop — la consolidation et le handoff sont encore nécessaires."
|
|
589
|
+
|
|
590
|
+
// MANDATORY TRANSITION — DO NOT STOP HERE
|
|
591
|
+
// If context is near exhaustion, the checkpoint above ensures the user
|
|
592
|
+
// can resume with /business-analyse and it will route to step-04a automatically.
|
|
593
|
+
Load: steps/step-04a-collect.md
|
|
569
594
|
```
|
|
570
595
|
|
|
571
596
|
---
|