@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.
Files changed (65) hide show
  1. package/.documentation/agents.html +5 -1
  2. package/.documentation/apex.html +644 -0
  3. package/.documentation/business-analyse.html +81 -1
  4. package/.documentation/cli-commands.html +5 -1
  5. package/.documentation/commands.html +5 -1
  6. package/.documentation/efcore.html +5 -1
  7. package/.documentation/gitflow.html +5 -1
  8. package/.documentation/hooks.html +5 -1
  9. package/.documentation/index.html +60 -2
  10. package/.documentation/init.html +414 -1
  11. package/.documentation/installation.html +5 -1
  12. package/.documentation/ralph-loop.html +365 -216
  13. package/.documentation/test-web.html +5 -1
  14. package/dist/index.js +32 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/mcp-entry.mjs +7 -24
  17. package/dist/mcp-entry.mjs.map +1 -1
  18. package/package.json +1 -2
  19. package/templates/agents/ba-writer.md +142 -15
  20. package/templates/mcp-scaffolding/controller.cs.hbs +5 -1
  21. package/templates/skills/apex/SKILL.md +9 -3
  22. package/templates/skills/apex/_shared.md +49 -4
  23. package/templates/skills/{ralph-loop → apex}/references/core-seed-data.md +20 -11
  24. package/templates/skills/{ralph-loop → apex}/references/error-classification.md +2 -1
  25. package/templates/skills/apex/references/post-checks.md +463 -3
  26. package/templates/skills/apex/references/smartstack-api.md +76 -8
  27. package/templates/skills/apex/references/smartstack-frontend.md +74 -1
  28. package/templates/skills/apex/references/smartstack-layers.md +21 -3
  29. package/templates/skills/apex/steps/step-00-init.md +121 -1
  30. package/templates/skills/apex/steps/step-01-analyze.md +58 -0
  31. package/templates/skills/apex/steps/step-02-plan.md +36 -0
  32. package/templates/skills/apex/steps/step-03-execute.md +114 -7
  33. package/templates/skills/apex/steps/step-04-examine.md +116 -2
  34. package/templates/skills/business-analyse/SKILL.md +31 -20
  35. package/templates/skills/business-analyse/_module-loop.md +68 -9
  36. package/templates/skills/business-analyse/_shared.md +80 -21
  37. package/templates/skills/business-analyse/questionnaire/00-application.md +4 -2
  38. package/templates/skills/business-analyse/questionnaire/00b-project.md +85 -0
  39. package/templates/skills/business-analyse/references/deploy-modes.md +69 -0
  40. package/templates/skills/business-analyse/references/team-orchestration.md +158 -7
  41. package/templates/skills/business-analyse/schemas/application-schema.json +15 -1
  42. package/templates/skills/business-analyse/schemas/project-schema.json +490 -0
  43. package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +2 -1
  44. package/templates/skills/business-analyse/steps/step-00-init.md +220 -38
  45. package/templates/skills/business-analyse/steps/step-01-cadrage.md +184 -5
  46. package/templates/skills/business-analyse/steps/step-01b-applications.md +423 -0
  47. package/templates/skills/business-analyse/steps/step-02-decomposition.md +23 -6
  48. package/templates/skills/business-analyse/steps/step-03c-compile.md +14 -2
  49. package/templates/skills/business-analyse/steps/step-03d-validate.md +32 -7
  50. package/templates/skills/business-analyse/steps/step-04a-collect.md +111 -0
  51. package/templates/skills/business-analyse/steps/step-05a-handoff.md +296 -103
  52. package/templates/skills/business-analyse/steps/step-05b-deploy.md +46 -14
  53. package/templates/skills/documentation/SKILL.md +92 -2
  54. package/templates/skills/ralph-loop/SKILL.md +14 -17
  55. package/templates/skills/ralph-loop/references/category-rules.md +63 -683
  56. package/templates/skills/ralph-loop/references/compact-loop.md +188 -428
  57. package/templates/skills/ralph-loop/references/section-splitting.md +439 -0
  58. package/templates/skills/ralph-loop/references/team-orchestration.md +13 -14
  59. package/templates/skills/ralph-loop/steps/step-01-task.md +27 -0
  60. package/templates/skills/ralph-loop/steps/step-02-execute.md +80 -691
  61. package/templates/skills/ralph-loop/steps/step-03-commit.md +38 -79
  62. package/templates/skills/ralph-loop/steps/step-04-check.md +39 -58
  63. package/templates/skills/ralph-loop/steps/step-05-report.md +31 -123
  64. package/scripts/health-check.sh +0 -168
  65. package/scripts/postinstall.js +0 -18
