@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
|
@@ -279,6 +279,117 @@ Identify shared lookup/reference tables:
|
|
|
279
279
|
|
|
280
280
|
---
|
|
281
281
|
|
|
282
|
+
### 2f. Cross-Application Validation (Project Mode Only)
|
|
283
|
+
|
|
284
|
+
> **Only runs when `workflow.mode === "project"`** (multi-application feature).
|
|
285
|
+
> Validates cross-application interactions identified during step-01b.
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
IF workflow.mode !== "project":
|
|
289
|
+
SKIP this section entirely
|
|
290
|
+
→ Proceed to section 6 storage
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Process:**
|
|
294
|
+
|
|
295
|
+
1. **Load project feature.json:**
|
|
296
|
+
```
|
|
297
|
+
projectFeature = ba-reader.findProjectFeature()
|
|
298
|
+
applications = projectFeature.applications
|
|
299
|
+
applicationGraph = projectFeature.applicationDependencyGraph
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
2. **Cross-Application Shared Entities:**
|
|
303
|
+
```javascript
|
|
304
|
+
const crossAppSharedEntities = [];
|
|
305
|
+
for (const app1 of applications) {
|
|
306
|
+
for (const app2 of applications) {
|
|
307
|
+
if (app1.code === app2.code) continue;
|
|
308
|
+
for (const mod1 of app1.modules) {
|
|
309
|
+
for (const mod2 of app2.modules) {
|
|
310
|
+
// Detect entity name overlap or FK references across apps
|
|
311
|
+
const shared = findSharedEntities(mod1.entities, mod2.entities);
|
|
312
|
+
if (shared.length > 0) {
|
|
313
|
+
crossAppSharedEntities.push({
|
|
314
|
+
entity: shared[0].name,
|
|
315
|
+
definedInApp: app1.code,
|
|
316
|
+
definedInModule: mod1.code,
|
|
317
|
+
referencedByApp: app2.code,
|
|
318
|
+
referencedByModule: mod2.code,
|
|
319
|
+
referenceType: shared[0].type
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
3. **Cross-Application Permission Path Consistency:**
|
|
329
|
+
```javascript
|
|
330
|
+
// Verify permission paths use correct context per application
|
|
331
|
+
for (const app of applications) {
|
|
332
|
+
const expectedPrefix = `${app.context}.${toKebabCase(app.code)}`;
|
|
333
|
+
for (const mod of app.modules) {
|
|
334
|
+
for (const perm of mod.permissions || []) {
|
|
335
|
+
if (!perm.path.startsWith(expectedPrefix)) {
|
|
336
|
+
WARNING(`Permission path mismatch in ${app.code}/${mod.code}: "${perm.path}" should start with "${expectedPrefix}"`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
4. **Cross-Application Role Name Consistency:**
|
|
344
|
+
```javascript
|
|
345
|
+
// Check for role name conflicts across applications
|
|
346
|
+
const allRoles = {};
|
|
347
|
+
for (const app of applications) {
|
|
348
|
+
for (const role of app.applicationRoles || []) {
|
|
349
|
+
if (allRoles[role.role] && allRoles[role.role].level !== role.level) {
|
|
350
|
+
WARNING(`Role "${role.role}" has different levels: ${allRoles[role.role].app}=${allRoles[role.role].level} vs ${app.code}=${role.level}`);
|
|
351
|
+
}
|
|
352
|
+
allRoles[role.role] = { app: app.code, level: role.level };
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
5. **Store Cross-Application Data:**
|
|
358
|
+
```javascript
|
|
359
|
+
ba-writer.enrichSection({
|
|
360
|
+
featureId: {project_id},
|
|
361
|
+
section: "consolidation.crossApplicationInteractions",
|
|
362
|
+
data: crossAppSharedEntities.map(shared => ({
|
|
363
|
+
fromApplication: shared.definedInApp,
|
|
364
|
+
fromModule: shared.definedInModule,
|
|
365
|
+
toApplication: shared.referencedByApp,
|
|
366
|
+
toModule: shared.referencedByModule,
|
|
367
|
+
interactionType: shared.referenceType,
|
|
368
|
+
entity: shared.entity,
|
|
369
|
+
description: `${shared.entity} defined in ${shared.definedInApp}/${shared.definedInModule}, referenced by ${shared.referencedByApp}/${shared.referencedByModule}`
|
|
370
|
+
}))
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
6. **Display Cross-Application Interaction Map:**
|
|
375
|
+
|
|
376
|
+
```
|
|
377
|
+
═══════════════════════════════════════════════════════════════
|
|
378
|
+
CROSS-APPLICATION INTERACTIONS
|
|
379
|
+
═══════════════════════════════════════════════════════════════
|
|
380
|
+
|
|
381
|
+
| Source App | Source Module | Target App | Target Module | Entity | Type |
|
|
382
|
+
|------------|-------------|------------|--------------|--------|------|
|
|
383
|
+
| HR | Employees | SelfService | LeaveRequests | Employee | FK |
|
|
384
|
+
|
|
385
|
+
Shared entities: {count}
|
|
386
|
+
Permission paths: {valid_count}/{total_count} consistent
|
|
387
|
+
Role conflicts: {conflict_count}
|
|
388
|
+
═══════════════════════════════════════════════════════════════
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
282
393
|
## SINGLE-MODULE MODE
|
|
283
394
|
|
|
284
395
|
When only 1 module:
|
|
@@ -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)
|