@atlashub/smartstack-cli 3.32.0 → 3.34.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 +5 -1
- package/.documentation/installation.html +5 -1
- package/.documentation/ralph-loop.html +365 -216
- package/.documentation/test-web.html +5 -1
- package/package.json +1 -1
- package/templates/agents/ba-writer.md +142 -15
- package/templates/skills/apex/SKILL.md +7 -1
- 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 +238 -3
- package/templates/skills/apex/references/smartstack-api.md +47 -7
- package/templates/skills/apex/references/smartstack-frontend.md +47 -1
- package/templates/skills/apex/references/smartstack-layers.md +3 -1
- package/templates/skills/apex/steps/step-00-init.md +48 -1
- package/templates/skills/apex/steps/step-01-analyze.md +37 -0
- package/templates/skills/apex/steps/step-02-plan.md +36 -0
- package/templates/skills/apex/steps/step-03-execute.md +42 -2
- package/templates/skills/apex/steps/step-04-examine.md +110 -2
- package/templates/skills/business-analyse/SKILL.md +29 -19
- package/templates/skills/business-analyse/_module-loop.md +68 -9
- package/templates/skills/business-analyse/_shared.md +71 -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 +2 -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 +30 -4
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +62 -2
- package/templates/skills/business-analyse/steps/step-01b-applications.md +252 -0
- package/templates/skills/business-analyse/steps/step-02-decomposition.md +23 -6
- package/templates/skills/business-analyse/steps/step-03d-validate.md +27 -6
- 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 +9 -17
- package/templates/skills/ralph-loop/references/category-rules.md +43 -692
- package/templates/skills/ralph-loop/references/compact-loop.md +104 -427
- package/templates/skills/ralph-loop/references/team-orchestration.md +13 -14
- package/templates/skills/ralph-loop/steps/step-02-execute.md +49 -704
- 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 +12 -123
|
@@ -32,8 +32,20 @@ Build the development handoff data: verify consolidation, choose implementation
|
|
|
32
32
|
Use ba-reader to locate the feature and verify consolidation status:
|
|
33
33
|
|
|
34
34
|
```
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
// Determine feature source based on workflow mode
|
|
36
|
+
IF workflow.mode === "project":
|
|
37
|
+
projectFeature = ba-reader.findProjectFeature()
|
|
38
|
+
// Verify ALL applications are specified
|
|
39
|
+
FOR each app in projectFeature.applications:
|
|
40
|
+
appFeature = ba-reader.findFeature(app.featureJsonPath)
|
|
41
|
+
IF appFeature.status !== "consolidated":
|
|
42
|
+
BLOCKING ERROR: "Application {app.code} not consolidated (status: {appFeature.status})"
|
|
43
|
+
→ Return to step-04a-collect.md
|
|
44
|
+
// Use project-level feature for overall consolidation
|
|
45
|
+
feature = projectFeature
|
|
46
|
+
ELSE:
|
|
47
|
+
ba-reader.findFeature({feature_id})
|
|
48
|
+
→ Check status = "consolidated"
|
|
37
49
|
```
|
|
38
50
|
|
|
39
51
|
**IF** status ≠ "consolidated" → **STOP**. Return to step-04a-collect.md.
|
|
@@ -42,18 +54,22 @@ Display validation summary:
|
|
|
42
54
|
|
|
43
55
|
```
|
|
44
56
|
✓ Consolidation: APPROVED
|
|
57
|
+
✓ Applications: {app_count} (project mode only)
|
|
45
58
|
✓ Modules: {count} specified and validated
|
|
46
59
|
✓ Cross-module: interactions mapped
|
|
60
|
+
✓ Cross-application: interactions mapped (project mode only)
|
|
47
61
|
✓ Permissions: coherent
|
|
48
62
|
→ Proceeding to handoff...
|
|
49
63
|
```
|
|
50
64
|
|
|
51
65
|
Include:
|
|
52
|
-
- Number of
|
|
66
|
+
- Number of applications (project mode only)
|
|
67
|
+
- Number of modules across all applications
|
|
53
68
|
- Number of entities across all modules
|
|
54
69
|
- Number of use cases across all modules
|
|
55
70
|
- Number of business rules across all modules
|
|
56
71
|
- Cross-module interaction count
|
|
72
|
+
- Cross-application interaction count (project mode only)
|
|
57
73
|
|
|
58
74
|
---
|
|
59
75
|
|
|
@@ -101,9 +117,9 @@ See [references/cache-warming-strategy.md](../references/cache-warming-strategy.
|
|
|
101
117
|
|
|
102
118
|
---
|
|
103
119
|
|
|
104
|
-
### 2. Implementation Strategy Choice (Multi-Module)
|
|
120
|
+
### 2. Implementation Strategy Choice (Multi-Module/Multi-App)
|
|
105
121
|
|
|
106
|
-
**IF** more than 1 module defined in feature.json:
|
|
122
|
+
**IF** more than 1 module defined in feature.json (or project mode with multiple applications):
|
|
107
123
|
|
|
108
124
|
Ask via AskUserQuestion:
|
|
109
125
|
|
|
@@ -117,8 +133,12 @@ options:
|
|
|
117
133
|
description: "Implémenter toutes les entités, puis tous les services, puis tous les contrôleurs, etc. Plus de parallélisation possible mais plus complexe."
|
|
118
134
|
- label: "Hybride"
|
|
119
135
|
description: "Modules fondation en premier (couche par couche), puis modules dépendants (module par module)"
|
|
136
|
+
- label: "Application par application (Recommandé multi-app)"
|
|
137
|
+
description: "Implémenter chaque application complètement avant de passer à la suivante. Suit l'ordre topologique inter-applications."
|
|
120
138
|
```
|
|
121
139
|
|
|
140
|
+
> **Note:** "Application par application" only appears for project mode with 2+ applications.
|
|
141
|
+
|
|
122
142
|
Store the chosen strategy in `handoff.implementationStrategy`.
|
|
123
143
|
|
|
124
144
|
**IF** only 1 module → default to "Module par module" (no choice needed).
|
|
@@ -335,6 +355,31 @@ Generate `.ralph/prd-CrossModule.json` with:
|
|
|
335
355
|
|
|
336
356
|
Add to progress.txt after all module tasks.
|
|
337
357
|
|
|
358
|
+
### 6d. Cross-Application PRD (Project Mode Only)
|
|
359
|
+
|
|
360
|
+
> **Only generated when `workflow.mode === "project"`.**
|
|
361
|
+
> Contains cross-application integration tests and shared entity validation.
|
|
362
|
+
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"$version": "3.0.0",
|
|
366
|
+
"implementation": {
|
|
367
|
+
"filesToCreate": {
|
|
368
|
+
"tests": [
|
|
369
|
+
{ "path": "src/Tests/Integration/CrossApplication/SharedEntityValidationTests.cs", "type": "IntegrationTests", "module": "CrossApplication" },
|
|
370
|
+
{ "path": "src/Tests/Integration/CrossApplication/CrossAppPermissionTests.cs", "type": "SecurityTests", "module": "CrossApplication" },
|
|
371
|
+
{ "path": "src/Tests/Integration/CrossApplication/CrossAppE2EFlowTests.cs", "type": "E2ETests", "module": "CrossApplication" }
|
|
372
|
+
]
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Write to: `.ralph/prd-CrossApplication.json`
|
|
379
|
+
|
|
380
|
+
> This PRD is generated IN ADDITION to the per-module cross-module PRD.
|
|
381
|
+
> It validates interactions between applications, not just between modules within the same application.
|
|
382
|
+
|
|
338
383
|
---
|
|
339
384
|
|
|
340
385
|
### 7. Write Handoff to Feature.json
|
|
@@ -434,53 +479,119 @@ const lang = master.metadata.language || "fr";
|
|
|
434
479
|
|
|
435
480
|
const seedDataCore = {
|
|
436
481
|
// Application-level navigation (MANDATORY — one entry per application)
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
:
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
482
|
+
// PROJECT MODE: Generate one entry per application from project feature.json
|
|
483
|
+
// SINGLE-APP MODE: Generate one entry from master feature.json
|
|
484
|
+
navigationApplications: (() => {
|
|
485
|
+
if (workflow.mode === "project") {
|
|
486
|
+
// Multi-app: one navigation entry per application
|
|
487
|
+
return projectFeature.applications.map((app, idx) => {
|
|
488
|
+
const appLabel = toHumanReadable(app.code);
|
|
489
|
+
const appContext = app.context || "business";
|
|
490
|
+
return {
|
|
491
|
+
code: app.code.toLowerCase(),
|
|
492
|
+
name: app.code,
|
|
493
|
+
labels: {
|
|
494
|
+
fr: lang === "fr" ? (app.name || appLabel) : appLabel,
|
|
495
|
+
en: lang === "en" ? (app.name || appLabel) : appLabel,
|
|
496
|
+
it: appLabel,
|
|
497
|
+
de: appLabel
|
|
498
|
+
},
|
|
499
|
+
description: {
|
|
500
|
+
fr: lang === "fr" ? (app.description || `Gestion ${appLabel}`) : `Gestion ${appLabel}`,
|
|
501
|
+
en: lang === "en" ? (app.description || `${appLabel} management`) : `${appLabel} management`,
|
|
502
|
+
it: `Gestione ${appLabel}`,
|
|
503
|
+
de: `${appLabel} Verwaltung`
|
|
504
|
+
},
|
|
505
|
+
icon: app.icon || inferIconFromApplication({ metadata: { application: app.code } }) || "layout-grid",
|
|
506
|
+
iconType: "lucide",
|
|
507
|
+
context: appContext,
|
|
508
|
+
route: `/${appContext}/${toKebabCase(app.code)}`,
|
|
509
|
+
displayOrder: (idx + 1) * 10
|
|
510
|
+
};
|
|
511
|
+
});
|
|
512
|
+
} else {
|
|
513
|
+
// Single-app: one navigation entry
|
|
514
|
+
return [{
|
|
515
|
+
code: appCode.toLowerCase(),
|
|
516
|
+
name: appCode,
|
|
517
|
+
labels: {
|
|
518
|
+
fr: lang === "fr" ? (master.cadrage?.applicationName || appLabel) : appLabel,
|
|
519
|
+
en: lang === "en" ? (master.cadrage?.applicationName || appLabel) : appLabel,
|
|
520
|
+
it: appLabel,
|
|
521
|
+
de: appLabel
|
|
522
|
+
},
|
|
523
|
+
description: {
|
|
524
|
+
fr: lang === "fr" ? appDesc : `Gestion ${appLabel}`,
|
|
525
|
+
en: lang === "en" ? appDesc : `${appLabel} management`,
|
|
526
|
+
it: `Gestione ${appLabel}`,
|
|
527
|
+
de: `${appLabel} Verwaltung`
|
|
528
|
+
},
|
|
529
|
+
icon: inferIconFromApplication(master) || "layout-grid",
|
|
530
|
+
iconType: "lucide",
|
|
531
|
+
context: contextCode,
|
|
532
|
+
route: `/${contextCode}/${toKebabCase(appCode)}`,
|
|
533
|
+
displayOrder: 1
|
|
534
|
+
}];
|
|
535
|
+
}
|
|
536
|
+
})(),
|
|
537
|
+
|
|
538
|
+
// PROJECT MODE: Flatten modules from ALL applications
|
|
539
|
+
// SINGLE-APP MODE: Use master.modules directly
|
|
540
|
+
navigationModules: (() => {
|
|
541
|
+
if (workflow.mode === "project") {
|
|
542
|
+
let order = 0;
|
|
543
|
+
return projectFeature.applications.flatMap(app => {
|
|
544
|
+
const appContext = app.context || "business";
|
|
545
|
+
return (app.modules || []).map(m => ({
|
|
546
|
+
code: m.code,
|
|
547
|
+
applicationCode: app.code,
|
|
548
|
+
label: m.name || m.code,
|
|
549
|
+
description: m.description,
|
|
550
|
+
icon: inferIconFromModule(m) || "folder",
|
|
551
|
+
iconType: "lucide",
|
|
552
|
+
route: `/${appContext}/${toKebabCase(app.code)}/${toKebabCase(m.code)}`,
|
|
553
|
+
displayOrder: (++order) * 10
|
|
554
|
+
}));
|
|
555
|
+
});
|
|
556
|
+
} else {
|
|
557
|
+
return master.modules.map((m, i) => ({
|
|
558
|
+
code: m.code,
|
|
559
|
+
label: m.name || m.code,
|
|
560
|
+
description: m.description,
|
|
561
|
+
icon: inferIconFromModule(m) || "folder",
|
|
562
|
+
iconType: "lucide",
|
|
563
|
+
route: `/${contextCode}/${toKebabCase(appCode)}/${toKebabCase(m.code)}`,
|
|
564
|
+
displayOrder: (i + 1) * 10
|
|
565
|
+
}));
|
|
566
|
+
}
|
|
567
|
+
})(),
|
|
568
|
+
|
|
569
|
+
navigationSections: (() => {
|
|
570
|
+
const buildSections = (modules, appContextCode, appCode) =>
|
|
571
|
+
modules.flatMap(m =>
|
|
572
|
+
(m.anticipatedSections || []).map((s, j) => ({
|
|
573
|
+
moduleCode: m.code,
|
|
574
|
+
code: s.code,
|
|
575
|
+
label: s.description?.split(':')[0] || s.code,
|
|
576
|
+
description: s.description || "",
|
|
577
|
+
route: s.code === "list"
|
|
578
|
+
? `/${appContextCode}/${toKebabCase(appCode)}/${toKebabCase(m.code)}`
|
|
579
|
+
: s.code === "detail"
|
|
580
|
+
? `/${appContextCode}/${toKebabCase(appCode)}/${toKebabCase(m.code)}/:id`
|
|
581
|
+
: `/${appContextCode}/${toKebabCase(appCode)}/${toKebabCase(m.code)}/${toKebabCase(s.code)}`,
|
|
582
|
+
displayOrder: (j + 1) * 10,
|
|
583
|
+
navigation: s.code === "detail" ? "hidden" : "visible"
|
|
584
|
+
}))
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
if (workflow.mode === "project") {
|
|
588
|
+
return projectFeature.applications.flatMap(app =>
|
|
589
|
+
buildSections(app.modules || [], app.context || "business", app.code)
|
|
590
|
+
);
|
|
591
|
+
} else {
|
|
592
|
+
return buildSections(master.modules, contextCode, appCode);
|
|
593
|
+
}
|
|
594
|
+
})(),
|
|
484
595
|
|
|
485
596
|
navigationResources: master.cadrage.coverageMatrix
|
|
486
597
|
.filter(cm => cm.module && cm.anticipatedResources?.length > 0)
|
|
@@ -504,37 +615,73 @@ const seedDataCore = {
|
|
|
504
615
|
}));
|
|
505
616
|
}),
|
|
506
617
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
618
|
+
// PROJECT MODE: permissions scoped per application context
|
|
619
|
+
// SINGLE-APP MODE: all permissions under business.{app}
|
|
620
|
+
permissions: (() => {
|
|
621
|
+
const buildPermissions = (modules, appContext, appCode) =>
|
|
622
|
+
modules.flatMap(m => {
|
|
623
|
+
const basePath = `${appContext}.${toKebabCase(appCode)}.${toKebabCase(m.code)}`;
|
|
624
|
+
const actions = ['read', 'create', 'update', 'delete'];
|
|
625
|
+
return [
|
|
626
|
+
{ path: `${basePath}.*`, action: '*', description: `Full ${m.name || m.code} access` },
|
|
627
|
+
...actions.map(action => ({
|
|
628
|
+
path: `${basePath}.${action}`,
|
|
629
|
+
action: action,
|
|
630
|
+
description: `${action.charAt(0).toUpperCase() + action.slice(1)} ${m.name || m.code}`
|
|
631
|
+
}))
|
|
632
|
+
];
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
if (workflow.mode === "project") {
|
|
636
|
+
return projectFeature.applications.flatMap(app =>
|
|
637
|
+
buildPermissions(app.modules || [], app.context || "business", app.code)
|
|
638
|
+
);
|
|
639
|
+
} else {
|
|
640
|
+
return buildPermissions(master.modules, contextCode, appCode);
|
|
641
|
+
}
|
|
642
|
+
})(),
|
|
643
|
+
|
|
644
|
+
rolePermissions: (() => {
|
|
645
|
+
const buildRolePermissions = (roles, modules, appContext, appCode) =>
|
|
646
|
+
roles.map(role => ({
|
|
647
|
+
role: role.role,
|
|
648
|
+
level: role.level,
|
|
649
|
+
permissions: modules.map(m => `${appContext}.${toKebabCase(appCode)}.${toKebabCase(m.code)}.${
|
|
650
|
+
role.level === 'admin' ? '*' :
|
|
651
|
+
role.level === 'manager' ? 'read,create,update' :
|
|
652
|
+
role.level === 'contributor' ? 'read,create' : 'read'
|
|
653
|
+
}`)
|
|
654
|
+
}));
|
|
655
|
+
|
|
656
|
+
if (workflow.mode === "project") {
|
|
657
|
+
return projectFeature.applications.flatMap(app =>
|
|
658
|
+
buildRolePermissions(app.applicationRoles || [], app.modules || [], app.context || "business", app.code)
|
|
659
|
+
);
|
|
660
|
+
} else {
|
|
661
|
+
return buildRolePermissions(master.cadrage.applicationRoles, master.modules, contextCode, appCode);
|
|
662
|
+
}
|
|
663
|
+
})(),
|
|
664
|
+
|
|
665
|
+
permissionConstants: (() => {
|
|
666
|
+
const buildConstants = (modules, appCode) =>
|
|
667
|
+
modules.flatMap(m =>
|
|
668
|
+
['Read', 'Create', 'Update', 'Delete', 'Validate', 'Export'].map(action => ({
|
|
669
|
+
module: m.code,
|
|
670
|
+
application: appCode,
|
|
671
|
+
action: action,
|
|
672
|
+
constant: `${appCode}${m.code}${action}`,
|
|
673
|
+
path: `${contextCode}.${toKebabCase(appCode)}.${toKebabCase(m.code)}.${action.toLowerCase()}`
|
|
674
|
+
}))
|
|
675
|
+
);
|
|
676
|
+
|
|
677
|
+
if (workflow.mode === "project") {
|
|
678
|
+
return projectFeature.applications.flatMap(app =>
|
|
679
|
+
buildConstants(app.modules || [], app.code)
|
|
680
|
+
);
|
|
681
|
+
} else {
|
|
682
|
+
return buildConstants(master.modules, appCode);
|
|
683
|
+
}
|
|
684
|
+
})()
|
|
538
685
|
};
|
|
539
686
|
|
|
540
687
|
// Icon inference for APPLICATION level (NEVER leave as null)
|
|
@@ -609,26 +756,72 @@ IF seedDataCore.navigationSections.length === 0:
|
|
|
609
756
|
#### 7c. Master Handoff (after ALL modules written + seedDataCore generated)
|
|
610
757
|
|
|
611
758
|
```
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
}
|
|
759
|
+
// Write handoff to application-level feature.json (single-app mode)
|
|
760
|
+
// OR to each application feature.json + project feature.json (project mode)
|
|
761
|
+
|
|
762
|
+
IF workflow.mode === "project":
|
|
763
|
+
// Write handoff to EACH application feature.json
|
|
764
|
+
FOR each app in projectFeature.applications:
|
|
765
|
+
ba-writer.enrichSection({
|
|
766
|
+
featureId: app.featureJsonPath,
|
|
767
|
+
section: "handoff",
|
|
768
|
+
data: {
|
|
769
|
+
status: "handed-off",
|
|
770
|
+
complexity: "{app-level complexity}",
|
|
771
|
+
implementationStrategy: "{strategy}",
|
|
772
|
+
moduleCount: app.modules.length,
|
|
773
|
+
moduleOrder: app.modules.map(m => m.code),
|
|
774
|
+
totalFilesToCreate: {sum across app modules},
|
|
775
|
+
totalTasks: {sum across app modules},
|
|
776
|
+
prdFiles: app.modules.map(m => ({ module: m.code, path: `.ralph/prd-${m.code}.json` })),
|
|
777
|
+
handedOffAt: "{ISO timestamp}"
|
|
778
|
+
}
|
|
779
|
+
})
|
|
780
|
+
|
|
781
|
+
// Write project-level handoff summary
|
|
782
|
+
ba-writer.enrichSection({
|
|
783
|
+
featureId: {project_id},
|
|
784
|
+
section: "handoff",
|
|
785
|
+
data: {
|
|
786
|
+
status: "handed-off",
|
|
787
|
+
complexity: "{global complexity}",
|
|
788
|
+
implementationStrategy: "{strategy}",
|
|
789
|
+
applicationCount: projectFeature.applications.length,
|
|
790
|
+
applicationOrder: projectFeature.applicationDependencyGraph.topologicalOrder,
|
|
791
|
+
totalModuleCount: {sum of all app module counts},
|
|
792
|
+
totalFilesToCreate: {sum across ALL applications and modules},
|
|
793
|
+
totalTasks: {sum across ALL applications and modules},
|
|
794
|
+
prdStructure: "per-module",
|
|
795
|
+
prdFiles: [
|
|
796
|
+
...allModulePrdFiles,
|
|
797
|
+
{ module: "CrossModule", path: ".ralph/prd-CrossModule.json" },
|
|
798
|
+
{ module: "CrossApplication", path: ".ralph/prd-CrossApplication.json" }
|
|
799
|
+
],
|
|
800
|
+
progressTrackerPath: ".ralph/progress.txt",
|
|
801
|
+
handedOffAt: "{ISO timestamp}"
|
|
802
|
+
}
|
|
803
|
+
})
|
|
804
|
+
ELSE:
|
|
805
|
+
ba-writer.enrichSection({
|
|
806
|
+
featureId: {feature_id},
|
|
807
|
+
section: "handoff",
|
|
808
|
+
data: {
|
|
809
|
+
status: "handed-off",
|
|
810
|
+
complexity: "{simple|medium|complex}",
|
|
811
|
+
implementationStrategy: "{strategy}",
|
|
812
|
+
moduleCount: {count},
|
|
813
|
+
moduleOrder: [...],
|
|
814
|
+
totalFilesToCreate: {sum across all modules},
|
|
815
|
+
totalTasks: {sum across all modules},
|
|
816
|
+
prdStructure: "per-module | consolidated",
|
|
817
|
+
prdFiles: [
|
|
818
|
+
{ module: "{module1}", path: ".ralph/prd-{module1}.json" },
|
|
819
|
+
{ module: "{module2}", path: ".ralph/prd-{module2}.json" }
|
|
820
|
+
],
|
|
821
|
+
progressTrackerPath: ".ralph/progress.txt",
|
|
822
|
+
handedOffAt: "{ISO timestamp}"
|
|
823
|
+
}
|
|
824
|
+
})
|
|
632
825
|
```
|
|
633
826
|
|
|
634
827
|
#### 7d. Final Verification (BLOCKING)
|
|
@@ -176,21 +176,38 @@ IF ANY category shows FAIL → **STOP AND RE-RUN `ss derive-prd`**. DO NOT proce
|
|
|
176
176
|
**Update logic:**
|
|
177
177
|
|
|
178
178
|
1. Read existing manifest at `docs/business/index.json` (or create empty `{ "version": "1.0", "updatedAt": "", "analyses": [] }`)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
179
|
+
|
|
180
|
+
2. **PROJECT MODE (`workflow.mode === "project"`):**
|
|
181
|
+
a. Add/update PROJECT-level entry:
|
|
182
|
+
- Find existing entry where `projectId == {project_id}` AND `scope == "project"`
|
|
183
|
+
- If found: update `status`, `updatedAt`
|
|
184
|
+
- If not found: append new entry with `scope: "project"`, `projectId: "{project_id}"`, `path: "business-analyse/v{version}/feature.json"`
|
|
185
|
+
b. For EACH APPLICATION:
|
|
186
|
+
- Find existing entry where `appCode == {app_code}` AND `moduleCode == null` AND `version == {version}`
|
|
187
|
+
- If found: update `status`, `updatedAt`, `featureDescription`
|
|
188
|
+
- If not found: append new entry with `moduleCode: null`, `context: "{app.context}"`, and `path: "{context}/{app_code}/business-analyse/v{version}/feature.json"`
|
|
189
|
+
c. For EACH MODULE within each application:
|
|
190
|
+
- Find existing entry where `appCode == {app_code}` AND `moduleCode == {module_code}` AND `version == {version}`
|
|
191
|
+
- If found: update `status`, `updatedAt`, `featureDescription`
|
|
192
|
+
- If not found: append new entry with `path: "{context}/{app_code}/{module_code}/business-analyse/v{version}/feature.json"`
|
|
193
|
+
|
|
194
|
+
3. **SINGLE-APP MODE (default):**
|
|
195
|
+
a. For the APPLICATION-level feature.json:
|
|
196
|
+
- Find existing entry where `appCode == {app_code}` AND `moduleCode == null` AND `version == {version}`
|
|
197
|
+
- If found: update `status`, `updatedAt`, `featureDescription`
|
|
198
|
+
- If not found: append new entry with `moduleCode: null` and `path: "{app_code}/business-analyse/v{version}/feature.json"`
|
|
199
|
+
b. For EACH MODULE-level feature.json:
|
|
200
|
+
- Find existing entry where `appCode == {app_code}` AND `moduleCode == {module_code}` AND `version == {version}`
|
|
201
|
+
- If found: update `status`, `updatedAt`, `featureDescription`
|
|
202
|
+
- If not found: append new entry with `moduleCode: "{module_code}"` and `path: "{app_code}/{module_code}/business-analyse/v{version}/feature.json"`
|
|
203
|
+
|
|
187
204
|
4. Update root `updatedAt` to current timestamp
|
|
188
205
|
5. Write manifest back to `docs/business/index.json`
|
|
189
206
|
|
|
190
207
|
**Display confirmation:**
|
|
191
208
|
```
|
|
192
209
|
✓ BA manifest updated: docs/business/index.json
|
|
193
|
-
Entries: {total_count} ({app_count} applications, {module_count} modules)
|
|
210
|
+
Entries: {total_count} ({project_count} projects, {app_count} applications, {module_count} modules)
|
|
194
211
|
Web viewer: /system/docs/ba
|
|
195
212
|
```
|
|
196
213
|
|
|
@@ -205,20 +222,28 @@ IF ANY category shows FAIL → **STOP AND RE-RUN `ss derive-prd`**. DO NOT proce
|
|
|
205
222
|
### 4. Read Source Data for HTML
|
|
206
223
|
|
|
207
224
|
1. Read the HTML template from skill directory: `html/ba-interactive.html` (relative to `~/.claude/skills/business-analyse/`)
|
|
208
|
-
2. Read the master feature.json (application level)
|
|
209
|
-
3. Read
|
|
225
|
+
2. **SINGLE-APP MODE:** Read the master feature.json (application level)
|
|
226
|
+
3. **PROJECT MODE:** Read the project feature.json + ALL application feature.json files
|
|
227
|
+
4. Read EACH module feature.json (module level, across all applications in project mode)
|
|
210
228
|
|
|
211
229
|
> **Reference:** Read `references/html-data-mapping.md` for the complete FEATURE_DATA and EMBEDDED_ARTIFACTS mapping specification.
|
|
212
230
|
|
|
213
231
|
**Key requirements:**
|
|
214
232
|
- FEATURE_DATA must be pre-populated with ALL analysis data (empty data = BUG)
|
|
215
|
-
- FEATURE_DATA.**moduleSpecs** MUST be populated for EACH module (use cases, business rules, entities, permissions) — empty moduleSpecs = BROKEN specification tabs
|
|
233
|
+
- FEATURE_DATA.**moduleSpecs** MUST be populated for EACH module across ALL applications (use cases, business rules, entities, permissions) — empty moduleSpecs = BROKEN specification tabs
|
|
216
234
|
- FEATURE_DATA.**cadrage.scope** must use HTML keys (vital/important/optional/excluded) NOT feature.json keys (mustHave/shouldHave/couldHave/outOfScope)
|
|
217
235
|
- FEATURE_DATA.**metadata.analysisMode** must be set from `master.metadata.analysisMode` (always "interactive")
|
|
218
236
|
- EMBEDDED_ARTIFACTS contains wireframes, E2E diagrams, dependency graph
|
|
219
237
|
- Both objects are serialized as JSON with 2-space indentation
|
|
220
238
|
- All data mapped from master and module feature.json files — follow `html-data-mapping.md` EXACTLY
|
|
221
239
|
|
|
240
|
+
**PROJECT MODE additions to FEATURE_DATA:**
|
|
241
|
+
- `FEATURE_DATA.project` — project-level metadata (name, applicationCount, applicationOrder)
|
|
242
|
+
- `FEATURE_DATA.applications` — array of application summaries with their modules
|
|
243
|
+
- `FEATURE_DATA.modules` — flattened list of ALL modules across ALL applications (each with `applicationCode` field)
|
|
244
|
+
- `FEATURE_DATA.consolidation.crossApplicationInteractions` — from project feature.json
|
|
245
|
+
- FEATURE_DATA.**metadata.workflowMode** must be `"project"` (enables multi-app tabs in HTML)
|
|
246
|
+
|
|
222
247
|
---
|
|
223
248
|
|
|
224
249
|
### 5-7. Build FEATURE_DATA, EMBEDDED_ARTIFACTS & Replace Placeholders
|
|
@@ -426,9 +451,13 @@ Display completion using the template from `templates/tpl-launch-displays.md`:
|
|
|
426
451
|
|
|
427
452
|
```
|
|
428
453
|
═══════════════════════════════════════════════════════════════
|
|
429
|
-
[OK] BUSINESS ANALYSE TERMINEE - {application_name}
|
|
454
|
+
[OK] BUSINESS ANALYSE TERMINEE - {application_name OR project_name}
|
|
430
455
|
═══════════════════════════════════════════════════════════════
|
|
431
456
|
|
|
457
|
+
{IF workflow.mode === "project":}
|
|
458
|
+
Project: {project_name}
|
|
459
|
+
Apps: {app_count} ({app_names})
|
|
460
|
+
{ENDIF}
|
|
432
461
|
Modules: {count} ({names})
|
|
433
462
|
Strategy: {strategy}
|
|
434
463
|
Files: {total files across all modules}
|
|
@@ -437,8 +466,11 @@ Complexity: {complexity}
|
|
|
437
466
|
Effort: {total_days} days ({total_hours} hours)
|
|
438
467
|
|
|
439
468
|
[DIR] Artefacts générés:
|
|
440
|
-
✓ feature.json (master + per-module) - spécification complète
|
|
469
|
+
✓ feature.json ({IF project: "project + " ENDIF}master + per-module) - spécification complète
|
|
441
470
|
✓ .ralph/prd-{module}.json - task breakdown per module
|
|
471
|
+
{IF workflow.mode === "project":}
|
|
472
|
+
✓ .ralph/prd-CrossApplication.json - cross-application integration tests
|
|
473
|
+
{ENDIF}
|
|
442
474
|
✓ .ralph/progress.txt - tracker de progression
|
|
443
475
|
✓ ba-interactive.html - document de revue interactif
|
|
444
476
|
|