@@ -85,7 +85,8 @@ mcp__smartstack__validate_conventions({ checks: ["tables"] })
85
85
 
86
86
  Execute workflow detection algorithm:
87
87
  1. **Review Mode Detection:** Check if `{feature_description}` starts with `-review`
88
- 2. **Existing Applications Scanner:** Glob `docs/business/*/business-analyse/*/feature.json`
88
+ 2. **Existing Projects Scanner:** Glob `docs/business-analyse/*/feature.json` (project-level)
89
+ 2b. **Existing Applications Scanner:** Glob `docs/business/*/business-analyse/*/feature.json` + `docs/platform/*/business-analyse/*/feature.json` + `docs/personal/*/business-analyse/*/feature.json`
89
90
  3. **Similarity Analysis:** Score user intent against existing apps (>= 80 = strong match)
90
91
  4. **Decision Tree:** Prompt user with relevant options
91
92
 
@@ -119,15 +120,125 @@ ELSE:
119
120
  ```yaml
120
121
  workflow_type: "new" | "update" | "review"
121
122
  existing_feature_id: string | null
123
+ existing_project_id: string | null # PROJ-NNN if resuming a project
122
124
  version: "1.0" (new) | "1.1"+ (update)
123
125
  review_json_path: string | null (review only)
124
126
  existing_apps: array of { app, featureId, description, version }
127
+ existing_projects: array of { projectName, projectId, applications[], version }
125
128
  ```
126
129
 
