@atlashub/smartstack-cli 3.4.0 → 3.4.1
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 +14 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/project/appsettings.json.template +12 -2
- package/templates/skills/business-analyse/SKILL.md +47 -143
- package/templates/skills/business-analyse/_shared.md +1 -1
- package/templates/skills/business-analyse/html/ba-interactive.html +269 -28
- package/templates/skills/business-analyse/schemas/application-schema.json +3 -4
- package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +1 -2
- package/templates/skills/business-analyse/steps/step-00-init.md +130 -398
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +6 -14
- package/templates/skills/business-analyse/steps/step-05b-deploy.md +22 -69
- package/templates/skills/business-analyse/templates/tpl-handoff.md +3 -13
- package/templates/skills/business-analyse/templates/tpl-launch-displays.md +23 -128
- package/templates/skills/business-analyse/templates-frd.md +3 -19
- package/templates/skills/business-analyse/steps/step-06-extract.md +0 -648
|
@@ -1,648 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: step-06-extract
|
|
3
|
-
description: Extract interactive HTML document data into feature.json - zero information loss
|
|
4
|
-
model: sonnet
|
|
5
|
-
next_step: null
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
> **Context files:** `_shared.md`
|
|
9
|
-
|
|
10
|
-
# Step 6: Extraction depuis le document interactif
|
|
11
|
-
|
|
12
|
-
## REGLES D'EXECUTION
|
|
13
|
-
|
|
14
|
-
- TOUJOURS lire le fichier JSON exporte avant toute operation
|
|
15
|
-
- TOUJOURS mapper CHAQUE element sans exception (zero perte d'information)
|
|
16
|
-
- TOUJOURS utiliser ba-writer pour ecrire dans feature.json
|
|
17
|
-
- TOUJOURS afficher un resume comparatif avant/apres extraction
|
|
18
|
-
- TOUJOURS demander confirmation avant d'ecraser un feature.json existant
|
|
19
|
-
- COMMUNICATION en `{language}` (depuis metadata ou config)
|
|
20
|
-
|
|
21
|
-
## VOTRE TACHE
|
|
22
|
-
|
|
23
|
-
Lire le fichier JSON exporte depuis le document HTML interactif et transformer toutes les donnees client en feature.json conforme au schema. Chaque element saisi par le client doit se retrouver dans le feature.json sans perte ni alteration.
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## SEQUENCE D'EXECUTION
|
|
28
|
-
|
|
29
|
-
### 1. Lire le fichier JSON exporte
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
Lire le fichier passe en argument : {extract_path}
|
|
33
|
-
→ Parser le JSON
|
|
34
|
-
→ Valider la structure minimale : metadata, cadrage, modules
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
**Structure attendue du JSON exporte :**
|
|
38
|
-
```json
|
|
39
|
-
{
|
|
40
|
-
"metadata": {
|
|
41
|
-
"applicationName": "...",
|
|
42
|
-
"applicationId": "...",
|
|
43
|
-
"version": "...",
|
|
44
|
-
"createdAt": "...",
|
|
45
|
-
"lastModified": "...",
|
|
46
|
-
"exportedAt": "..."
|
|
47
|
-
},
|
|
48
|
-
"cadrage": {
|
|
49
|
-
"problem": { "description": "", "impactedPeople": "", "history": "", "trigger": "", "consequences": "" },
|
|
50
|
-
"current": { "tools": "", "painPoints": "", "errors": "", "steps": [] },
|
|
51
|
-
"vision": { "changes": "", "results": "", "successSign": "" },
|
|
52
|
-
"stakeholders": [{ "role": "", "function": "", "tasks": [], "frequency": "", "access": "", "frustrations": "" }],
|
|
53
|
-
"scope": {
|
|
54
|
-
"vital": [{ "name": "", "description": "" }],
|
|
55
|
-
"important": [],
|
|
56
|
-
"optional": [],
|
|
57
|
-
"excluded": []
|
|
58
|
-
},
|
|
59
|
-
"risks": [{ "description": "", "probability": "", "impact": "", "mitigation": "" }],
|
|
60
|
-
"assumptions": "",
|
|
61
|
-
"success": { "definition": "", "metrics": "", "timeline": "", "minimumConditions": "" }
|
|
62
|
-
},
|
|
63
|
-
"modules": [{ "code": "", "name": "", "description": "", "featureType": "", "priority": "", "entities": [], "status": "" }],
|
|
64
|
-
"dependencies": [{ "from": "", "to": "", "description": "" }],
|
|
65
|
-
"moduleSpecifications": {
|
|
66
|
-
"{code}": {
|
|
67
|
-
"module": {},
|
|
68
|
-
"useCases": [{ "id": "", "name": "", "actor": "", "steps": "", "alternative": "" }],
|
|
69
|
-
"businessRules": [{ "id": "", "name": "", "category": "", "statement": "", "example": "" }],
|
|
70
|
-
"entities": [{ "name": "", "description": "", "attributes": [{ "name": "", "description": "" }], "relationships": [] }],
|
|
71
|
-
"permissions": [],
|
|
72
|
-
"notes": ""
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
"consolidation": {
|
|
76
|
-
"interactions": [],
|
|
77
|
-
"e2eFlows": [{ "name": "", "steps": [{ "module": "", "action": "" }], "actors": "", "diagram": "" }]
|
|
78
|
-
},
|
|
79
|
-
"artifacts": {
|
|
80
|
-
"wireframes": {
|
|
81
|
-
"{moduleCode}": [
|
|
82
|
-
{ "screen": "", "section": "", "format": "ascii|svg", "content": "", "description": "",
|
|
83
|
-
"elements": [], "actions": [], "componentMapping": [], "layout": {}, "permissionsRequired": [] }
|
|
84
|
-
]
|
|
85
|
-
},
|
|
86
|
-
"e2eFlows": [
|
|
87
|
-
{ "name": "", "diagram": "", "steps": [], "actors": "", "modules": "" }
|
|
88
|
-
],
|
|
89
|
-
"dependencyGraph": {
|
|
90
|
-
"nodes": [{ "id": "", "label": "", "type": "" }],
|
|
91
|
-
"edges": [{ "from": "", "to": "", "description": "" }]
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
SI le fichier est invalide ou manquant → STOP avec message d'erreur.
|
|
98
|
-
|
|
99
|
-
### 2. Determiner l'application et le contexte
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
application_name = metadata.applicationName OU metadata.applicationId
|
|
103
|
-
version = metadata.version OU "1.0"
|
|
104
|
-
language = "fr" (par defaut, le document HTML est en francais)
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Verifier si un feature.json existe deja :
|
|
108
|
-
```
|
|
109
|
-
ba-reader.findFeature(application_name)
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
SI feature.json existe :
|
|
113
|
-
→ Demander via AskUserQuestion :
|
|
114
|
-
```
|
|
115
|
-
question: "Un feature.json existe deja pour cette application. Que souhaitez-vous faire ?"
|
|
116
|
-
header: "Conflit"
|
|
117
|
-
options:
|
|
118
|
-
- label: "Remplacer"
|
|
119
|
-
description: "Ecraser le feature.json existant avec les donnees du document interactif"
|
|
120
|
-
- label: "Fusionner"
|
|
121
|
-
description: "Fusionner les nouvelles donnees avec l'existant (priorite au document interactif)"
|
|
122
|
-
- label: "Nouvelle version"
|
|
123
|
-
description: "Creer une nouvelle version (v1.1) en conservant l'ancien"
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### 3. Mapper le cadrage
|
|
127
|
-
|
|
128
|
-
**Transformation : HTML export → feature.json cadrage**
|
|
129
|
-
|
|
130
|
-
| Source (export JSON) | Destination (feature.json) |
|
|
131
|
-
|---------------------|---------------------------|
|
|
132
|
-
| `cadrage.problem.description` | `cadrage.problem` |
|
|
133
|
-
| `cadrage.problem.impactedPeople` | `cadrage.problem` (append) |
|
|
134
|
-
| `cadrage.problem.history` | `cadrage.problem` (append) |
|
|
135
|
-
| `cadrage.problem.trigger` | `cadrage.trigger` |
|
|
136
|
-
| `cadrage.problem.consequences` | `cadrage.problem` (append) |
|
|
137
|
-
| `cadrage.current.tools` | `cadrage.asIs` |
|
|
138
|
-
| `cadrage.current.steps[]` | `cadrage.asIs` (append process steps) |
|
|
139
|
-
| `cadrage.current.painPoints` | `cadrage.asIs` (append) |
|
|
140
|
-
| `cadrage.current.errors` | `cadrage.asIs` (append) |
|
|
141
|
-
| `cadrage.vision.changes` | `cadrage.toBe` |
|
|
142
|
-
| `cadrage.vision.results` | `cadrage.toBe` (append) |
|
|
143
|
-
| `cadrage.vision.successSign` | `cadrage.toBe` (append) |
|
|
144
|
-
| `cadrage.stakeholders[]` | `cadrage.stakeholders[]` (voir mapping detaille) |
|
|
145
|
-
| `cadrage.scope.vital[]` | `cadrage.globalScope.mustHave[]` |
|
|
146
|
-
| `cadrage.scope.important[]` | `cadrage.globalScope.shouldHave[]` |
|
|
147
|
-
| `cadrage.scope.optional[]` | `cadrage.globalScope.couldHave[]` |
|
|
148
|
-
| `cadrage.scope.excluded[]` | `cadrage.globalScope.outOfScope[]` |
|
|
149
|
-
| `cadrage.risks[]` | `cadrage.risks[]` (voir mapping detaille) |
|
|
150
|
-
| `cadrage.assumptions` | `cadrage.risks[]` (type: "assumption") |
|
|
151
|
-
| `cadrage.success.definition` | `cadrage.acceptanceCriteria[]` |
|
|
152
|
-
| `cadrage.success.metrics` | `cadrage.acceptanceCriteria[]` |
|
|
153
|
-
| `cadrage.success.timeline` | `cadrage.acceptanceCriteria[]` |
|
|
154
|
-
| `cadrage.success.minimumConditions` | `cadrage.acceptanceCriteria[]` |
|
|
155
|
-
|
|
156
|
-
**Mapping detaille des parties prenantes :**
|
|
157
|
-
|
|
158
|
-
Pour chaque `cadrage.stakeholders[i]` :
|
|
159
|
-
```json
|
|
160
|
-
{
|
|
161
|
-
"role": stakeholders[i].role,
|
|
162
|
-
"function": stakeholders[i].function,
|
|
163
|
-
"involvement": mapAccessToInvolvement(stakeholders[i].access),
|
|
164
|
-
"tasks": stakeholders[i].tasks,
|
|
165
|
-
"frequency": stakeholders[i].frequency,
|
|
166
|
-
"painPoints": [stakeholders[i].frustrations]
|
|
167
|
-
}
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Mapping `access` → `involvement` :
|
|
171
|
-
| access (HTML) | involvement (feature.json) |
|
|
172
|
-
|--------------|---------------------------|
|
|
173
|
-
| admin | decision-maker |
|
|
174
|
-
| manager | approver |
|
|
175
|
-
| contributor | end-user |
|
|
176
|
-
| viewer | informed |
|
|
177
|
-
|
|
178
|
-
**Mapping detaille des risques :**
|
|
179
|
-
|
|
180
|
-
Pour chaque `cadrage.risks[i]` :
|
|
181
|
-
```json
|
|
182
|
-
{
|
|
183
|
-
"id": "RISK-" + String(i + 1).padStart(3, '0'),
|
|
184
|
-
"type": "business",
|
|
185
|
-
"description": risks[i].description,
|
|
186
|
-
"probability": risks[i].probability,
|
|
187
|
-
"impact": risks[i].impact,
|
|
188
|
-
"priority": computePriority(risks[i].probability, risks[i].impact),
|
|
189
|
-
"mitigation": risks[i].mitigation
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
Pour les hypotheses (texte libre `cadrage.assumptions`) :
|
|
194
|
-
```
|
|
195
|
-
Decouper le texte par lignes
|
|
196
|
-
Pour chaque ligne non vide, creer un risque :
|
|
197
|
-
{
|
|
198
|
-
"id": "RISK-ASM-" + index,
|
|
199
|
-
"type": "assumption",
|
|
200
|
-
"description": ligne,
|
|
201
|
-
"probability": "medium",
|
|
202
|
-
"impact": "medium",
|
|
203
|
-
"priority": "medium",
|
|
204
|
-
"mitigation": "A verifier avant le demarrage du projet"
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
**Mapping de la couverture :**
|
|
209
|
-
|
|
210
|
-
Construire `cadrage.coverageMatrix[]` a partir du scope :
|
|
211
|
-
```
|
|
212
|
-
Pour chaque item dans scope.vital :
|
|
213
|
-
{ "item": item.name, "category": "mustHave", "module": assignModule(item), "notes": item.description }
|
|
214
|
-
Pour chaque item dans scope.important :
|
|
215
|
-
{ "item": item.name, "category": "shouldHave", "module": assignModule(item), "notes": item.description }
|
|
216
|
-
Pour chaque item dans scope.optional :
|
|
217
|
-
{ "item": item.name, "category": "couldHave", "module": assignModule(item), "notes": item.description }
|
|
218
|
-
Pour chaque item dans scope.excluded :
|
|
219
|
-
{ "item": item.name, "category": "outOfScope", "module": null, "notes": item.description }
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
`assignModule(item)` : Si un seul module, assigner ce module. Si plusieurs modules, chercher le module dont le nom ou les entites correspondent le mieux a l'item.
|
|
223
|
-
|
|
224
|
-
**Mapping des roles applicatifs :**
|
|
225
|
-
|
|
226
|
-
Deriver `cadrage.applicationRoles[]` a partir des profils stakeholders :
|
|
227
|
-
```
|
|
228
|
-
Pour chaque stakeholder unique par niveau d'acces :
|
|
229
|
-
{
|
|
230
|
-
"role": "{App} " + formatRole(access),
|
|
231
|
-
"description": stakeholder.function,
|
|
232
|
-
"level": access,
|
|
233
|
-
"permissionPattern": "business.{app}." + (access === "admin" ? "*" : "...")
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
**Ecriture :**
|
|
238
|
-
```
|
|
239
|
-
ba-writer.enrichSection({
|
|
240
|
-
featureId: {feature_id},
|
|
241
|
-
section: "cadrage",
|
|
242
|
-
data: { problem, asIs, toBe, trigger, stakeholders, globalScope, applicationRoles, risks, acceptanceCriteria, coverageMatrix, codebaseContext }
|
|
243
|
-
})
|
|
244
|
-
ba-writer.updateStatus({feature_id}, "framed")
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### 4. Mapper les modules
|
|
248
|
-
|
|
249
|
-
Pour chaque `modules[i]` du JSON exporte :
|
|
250
|
-
```json
|
|
251
|
-
{
|
|
252
|
-
"code": modules[i].code,
|
|
253
|
-
"description": modules[i].description,
|
|
254
|
-
"featureType": modules[i].featureType,
|
|
255
|
-
"dependencies": deriveDependencies(modules[i].code),
|
|
256
|
-
"dependents": deriveDependents(modules[i].code),
|
|
257
|
-
"status": "pending",
|
|
258
|
-
"featureJsonPath": null,
|
|
259
|
-
"priority": modules[i].priority,
|
|
260
|
-
"sortOrder": computeSortOrder(modules[i].code),
|
|
261
|
-
"entities": modules[i].entities,
|
|
262
|
-
"estimatedComplexity": estimateComplexity(modules[i].code)
|
|
263
|
-
}
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
`deriveDependencies(code)` : filtrer `dependencies[]` ou `from === code`, retourner les `to`
|
|
267
|
-
`deriveDependents(code)` : filtrer `dependencies[]` ou `to === code`, retourner les `from`
|
|
268
|
-
`computeSortOrder(code)` : depuis le tri topologique
|
|
269
|
-
`estimateComplexity(code)` : basee sur le nombre d'entites et de cas d'utilisation du module
|
|
270
|
-
|
|
271
|
-
**Construire le graphe de dependances :**
|
|
272
|
-
```json
|
|
273
|
-
{
|
|
274
|
-
"edges": dependencies.map(d => ({ "from": d.from, "to": d.to, "type": "FK", "description": d.description })),
|
|
275
|
-
"topologicalOrder": computeTopologicalOrder(),
|
|
276
|
-
"layers": computeLayers()
|
|
277
|
-
}
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
**Ecriture :**
|
|
281
|
-
```
|
|
282
|
-
ba-writer.enrichModuleRegistry({
|
|
283
|
-
featureId: {feature_id},
|
|
284
|
-
modules: [mapped modules],
|
|
285
|
-
dependencyGraph: { edges, topologicalOrder, layers }
|
|
286
|
-
})
|
|
287
|
-
ba-writer.updateStatus({feature_id}, "decomposed")
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### 5. Mapper les specifications par module
|
|
291
|
-
|
|
292
|
-
Pour chaque module dans l'ordre topologique :
|
|
293
|
-
|
|
294
|
-
#### 5a. Creer le feature.json du module
|
|
295
|
-
|
|
296
|
-
```
|
|
297
|
-
ba-writer.create({
|
|
298
|
-
scope: "module",
|
|
299
|
-
applicationRef: {feature_id},
|
|
300
|
-
moduleCode: {module.code},
|
|
301
|
-
path: "docs/business/{app}/{module_code}/business-analyse/v1.0/feature.json"
|
|
302
|
-
})
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
#### 5b. Mapper la section discovery
|
|
306
|
-
|
|
307
|
-
Deriver de la cadrage, filtree pour ce module (meme logique que step-03 section 2-ter).
|
|
308
|
-
|
|
309
|
-
#### 5c. Mapper les cas d'utilisation
|
|
310
|
-
|
|
311
|
-
Pour chaque `moduleSpecifications[code].useCases[i]` :
|
|
312
|
-
```json
|
|
313
|
-
{
|
|
314
|
-
"id": "UC-{PREFIX}-" + String(i + 1).padStart(3, '0'),
|
|
315
|
-
"name": uc.name,
|
|
316
|
-
"primaryActor": uc.actor,
|
|
317
|
-
"permission": "business.{app}.{module}.{inferAction(uc.name)}",
|
|
318
|
-
"preconditions": [],
|
|
319
|
-
"postconditions": [],
|
|
320
|
-
"mainScenario": parseSteps(uc.steps),
|
|
321
|
-
"alternativeScenarios": uc.alternative ? [{ "name": "Cas alternatif", "steps": [uc.alternative] }] : [],
|
|
322
|
-
"errorScenarios": [],
|
|
323
|
-
"linkedRules": linkToBusinessRules(uc, moduleSpec.businessRules)
|
|
324
|
-
}
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
`parseSteps(text)` : Decouper par lignes, retourner en tableau.
|
|
328
|
-
`inferAction(name)` : Extraire le verbe (Creer→create, Modifier→update, Supprimer→delete, Consulter→read, Valider→approve, Exporter→export).
|
|
329
|
-
`linkToBusinessRules(uc, rules)` : Chercher les regles dont le statement mentionne des concepts similaires au nom du UC.
|
|
330
|
-
|
|
331
|
-
#### 5d. Mapper les regles metier
|
|
332
|
-
|
|
333
|
-
Pour chaque `moduleSpecifications[code].businessRules[i]` :
|
|
334
|
-
```json
|
|
335
|
-
{
|
|
336
|
-
"id": "BR-{CAT}-{PREFIX}-" + String(i + 1).padStart(3, '0'),
|
|
337
|
-
"name": br.name,
|
|
338
|
-
"category": br.category,
|
|
339
|
-
"statement": br.statement,
|
|
340
|
-
"priority": "must",
|
|
341
|
-
"conditions": extractConditions(br.statement),
|
|
342
|
-
"examples": br.example ? [{ "input": br.example, "expected": "Selon la regle" }] : [],
|
|
343
|
-
"testability": "Via test unitaire"
|
|
344
|
-
}
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
`{CAT}` derive de `category` : validation→VAL, calculation→CALC, workflow→WF, security→SEC, data→DATA
|
|
348
|
-
`extractConditions(statement)` : Extraire les conditions depuis le texte "Si..." en tableau.
|
|
349
|
-
|
|
350
|
-
#### 5e. Mapper les entites
|
|
351
|
-
|
|
352
|
-
Pour chaque `moduleSpecifications[code].entities[i]` :
|
|
353
|
-
```json
|
|
354
|
-
{
|
|
355
|
-
"name": toPascalCase(ent.name),
|
|
356
|
-
"description": ent.description,
|
|
357
|
-
"attributes": ent.attributes.map(a => ({
|
|
358
|
-
"name": toCamelCase(a.name),
|
|
359
|
-
"description": a.description,
|
|
360
|
-
"required": true,
|
|
361
|
-
"unique": false,
|
|
362
|
-
"validation": ""
|
|
363
|
-
})),
|
|
364
|
-
"relationships": parseRelationships(ent.relationships)
|
|
365
|
-
}
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
`parseRelationships(rels)` : Pour chaque relation texte "Nom - Description", extraire :
|
|
369
|
-
```json
|
|
370
|
-
{ "target": toPascalCase(nom), "type": "1:N", "description": description }
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
#### 5f. Mapper les permissions
|
|
374
|
-
|
|
375
|
-
Transformer le format `permissions: ["Role|Action"]` en matrice structuree :
|
|
376
|
-
```json
|
|
377
|
-
{
|
|
378
|
-
"permissions": derivePermissionPaths(code, actions),
|
|
379
|
-
"roleAssignments": deriveRoleAssignments(code, permissions)
|
|
380
|
-
}
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
#### 5g. Generer les sections, wireframes et seedDataCore
|
|
384
|
-
|
|
385
|
-
Inferer automatiquement a partir des entites et du type de module (meme logique que step-03 section 3a-infer).
|
|
386
|
-
|
|
387
|
-
#### 5h. Ecrire le feature.json du module
|
|
388
|
-
|
|
389
|
-
```
|
|
390
|
-
ba-writer.enrichSection({ featureId: moduleFeatureId, section: "analysis", data: { objectives, entities, businessRules, processFlow, dataLifecycle } })
|
|
391
|
-
ba-writer.enrichSection({ featureId: moduleFeatureId, section: "specification", data: { actors, useCases, functionalRequirements, permissionMatrix, navigation, seedDataCore, sections, uiWireframes } })
|
|
392
|
-
ba-writer.updateModuleStatus({feature_id}, {module.code}, "specified")
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
### 6. Mapper la consolidation
|
|
396
|
-
|
|
397
|
-
Si plusieurs modules :
|
|
398
|
-
```
|
|
399
|
-
ba-writer.enrichSection({
|
|
400
|
-
featureId: {feature_id},
|
|
401
|
-
section: "consolidation",
|
|
402
|
-
data: {
|
|
403
|
-
crossModuleInteractions: dependencies.map(d => ({
|
|
404
|
-
"fromModule": d.from, "toModule": d.to,
|
|
405
|
-
"interactionType": "FK-reference",
|
|
406
|
-
"description": d.description,
|
|
407
|
-
"entities": []
|
|
408
|
-
})),
|
|
409
|
-
e2eFlows: consolidation.e2eFlows.map(flow => ({
|
|
410
|
-
"name": flow.name,
|
|
411
|
-
"modules": [...new Set(flow.steps.map(s => s.module))],
|
|
412
|
-
"steps": flow.steps.map(s => ({
|
|
413
|
-
"module": s.module,
|
|
414
|
-
"action": s.action,
|
|
415
|
-
"permission": "",
|
|
416
|
-
"dataFlow": ""
|
|
417
|
-
}))
|
|
418
|
-
})),
|
|
419
|
-
permissionCoherence: { rolesConsistent: true, pathFormatConsistent: true, hierarchyRespected: true, conflicts: [], warnings: [] },
|
|
420
|
-
decision: { approved: true, reason: "Extracted from interactive document", approvedBy: "Client", approvedAt: new Date().toISOString() }
|
|
421
|
-
}
|
|
422
|
-
})
|
|
423
|
-
ba-writer.updateStatus({feature_id}, "consolidated")
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### 6-bis. Extraire et reconstituer les artefacts visuels (NEW)
|
|
427
|
-
|
|
428
|
-
> Visual artifacts (wireframes, E2E diagrams, dependency graph) are extracted from the exported JSON and reconstituted into feature.json.
|
|
429
|
-
|
|
430
|
-
**IF** `artifacts` exists in exported JSON:
|
|
431
|
-
|
|
432
|
-
#### Extract wireframes per module
|
|
433
|
-
|
|
434
|
-
Pour chaque module dans `artifacts.wireframes`:
|
|
435
|
-
|
|
436
|
-
```
|
|
437
|
-
FOR EACH moduleCode IN artifacts.wireframes:
|
|
438
|
-
moduleWireframes = artifacts.wireframes[moduleCode]
|
|
439
|
-
|
|
440
|
-
// Locate the module feature.json
|
|
441
|
-
moduleFeature = ba-reader.findModuleFeature({feature_id}, moduleCode)
|
|
442
|
-
|
|
443
|
-
// Map wireframes to specification.uiWireframes[]
|
|
444
|
-
uiWireframes = moduleWireframes.map(wf => ({
|
|
445
|
-
"screen": wf.screen,
|
|
446
|
-
"section": wf.section,
|
|
447
|
-
"mockupFormat": wf.format,
|
|
448
|
-
"mockup": wf.content,
|
|
449
|
-
"description": wf.description || "",
|
|
450
|
-
"elements": wf.elements || [],
|
|
451
|
-
"actions": wf.actions || [],
|
|
452
|
-
"permissionsRequired": wf.permissionsRequired || [],
|
|
453
|
-
"componentMapping": wf.componentMapping || [],
|
|
454
|
-
"layout": wf.layout || null
|
|
455
|
-
}))
|
|
456
|
-
|
|
457
|
-
// Write to module feature.json (enriching specification section)
|
|
458
|
-
ba-writer.enrichSection({
|
|
459
|
-
featureId: moduleFeature.id,
|
|
460
|
-
section: "specification",
|
|
461
|
-
data: { uiWireframes: uiWireframes }
|
|
462
|
-
})
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
**Validation:** For each wireframe:
|
|
466
|
-
- `screen` must be unique within module
|
|
467
|
-
- `mockupFormat` must be "ascii" or "svg"
|
|
468
|
-
- `mockup` content must not be empty
|
|
469
|
-
- `componentMapping` array must have at least one entry
|
|
470
|
-
- `layout` object must have `type` and `regions` if present
|
|
471
|
-
|
|
472
|
-
#### Extract E2E flow diagrams
|
|
473
|
-
|
|
474
|
-
IF `artifacts.e2eFlows` exists:
|
|
475
|
-
|
|
476
|
-
```
|
|
477
|
-
e2eFlows = artifacts.e2eFlows.map(flow => ({
|
|
478
|
-
"name": flow.name,
|
|
479
|
-
"modules": flow.modules.split(" → ").map(m => m.trim()), // "OrderManagement → Invoicing" → ["OrderManagement", "Invoicing"]
|
|
480
|
-
"steps": flow.steps || [],
|
|
481
|
-
"diagram": flow.diagram, // NEW: ASCII diagram preserved
|
|
482
|
-
"actors": flow.actors.split(", ").map(a => a.trim())
|
|
483
|
-
}))
|
|
484
|
-
|
|
485
|
-
// Merge with existing e2eFlows from consolidation.e2eFlows
|
|
486
|
-
ba-writer.enrichSection({
|
|
487
|
-
featureId: {feature_id},
|
|
488
|
-
section: "consolidation",
|
|
489
|
-
data: { e2eFlows: e2eFlows }
|
|
490
|
-
})
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
**Validation:** For each E2E flow:
|
|
494
|
-
- `diagram` must not be empty if present
|
|
495
|
-
- `modules` array must match modules defined in master feature.json
|
|
496
|
-
- `steps` must have at least 2 entries (cross-module flow)
|
|
497
|
-
|
|
498
|
-
#### Extract dependency graph (optional)
|
|
499
|
-
|
|
500
|
-
IF `artifacts.dependencyGraph` exists:
|
|
501
|
-
|
|
502
|
-
```
|
|
503
|
-
dependencyGraph = {
|
|
504
|
-
"nodes": artifacts.dependencyGraph.nodes.map(n => ({
|
|
505
|
-
"id": n.id,
|
|
506
|
-
"label": n.label || n.id,
|
|
507
|
-
"type": n.type || "data-centric"
|
|
508
|
-
})),
|
|
509
|
-
"edges": artifacts.dependencyGraph.edges.map(e => ({
|
|
510
|
-
"from": e.from,
|
|
511
|
-
"to": e.to,
|
|
512
|
-
"description": e.description || ""
|
|
513
|
-
}))
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// Write to master feature.json
|
|
517
|
-
ba-writer.enrichSection({
|
|
518
|
-
featureId: {feature_id},
|
|
519
|
-
section: "decomposition",
|
|
520
|
-
data: { dependencyGraph: dependencyGraph }
|
|
521
|
-
})
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
**Post-extraction summary:**
|
|
525
|
-
|
|
526
|
-
```
|
|
527
|
-
✓ Artefacts visuels extraits:
|
|
528
|
-
- Wireframes: {total_wireframe_count} across {module_count} modules
|
|
529
|
-
- E2E diagrams: {e2e_flow_count}
|
|
530
|
-
- Dependency graph: {node_count} nodes, {edge_count} edges
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
### 7. Resume de l'extraction
|
|
534
|
-
|
|
535
|
-
Afficher un resume comparatif :
|
|
536
|
-
```
|
|
537
|
-
═══════════════════════════════════════════════════════════════
|
|
538
|
-
EXTRACTION TERMINEE - {application_name}
|
|
539
|
-
═══════════════════════════════════════════════════════════════
|
|
540
|
-
|
|
541
|
-
| Element | Document client | Feature.json |
|
|
542
|
-
|------------------------|----------------|--------------|
|
|
543
|
-
| Probleme | {oui/non} | cadrage.problem |
|
|
544
|
-
| Situation actuelle | {oui/non} | cadrage.asIs |
|
|
545
|
-
| Vision | {oui/non} | cadrage.toBe |
|
|
546
|
-
| Parties prenantes | {count} | cadrage.stakeholders |
|
|
547
|
-
| Perimetre (vital) | {count} | globalScope.mustHave |
|
|
548
|
-
| Perimetre (important) | {count} | globalScope.shouldHave |
|
|
549
|
-
| Perimetre (optionnel) | {count} | globalScope.couldHave |
|
|
550
|
-
| Risques | {count} | cadrage.risks |
|
|
551
|
-
| Criteres de reussite | {count} | acceptanceCriteria |
|
|
552
|
-
| Domaines fonctionnels | {count} | modules |
|
|
553
|
-
| Dependances | {count} | dependencyGraph.edges |
|
|
554
|
-
| Cas d'utilisation | {total} | specification.useCases |
|
|
555
|
-
| Regles metier | {total} | analysis.businessRules |
|
|
556
|
-
| Entites | {total} | analysis.entities |
|
|
557
|
-
| Parcours E2E | {count} | consolidation.e2eFlows |
|
|
558
|
-
| Maquettes (wireframes) | {total} | specification.uiWireframes[] |
|
|
559
|
-
| Diagrammes E2E | {count} | consolidation.e2eFlows[].diagram |
|
|
560
|
-
|
|
561
|
-
Fichiers generes :
|
|
562
|
-
- docs/business/{app}/business-analyse/v1.0/feature.json (master)
|
|
563
|
-
- docs/business/{app}/{module}/business-analyse/v1.0/feature.json (par module)
|
|
564
|
-
|
|
565
|
-
Artefacts visuels preserves :
|
|
566
|
-
- Toutes les maquettes ASCII/SVG validees lors de la specification
|
|
567
|
-
- Tous les diagrammes E2E pour les flux cross-module
|
|
568
|
-
- Graphe de dependances entre modules
|
|
569
|
-
|
|
570
|
-
═══════════════════════════════════════════════════════════════
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
### 8. Choix de la suite
|
|
574
|
-
|
|
575
|
-
```
|
|
576
|
-
question: "L'extraction est terminee. Que souhaitez-vous faire ?"
|
|
577
|
-
header: "Suite"
|
|
578
|
-
options:
|
|
579
|
-
- label: "Enrichir avec le questionnaire"
|
|
580
|
-
description: "Lancer le cadrage approfondi (step-01) pour completer l'analyse avec des questions detaillees"
|
|
581
|
-
- label: "Passer au handoff"
|
|
582
|
-
description: "Generer directement le plan de developpement (step-05)"
|
|
583
|
-
- label: "Terminer"
|
|
584
|
-
description: "L'extraction suffit, je reprendrai manuellement"
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
SI "Enrichir" → charger step-01-cadrage.md (les donnees existantes seront preservees)
|
|
588
|
-
SI "Handoff" → charger step-05a-handoff.md
|
|
589
|
-
SI "Terminer" → EXIT
|
|
590
|
-
|
|
591
|
-
---
|
|
592
|
-
|
|
593
|
-
## FONCTIONS UTILITAIRES
|
|
594
|
-
|
|
595
|
-
### toPascalCase(text)
|
|
596
|
-
"gestion des commandes" → "GestionDesCommandes"
|
|
597
|
-
"commande" → "Commande"
|
|
598
|
-
|
|
599
|
-
### toCamelCase(text)
|
|
600
|
-
"Numero de commande" → "numeroDeCommande"
|
|
601
|
-
"Date" → "date"
|
|
602
|
-
|
|
603
|
-
### computePriority(probability, impact)
|
|
604
|
-
| probability | impact | priority |
|
|
605
|
-
|------------|--------|----------|
|
|
606
|
-
| high | high | critical |
|
|
607
|
-
| high | medium | critical |
|
|
608
|
-
| high | low | medium |
|
|
609
|
-
| medium | high | critical |
|
|
610
|
-
| medium | medium | medium |
|
|
611
|
-
| medium | low | low |
|
|
612
|
-
| low | high | medium |
|
|
613
|
-
| low | medium | low |
|
|
614
|
-
| low | low | low |
|
|
615
|
-
|
|
616
|
-
### inferAction(ucName)
|
|
617
|
-
Mots cles → action :
|
|
618
|
-
- creer, ajouter, nouveau → create
|
|
619
|
-
- modifier, editer, mettre a jour → update
|
|
620
|
-
- supprimer, retirer, annuler → delete
|
|
621
|
-
- consulter, voir, afficher, lister → read
|
|
622
|
-
- valider, approuver, confirmer → approve
|
|
623
|
-
- exporter, telecharger → export
|
|
624
|
-
- importer, charger → import
|
|
625
|
-
- defaut → read
|
|
626
|
-
|
|
627
|
-
---
|
|
628
|
-
|
|
629
|
-
## VALIDATION
|
|
630
|
-
|
|
631
|
-
Avant d'ecrire dans feature.json, verifier :
|
|
632
|
-
- Chaque stakeholder a au minimum : role, function
|
|
633
|
-
- Chaque use case a au minimum : name, actor
|
|
634
|
-
- Chaque business rule a au minimum : name, statement
|
|
635
|
-
- Chaque entite a au minimum : name
|
|
636
|
-
- Les IDs sont uniques (pas de doublons UC, BR, RISK)
|
|
637
|
-
- Les modules references dans les dependances existent
|
|
638
|
-
|
|
639
|
-
SI une validation echoue → afficher l'erreur et demander correction.
|
|
640
|
-
|
|
641
|
-
---
|
|
642
|
-
|
|
643
|
-
## GARANTIES
|
|
644
|
-
|
|
645
|
-
- **Zero perte** : chaque champ saisi dans le document HTML se retrouve dans le feature.json
|
|
646
|
-
- **Enrichissement** : les IDs, permissions et liens sont generes automatiquement
|
|
647
|
-
- **Conformite** : le feature.json resultant est conforme au schema
|
|
648
|
-
- **Reversibilite** : le JSON exporte original est conserve dans `metadata.sourceExport`
|