130
+ > **Project Resume Detection:** If a project-level feature.json is found at `docs/business-analyse/*/feature.json`, check its `metadata.workflow` to determine resume point. The project may have partially completed applications.
131
+
132
+ ## Step 3b: Early Multi-Application Detection from Prompt (NEW)
133
+
134
+ > **Detect multi-app structure BEFORE asking for a single application name.**
135
+ > When the user's prompt explicitly describes multiple applications, we must recognize this immediately
136
+ > and set `workflow.mode = "project"` to avoid doing cadrage for a single app.
137
+
138
+ **Detection patterns (ANY match = multi-app detected):**
139
+
140
+ ```javascript
141
+ const multiAppPatterns = [
142
+ // French patterns
143
+ /une\s+application\s+\w+.*une\s+application\s+\w+/is,
144
+ /application\s*\d?\s*[:]\s*\w+.*application\s*\d?\s*[:]\s*\w+/is,
145
+ /premier[e]?\s+application.*deuxième\s+application/is,
146
+ /app\s*1\s*[:.].*app\s*2\s*[:.]*/is,
147
+ // English patterns
148
+ /an?\s+application\s+(for\s+)?\w+.*an?\s+application\s+(for\s+)?\w+/is,
149
+ /application\s*#?\d\s*[:.].*application\s*#?\d\s*[:.]*/is,
150
+ /first\s+app.*second\s+app/is,
151
+ ];
152
+
153
+ const isMultiApp = multiAppPatterns.some(p => p.test(feature_description));
154
+ ```
155
+
156
+ **IF multi-app detected:**
157
+
158
+ 1. Extract candidate applications from the prompt:
159
+
160
+ ```javascript
161
+ // Parse the prompt to identify application boundaries
162
+ // Each "une application X" / "an application X" block = one candidate
163
+ const candidates = extractApplicationCandidates(feature_description);
164
+ // Result example:
165
+ // [
166
+ // { name: "RH", description: "gestion des employes, conges, temps", modules: ["Employes", "Conges", "Temps"] },
167
+ // { name: "Projet", description: "gestion des projets, saisie du temps", modules: ["Projets", "Temps"] }
168
+ // ]
169
+ ```
170
+
171
+ 2. Detect shared modules across candidates:
172
+
173
+ ```javascript
174
+ const allModules = candidates.flatMap(c => c.modules);
175
+ const sharedModules = allModules.filter((m, i) => allModules.indexOf(m) !== i);
176
+ // Example: sharedModules = ["Temps"] → appears in both RH and Projet
177
+ ```
178
+
179
+ 3. Display detection result and confirm:
180
+
181
+ ```
182
+ {language == "fr"
183
+ ? "### Détection multi-application\n\nJ'ai détecté **{candidates.length} applications** dans votre description :"
184
+ : "### Multi-application detection\n\nI detected **{candidates.length} applications** in your description:"}
185
+
186
+ | # | Application | Modules identifiés |
187
+ |---|-------------|-------------------|
188
+ {for each candidate: index | name | modules.join(", ")}
189
+
190
+ {sharedModules.length > 0
191
+ ? "⚠️ **Modules partagés détectés :** {sharedModules.join(', ')} — ces modules apparaissent dans plusieurs applications. Ils pourraient constituer une application transversale dédiée."
192
+ : ""}
193
+ ```
194
+
195
+ Ask via AskUserQuestion:
196
+ ```
197
+ question: "{language == 'fr' ? 'Confirmez-vous cette structure multi-application ?' : 'Do you confirm this multi-application structure?'}"
198
+ header: "Architecture"
199
+ options:
200
+ - label: "{language == 'fr' ? 'Oui, {candidates.length} applications' : 'Yes, {candidates.length} applications'}"
201
+ description: "{language == 'fr' ? 'Créer un projet avec les applications identifiées' : 'Create a project with the identified applications'}"
202
+ - label: "{language == 'fr' ? 'Extraire les modules partagés' : 'Extract shared modules'}" (only if sharedModules.length > 0)
203
+ description: "{language == 'fr' ? 'Créer une application dédiée pour {sharedModules.join(', ')} ({candidates.length + 1} applications au total)' : 'Create a dedicated app for {sharedModules.join(', ')} ({candidates.length + 1} total)'}"
204
+ - label: "{language == 'fr' ? 'Application unique' : 'Single application'}"
205
+ description: "{language == 'fr' ? 'Tout regrouper en une seule application avec plusieurs modules' : 'Group everything into one application with multiple modules'}"
206
+ ```
207
+
208
+ **IF "Oui, N applications" or "Extraire les modules partagés":**
209
+
210
+ ```yaml
211
+ workflow_mode: "project"
212
+ project_name: derived from feature_description
213
+ candidate_applications: [{ name, description, modules, context }]
214
+ shared_modules_extracted: boolean # true if user chose extraction
215
+ ```
216
+
217
+ → Skip step 4 (application name) — applications will be confirmed in step-01b
218
+ → Continue to step 5 (language selection)
219
+
220
+ **IF "Application unique":**
221
+
222
+ ```yaml
223
+ workflow_mode: "application"
224
+ ```
225
+
226
+ → Continue to step 4 normally
227
+
228
+ **IF no multi-app patterns detected:**
229
+ → Continue to step 4 normally
230
+
127
231
  ## Step 4: Determine Application Name
128
232
 
233
+ > **This step is SKIPPED if `workflow_mode = "project"` (multi-app detected in step 3b).**
234
+
129
235
  ```
130
- IF workflow_type = "update":
236
+ IF workflow_mode = "project":
237
+ application_name = project_name // Project-level name, not a single app name
238
+ context = "business" // Default, each app can have its own context
239
+ → Skip to step 5
240
+
241
+ ELSE IF workflow_type = "update":
131
242
  application_name = existing app name (from step 3)
132
243
  ELSE:
133
244
  Analyze {feature_description} to extract application name
@@ -144,12 +255,13 @@ ELSE:
144
255
  **Validate business context:**
145
256
  ```
146
257
  validate_business_context("business")
147
- → BA restricted to 'business' context only
258
+ → BA restricted to 'business' context only (in standalone mode)
259
+ → In project mode, each application can target any context
148
260
  ```
149
261
 
150
262
  **Store:**
151
263
  ```yaml
152
- application_name: string
264
+ application_name: string # or project_name if project mode
153
265
  context: "business"
154
266
  ```
155
267
 
@@ -211,15 +323,22 @@ feature_id: string
211
323
  ## Step 7: Create Output Directory Structure
212
324
 
213
325
  ```
214
- IF workflow_type = "new":
326
+ IF workflow_mode = "project":
327
+ // Project mode: create project-level directory + per-app directories later (in step-01b)
328
+ mkdir -p docs/business-analyse/v1.0
329
+ docs_dir = "docs/business-analyse/v{version}"
330
+
331
+ ELSE IF workflow_type = "new":
215
332
  mkdir -p docs/business/{application_name}/business-analyse/v1.0
333
+ docs_dir = "docs/business/{app}/business-analyse/v{version}"
334
+
216
335
  ELSE:
217
336
  Directory already exists from ba-writer.createVersion()
218
337
  ```
219
338
 
220
339
  **Store:**
221
340
  ```yaml
222
- docs_dir: "docs/business/{app}/business-analyse/v{version}"
341
+ docs_dir: string
223
342
  ```
224
343
 
225
344
  ## Step 8: Deploy JSON Schemas to Project (MANDATORY)
@@ -272,34 +391,67 @@ See [references/cache-warming-strategy.md](../references/cache-warming-strategy.
272
391
  Create the master feature document using ba-writer agent.
273
392
 
274
393
  ```
275
- ba-writer.createApplicationFeature({
276
- id: {feature_id},
277
- version: {version},
278
- scope: "application",
279
- status: "draft",
280
- metadata: {
281
- application: {application_name},
282
- context: "business",
283
- language: {language},
284
- featureDescription: {feature_description},
285
- workflowType: {workflow_type},
286
- analysisMode: "interactive",
287
- mcpAvailable: true,
288
- workflow: {
289
- mode: "application",
290
- moduleOrder: [],
291
- currentModuleIndex: 0,
292
- completedModules: [],
293
- currentModule: null
394
+ IF workflow_mode = "project":
395
+ // PROJECT MODE: Create project-level feature.json
396
+ ba-writer.createProjectFeature({
397
+ id: generate_project_id(), // PROJ-NNN
398
+ version: {version},
399
+ scope: "project",
400
+ status: "draft",
401
+ metadata: {
402
+ projectName: {project_name},
403
+ language: {language},
404
+ featureDescription: {feature_description},
405
+ workflowType: {workflow_type},
406
+ analysisMode: "interactive",
407
+ mcpAvailable: true,
408
+ candidateApplications: {candidate_applications}, // From step 3b detection
409
+ sharedModulesExtracted: {shared_modules_extracted},
410
+ workflow: {
411
+ mode: "project",
412
+ applicationOrder: [],
413
+ currentApplicationIndex: 0,
414
+ completedApplications: []
415
+ }
294
416
  }
295
- }
296
- })
297
- ```
417
+ })
418
+
419
+ Output path: docs/business-analyse/v{version}/feature.json
298
420
 
299
- **Output path:**
300
- `docs/business/{app}/business-analyse/v{version}/feature.json`
421
+ Store:
422
+ project_id: string // PROJ-NNN
423
+ feature_id: project_id // In project mode, feature_id = project_id for step-01
301
424
 
302
- > **Note:** Always create the master feature.json first. Step-02 (decomposition) determines if it's single or multi-module.
425
+ ELSE:
426
+ // SINGLE-APP MODE: Create application-level feature.json
427
+ ba-writer.createApplicationFeature({
428
+ id: {feature_id},
429
+ version: {version},
430
+ scope: "application",
431
+ status: "draft",
432
+ metadata: {
433
+ application: {application_name},
434
+ context: "business",
435
+ language: {language},
436
+ featureDescription: {feature_description},
437
+ workflowType: {workflow_type},
438
+ analysisMode: "interactive",
439
+ mcpAvailable: true,
440
+ workflow: {
441
+ mode: "application",
442
+ moduleOrder: [],
443
+ currentModuleIndex: 0,
444
+ completedModules: [],
445
+ currentModule: null
446
+ }
447
+ }
448
+ })
449
+
450
+ Output path: docs/business/{app}/business-analyse/v{version}/feature.json
451
+ ```
452
+
453
+ > **Note:** In project mode, per-application feature.json files are created later in step-01b.
454
+ > In single-app mode, step-02 (decomposition) determines if it's single or multi-module.
303
455
 
304
456
  ## Step 10: Update Config
305
457
 
@@ -330,13 +482,18 @@ Update `.business-analyse/config.json` with new feature information.
330
482
  |--------------------|----------------------------------------------|
331
483
  | Feature ID | {feature_id} |
332
484
  | Workflow | {workflow_type} |
333
- | Application | business/{application_name} |
485
+ | Mode | {workflow_mode === "project" ? "Multi-application project" : "Single application"} |
486
+ | Application/Project| {workflow_mode === "project" ? project_name + " (" + candidate_applications.length + " apps)" : "business/" + application_name} |
334
487
  | Output Path | {docs_dir}/feature.json |
335
488
  | Language | {language} |
336
489
  | Version | {version} |
337
490
  | MCP Available | true |
338
491
  | Analysis Mode | Interactive (always) |
339
492
 
493
+ {workflow_mode === "project"
494
+ ? "Candidate applications: " + candidate_applications.map(a => a.name).join(", ")
495
+ : ""}
496
+
340
497
  NEXT STEP: step-01-cadrage
341
498
  ═══════════════════════════════════════════════════════════════
342
499
  ```
@@ -347,14 +504,18 @@ After showing initialization summary, proceed to `./step-01-cadrage.md`
347
504
 
348
505
  **Pass context variables:**
349
506
  ```yaml
350
- feature_id: string
507
+ feature_id: string # FEAT-NNN (single-app) or PROJ-NNN (project)
351
508
  feature_description: string
352
509
  workflow_type: "new" | "update"
353
- application_name: string
510
+ workflow_mode: "application" | "project"
511
+ application_name: string # Single-app: app name. Project: project name.
512
+ applicationCode: string # PascalCase derived from application_name (preliminary, confirmed in step-01b)
513
+ project_id: string | null # PROJ-NNN if project mode, null if single-app
514
+ candidate_applications: array | null # Pre-identified apps from prompt (project mode only)
515
+ shared_modules_extracted: boolean # True if user chose to extract shared modules as new app
354
516
  language: string
355
517
  docs_dir: string
356
518
  mcp_available: boolean
357
- workflow_mode: "application"
358
519
  analysisMode: "interactive"
359
520
  version: string
360
521
  ```
@@ -372,9 +533,11 @@ version: string
372
533
 
373
534
  If initialization was interrupted:
374
535
 
375
- 1. Check `.business-analyse/config.json` for currentFeature
376
- 2. If feature ID exists, search for feature.json in `docs/business/`
377
- 3. If found, check status and `metadata.workflow.lastCompletedStep`:
536
+ 1. Check `.business-analyse/config.json` for currentFeature or currentProject
537
+ 2. If project ID exists, search for project feature.json in `docs/business-analyse/`
538
+ - If found with scope = "project": resume project mode (see Project Resume below)
539
+ 3. If feature ID exists, search for feature.json in `docs/business/`, `docs/platform/`, `docs/personal/`
540
+ 4. If found, check status and `metadata.workflow.lastCompletedStep`:
378
541
 
379
542
  **Status-based resume routing (check in this order):**
380
543
 
@@ -401,3 +564,22 @@ If initialization was interrupted:
401
564
  - Otherwise: offer to resume from last completed step
402
565
 
403
566
  4. If not found, create fresh feature.json
567
+
568
+ **Project Resume (project mode):**
569
+
570
+ If a project-level feature.json is found (scope = "project"):
571
+
572
+ - If status = `"draft"` or `"framed"`:
573
+ → Resume at `step-01-cadrage.md` or `step-01b-applications.md`
574
+
575
+ - If status = `"decomposed"`:
576
+ → Check `metadata.workflow.currentApplicationIndex` and `completedApplications[]`
577
+ → Resume module specification for current application (step-02 or step-03)
578
+
579
+ - If status = `"specified"`:
580
+ → All applications specified → Resume at `step-04a-collect.md`
581
+
582
+ - If status = `"consolidated"`:
583
+ → Resume at `step-05a-handoff.md`
584
+
585
+ Follow `_module-loop.md` "Project Mode (multi app)" resume logic for detailed routing.
@@ -41,14 +41,31 @@ Phase 5: PERIMETRE → Bound scope with roles, coverage matrix (sections
41
41
 
42
42
  ---
43
43
 
44
+ ## PROJECT vs APPLICATION MODE
45
+
46
+ > **When `workflow_mode = "project"` (detected in step-00 from prompt structure):**
47
+ > The cadrage operates at the **PROJECT level**, not at a single application level.
48
+ > - Phase 1-3: Gather requirements for the ENTIRE project (all applications combined)
49
+ > - Phase 4: ANTICIPATION analyzes cross-application shared modules and suggests extracting them as dedicated applications
50
+ > - Phase 5: Coverage matrix maps requirements to APPLICATIONS first, then modules within each application
51
+ > - `candidate_applications` from step-00 are used as starting structure (can be modified during cadrage)
52
+ >
53
+ > **When `workflow_mode = "application"` (single-app):**
54
+ > The cadrage operates at the application level as before.
55
+
44
56
  ## PHASE 1: ECOUTE (Listen)
45
57
 
46
58
  ### 1. Read Current State
47
59
 
48
60
  ```
49
- ba-reader.findFeature({feature_id})
50
- → Read metadata: application, language, workflow.mode, useCase
51
- → Read cadrage section (if resuming)
61
+ IF workflow_mode === "project":
62
+ ba-reader.findProjectFeature({project_id})
63
+ → Read metadata: projectName, language, candidateApplications
64
+ → Read cadrage section (if resuming)
65
+ ELSE:
66
+ ba-reader.findFeature({feature_id})
67
+ → Read metadata: application, language, workflow.mode, useCase
68
+ → Read cadrage section (if resuming)
52
69
  ```
53
70
 
54
71
  IF cadrage already completed (status = "framed"):
@@ -507,6 +524,91 @@ options:
507
524
 
508
525
  6. Accepted suggestions enrich `coverageMatrix` and `globalScope`.
509
526
 
527
+ ### 5b. Cross-Application Shared Module Detection (PROJECT MODE ONLY)
528
+
529
+ > **When `workflow_mode = "project"`, analyze candidate applications for shared modules.**
530
+ > A module that appears in 2+ applications should be extracted as a dedicated transversal application.
531
+
532
+ **This section is SKIPPED if `workflow_mode !== "project"`.**
533
+
534
+ **Process:**
535
+
536
+ 1. Build module inventory per candidate application:
537
+
538
+ ```javascript
539
+ // From candidateApplications (step-00) + enriched by cadrage phases 1-4
540
+ const modulesByApp = {};
541
+ for (const app of candidate_applications) {
542
+ modulesByApp[app.name] = app.modules; // e.g., { "RH": ["Employes", "Conges", "Temps"], "Projet": ["Projets", "Temps"] }
543
+ }
544
+ ```
545
+
546
+ 2. Detect modules appearing in 2+ applications:
547
+
548
+ ```javascript
549
+ const allModules = Object.values(modulesByApp).flat();
550
+ const moduleCounts = {};
551
+ for (const mod of allModules) {
552
+ const normalized = normalizeModuleName(mod); // "Temps", "Saisie du temps", "Time Tracking" → same concept
553
+ moduleCounts[normalized] = (moduleCounts[normalized] || 0) + 1;
554
+ }
555
+ const sharedModules = Object.entries(moduleCounts)
556
+ .filter(([_, count]) => count >= 2)
557
+ .map(([name, count]) => ({ name, appearsIn: count, applications: findAppsContaining(name) }));
558
+ ```
559
+
560
+ 3. IF shared modules found, propose extraction:
561
+
562
+ ```
563
+ {language == "fr"
564
+ ? "### Modules partagés détectés\n\nCertains modules apparaissent dans plusieurs applications. Les extraire en application(s) dédiée(s) améliore la réutilisabilité et évite la duplication :"
565
+ : "### Shared modules detected\n\nSome modules appear in multiple applications. Extracting them as dedicated application(s) improves reusability and avoids duplication:"}
566
+
567
+ | Module | Présent dans | Suggestion |
568
+ |--------|-------------|-----------|
569
+ {for each shared: name | apps.join(", ") | "Extraire en application '{name}'" }
570
+
571
+ {language == "fr"
572
+ ? "**Exemple :** Si 'Gestion du temps' est dans RH et Projet, créer une application 'Temps' dédiée que les deux autres consomment."
573
+ : "**Example:** If 'Time Management' is in HR and Project, create a dedicated 'Time' application that the other two consume."}
574
+ ```
575
+
576
+ Ask via AskUserQuestion:
577
+ ```
578
+ question: "{language == 'fr' ? 'Souhaitez-vous extraire les modules partagés en application(s) dédiée(s) ?' : 'Do you want to extract shared modules as dedicated application(s)?'}"
579
+ header: "Extraction"
580
+ options:
581
+ - label: "{language == 'fr' ? 'Oui, extraire' : 'Yes, extract'}"
582
+ description: "{language == 'fr' ? 'Créer {sharedModules.length} application(s) transversale(s) supplémentaire(s)' : 'Create {sharedModules.length} additional cross-cutting application(s)'}"
583
+ - label: "{language == 'fr' ? 'Non, garder en l\'état' : 'No, keep as-is'}"
584
+ description: "{language == 'fr' ? 'Chaque application garde sa propre version du module' : 'Each application keeps its own version of the module'}"
585
+ ```
586
+
587
+ **IF "Oui, extraire":**
588
+ ```javascript
589
+ for (const shared of sharedModules) {
590
+ // Create new candidate application
591
+ candidate_applications.push({
592
+ name: shared.name,
593
+ description: `Application transversale pour ${shared.name}`,
594
+ modules: [shared.name],
595
+ context: "business",
596
+ isTransversal: true,
597
+ consumedBy: shared.applications
598
+ });
599
+
600
+ // Remove the shared module from original applications
601
+ for (const appName of shared.applications) {
602
+ const app = candidate_applications.find(a => a.name === appName);
603
+ app.modules = app.modules.filter(m => normalizeModuleName(m) !== shared.name);
604
+ app.dependencies = app.dependencies || [];
605
+ app.dependencies.push({ target: shared.name, type: "data-dependency" });
606
+ }
607
+ }
608
+ ```
609
+
610
+ Update `candidate_applications` in the project feature.json.
611
+
510
612
  ---
511
613
 
512
614
  ## PHASE 5: PERIMETRE (Bound Scope)
@@ -720,7 +822,82 @@ ba-writer.enrichSection({
720
822
  ba-writer.updateStatus({feature_id}, "framed")
721
823
  ```
722
824
 
723
- ### 9. Display Summary
825
+ ### 9. Multi-Application Detection
826
+
827
+ > **Analyze whether the project spans multiple independent applications.**
828
+ > **SKIP this section entirely if `workflow_mode = "project"`** — multi-app was already detected in step-00
829
+ > and cross-app analysis was done in section 5b above.
830
+
831
+ **IF `workflow_mode === "project"`:**
832
+ → SKIP section 9 entirely. Candidate applications are already identified and enriched.
833
+ → Write cadrage data to project-level feature.json:
834
+ ```
835
+ ba-writer.enrichSection({
836
+ projectId: {project_id},
837
+ section: "cadrage",
838
+ data: {cadrage data collected in phases 1-5 above}
839
+ })
840
+ ```
841
+ → Continue to section 10 (summary).
842
+
843
+ **IF `workflow_mode === "application"` (single-app mode):**
844
+
845
+ After coverage matrix is validated, check if the identified functional domains suggest multiple applications:
846
+
847
+ **Detection triggers (ANY of these = suggest multi-app):**
848
+ - Coverage matrix entries reference different navigation contexts (business + personal + platform)
849
+ - User mentioned "multiple applications", "several apps", "cross-platform"
850
+ - Functional domains form clearly independent applications with separate user bases
851
+ - Stakeholders only interact with specific domains (not shared across all)
852
+
853
+ **IF detection triggers matched:**
854
+
855
+ Display analysis as markdown:
856
+ ```
857
+ {language == "fr"
858
+ ? "### Analyse multi-application\n\nD'après mon analyse, ce projet couvre plusieurs domaines fonctionnels qui pourraient former des applications indépendantes :\n\n"
859
+ : "### Multi-Application Analysis\n\nBased on my analysis, this project spans multiple functional domains that could form independent applications:\n\n"}
860
+
861
+ | Domain | Suggested Context | Suggested Application | Key Modules |
862
+ |--------|-------------------|----------------------|-------------|
863
+ {for each identified domain: domain name | business/platform/personal | PascalCase name | top modules}
864
+ ```
865
+
866
+ Ask via AskUserQuestion:
867
+ ```
868
+ question: "{language == 'fr' ? 'Ce projet constitue-t-il une seule application ou plusieurs applications distinctes ?' : 'Is this a single application or multiple independent applications?'}"
869
+ header: "Architecture"
870
+ options:
871
+ - label: "{language == 'fr' ? 'Application unique' : 'Single application'}"
872
+ description: "{language == 'fr' ? 'Tous les domaines forment une seule application avec plusieurs modules' : 'All domains form one application with multiple modules'}"
873
+ - label: "{language == 'fr' ? 'Applications multiples' : 'Multiple applications'}"
874
+ description: "{language == 'fr' ? 'Chaque domaine est une application indépendante (navigation, rôles et préfixe de table séparés)' : 'Each domain is an independent application (separate navigation, roles, and table prefix)'}"
875
+ ```
876
+
877
+ **IF "Multiple applications":**
878
+ 1. Create project-level feature.json:
879
+ ```
880
+ ba-writer.createProjectFeature({
881
+ metadata: {
882
+ projectName: {project_name derived from feature_description},
883
+ language: {language},
884
+ featureDescription: {feature_description},
885
+ candidateApplications: [{detected candidates}]
886
+ },
887
+ cadrage: {cadrage data already collected in this step}
888
+ })
889
+ ```
890
+ 2. Set `workflow_mode = "project"` and `project_id = PROJ-NNN`
891
+ 3. Load `questionnaire/00b-project.md` for additional project-level questions
892
+ 4. Continue to section 10 and then step-01b
893
+
894
+ **IF "Single application":**
895
+ → Continue to step 10 (display summary) and step-02 as usual.
896
+
897
+ **IF no detection triggers matched:**
898
+ → Skip this section entirely — continue to step 10 (display summary).
899
+
900
+ ### 10. Display Summary
724
901
 
725
902
  ```
726
903
  ## Cadrage Complete - {feature_id}
@@ -748,4 +925,6 @@ ba-writer.updateStatus({feature_id}, "framed")
748
925
 
749
926
  ## NEXT STEP
750
927
 
751
- Load: `./step-02-decomposition.md`
928
+ Load: `./step-01b-applications.md`
929
+
930
+ > step-01b handles both single-app (lightweight identity confirmation) and multi-app (full application decomposition).