@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
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: step-01b-applications
|
|
3
|
+
description: Application decomposition - identify and define multiple applications within a project
|
|
4
|
+
model: opus
|
|
5
|
+
next_step: steps/step-02-decomposition.md
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
> **Context files:** `_shared.md`
|
|
9
|
+
|
|
10
|
+
# Step 1b: Application Decomposition
|
|
11
|
+
|
|
12
|
+
## MANDATORY EXECUTION RULES
|
|
13
|
+
|
|
14
|
+
- ALWAYS use ULTRATHINK mode
|
|
15
|
+
- This step is ONLY loaded when `workflow.mode === "project"` (multi-application mode)
|
|
16
|
+
- ALL communication in `{language}`
|
|
17
|
+
- This step takes the candidate applications identified during cadrage and formalizes them
|
|
18
|
+
|
|
19
|
+
## YOUR TASK
|
|
20
|
+
|
|
21
|
+
For each candidate application identified during step-01 cadrage, define its identity, context, roles, and scope. Establish inter-application dependencies and create per-application feature.json files.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
### 1. Load Project Context
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
projectFeature = ba-reader.findProjectFeature()
|
|
29
|
+
candidateApps = projectFeature.cadrage.coverageMatrix grouped by domain
|
|
30
|
+
globalRoles = projectFeature.cadrage.globalRoles (if defined)
|
|
31
|
+
globalScope = projectFeature.cadrage.globalScope
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. Application Identity (per candidate)
|
|
35
|
+
|
|
36
|
+
For EACH candidate application from the cadrage analysis:
|
|
37
|
+
|
|
38
|
+
#### 2a. Confirm Application Name and Context
|
|
39
|
+
|
|
40
|
+
Display proposed application:
|
|
41
|
+
```
|
|
42
|
+
{language == "fr"
|
|
43
|
+
? "### Application : {suggestedName}\n\n**Contexte de navigation :** {suggestedContext}\n**Description :** {description based on coverage matrix items}"
|
|
44
|
+
: "### Application: {suggestedName}\n\n**Navigation context:** {suggestedContext}\n**Description:** {description based on coverage matrix items}"}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Ask via AskUserQuestion:
|
|
48
|
+
```
|
|
49
|
+
question: "{language == 'fr' ? 'Cette application et son contexte vous conviennent-ils ?' : 'Does this application and its context suit you?'}"
|
|
50
|
+
header: "{appName}"
|
|
51
|
+
options:
|
|
52
|
+
- label: "{language == 'fr' ? 'Oui, parfait' : 'Yes, perfect'}"
|
|
53
|
+
description: "{language == 'fr' ? 'Nom et contexte corrects' : 'Name and context are correct'}"
|
|
54
|
+
- label: "{language == 'fr' ? 'Modifier' : 'Modify'}"
|
|
55
|
+
description: "{language == 'fr' ? 'Changer le nom, le contexte ou la description' : 'Change name, context, or description'}"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 2b. Table Prefix (per application)
|
|
59
|
+
|
|
60
|
+
Each application MUST have its own unique table prefix.
|
|
61
|
+
|
|
62
|
+
1. Derive suggested prefix from application name (2-5 lowercase letters + `_`)
|
|
63
|
+
2. Validate:
|
|
64
|
+
- Format: `^[a-z]{2,5}_$`
|
|
65
|
+
- No collision with platform prefixes: `auth_`, `nav_`, `usr_`, `ai_`, `cfg_`, `wkf_`, `support_`, `entra_`, `ref_`, `loc_`, `lic_`, `tenant_`
|
|
66
|
+
- No collision with other applications in this project
|
|
67
|
+
3. Ask via AskUserQuestion for confirmation
|
|
68
|
+
|
|
69
|
+
#### 2c. Application-Specific Roles
|
|
70
|
+
|
|
71
|
+
Based on global roles from cadrage + application-specific needs:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
{language == "fr"
|
|
75
|
+
? "### Rôles pour {appName}\n\nVoici les rôles hérités des rôles globaux, adaptés à cette application :"
|
|
76
|
+
: "### Roles for {appName}\n\nHere are the roles inherited from global roles, adapted for this application:"}
|
|
77
|
+
|
|
78
|
+
| Role | Level | Permission Pattern |
|
|
79
|
+
|------|-------|--------------------|
|
|
80
|
+
{for each role: name | admin/manager/contributor/viewer | context.app.* pattern}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Ask via AskUserQuestion if additional roles are needed for this specific application.
|
|
84
|
+
|
|
85
|
+
#### 2d. Application Scope
|
|
86
|
+
|
|
87
|
+
Extract the subset of global scope that applies to this application:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
applicationScope = {
|
|
91
|
+
mustHave: globalScope.mustHave.filter(item => belongsToApp(item, appCode)),
|
|
92
|
+
shouldHave: globalScope.shouldHave.filter(item => belongsToApp(item, appCode)),
|
|
93
|
+
couldHave: globalScope.couldHave.filter(item => belongsToApp(item, appCode))
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Display and confirm with user.
|
|
98
|
+
|
|
99
|
+
### 3. Inter-Application Dependency Analysis
|
|
100
|
+
|
|
101
|
+
After all applications are defined:
|
|
102
|
+
|
|
103
|
+
1. **Identify dependencies:** For each pair of applications:
|
|
104
|
+
- Shared entities (e.g., Employee defined in HR, referenced by Self-Service)
|
|
105
|
+
- Event flows (e.g., HR publishes "EmployeeCreated", Self-Service subscribes)
|
|
106
|
+
- Authentication delegation (e.g., Self-Service uses HR's employee data for auth)
|
|
107
|
+
- Data dependencies (e.g., Self-Service reads HR data)
|
|
108
|
+
|
|
109
|
+
2. **Build dependency graph:**
|
|
110
|
+
```
|
|
111
|
+
applicationDependencyGraph = {
|
|
112
|
+
edges: [
|
|
113
|
+
{ from: "EmployeeSelfService", to: "HumanResources", type: "data-dependency", description: "Reads employee data" }
|
|
114
|
+
],
|
|
115
|
+
topologicalOrder: ["HumanResources", "EmployeeSelfService"],
|
|
116
|
+
layers: [
|
|
117
|
+
{ layer: 0, applications: ["HumanResources"] },
|
|
118
|
+
{ layer: 1, applications: ["EmployeeSelfService"] }
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
3. **Cycle detection:** If circular dependencies detected → BLOCKING ERROR
|
|
124
|
+
- Display the cycle
|
|
125
|
+
- Ask user to resolve (merge applications or remove dependency)
|
|
126
|
+
|
|
127
|
+
### 4. Client Checkpoint (BLOCKING)
|
|
128
|
+
|
|
129
|
+
Display the full application structure:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
{language == "fr"
|
|
133
|
+
? "### Structure du projet\n\nVoici les applications identifiées :"
|
|
134
|
+
: "### Project Structure\n\nHere are the identified applications:"}
|
|
135
|
+
|
|
136
|
+
| # | Application | Contexte | Préfixe | Rôles | Dépendances |
|
|
137
|
+
|---|-------------|----------|---------|-------|-------------|
|
|
138
|
+
{for each app: index | name | context | prefix | role count | dependency list}
|
|
139
|
+
|
|
140
|
+
{language == "fr"
|
|
141
|
+
? "### Ordre de traitement\n\nLes applications seront traitées dans cet ordre (fondations d'abord) :"
|
|
142
|
+
: "### Processing Order\n\nApplications will be processed in this order (foundations first):"}
|
|
143
|
+
|
|
144
|
+
{for each layer: "Layer {n}: {app1}, {app2}, ..."}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Ask via AskUserQuestion:
|
|
148
|
+
```
|
|
149
|
+
question: "{language == 'fr' ? 'Cette structure de projet vous convient-elle ?' : 'Does this project structure suit you?'}"
|
|
150
|
+
header: "Validation"
|
|
151
|
+
options:
|
|
152
|
+
- label: "{language == 'fr' ? 'Oui, continuer' : 'Yes, continue'}"
|
|
153
|
+
description: "{language == 'fr' ? 'Passer à la décomposition en modules' : 'Proceed to module decomposition'}"
|
|
154
|
+
- label: "{language == 'fr' ? 'Modifier' : 'Modify'}"
|
|
155
|
+
description: "{language == 'fr' ? 'Ajouter, supprimer ou modifier des applications' : 'Add, remove, or modify applications'}"
|
|
156
|
+
- label: "{language == 'fr' ? 'Fusionner en une seule' : 'Merge into one'}"
|
|
157
|
+
description: "{language == 'fr' ? 'Finalement, c'est une seule application avec plusieurs modules' : 'Actually, this is one application with multiple modules'}"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**IF "Merge into one":**
|
|
161
|
+
→ Convert back to single-application mode
|
|
162
|
+
→ Delete project-level feature.json
|
|
163
|
+
→ Create application-level feature.json with all scope items
|
|
164
|
+
→ Load `steps/step-02-decomposition.md` directly
|
|
165
|
+
|
|
166
|
+
### 5. Create Per-Application Feature.json Files
|
|
167
|
+
|
|
168
|
+
For EACH application in topological order:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
ba-writer.createApplicationFeature({
|
|
172
|
+
id: generate_feature_id(),
|
|
173
|
+
version: "1.0",
|
|
174
|
+
scope: "application",
|
|
175
|
+
status: "draft",
|
|
176
|
+
metadata: {
|
|
177
|
+
application: {app.code},
|
|
178
|
+
context: {app.context},
|
|
179
|
+
language: {language},
|
|
180
|
+
featureDescription: {app.description},
|
|
181
|
+
workflowType: "new",
|
|
182
|
+
analysisMode: "interactive",
|
|
183
|
+
mcpAvailable: true,
|
|
184
|
+
tablePrefix: {app.tablePrefix},
|
|
185
|
+
projectRef: {project_id},
|
|
186
|
+
workflow: {
|
|
187
|
+
mode: "application",
|
|
188
|
+
moduleOrder: [],
|
|
189
|
+
currentModuleIndex: 0,
|
|
190
|
+
completedModules: [],
|
|
191
|
+
currentModule: null
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Store the created feature.json path in the project feature.json `applications[].featureJsonPath`.
|
|
198
|
+
|
|
199
|
+
### 6. Write to Project Feature.json
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
ba-writer.enrichApplicationRegistry({
|
|
203
|
+
projectId: {project_id},
|
|
204
|
+
applications: [
|
|
205
|
+
{
|
|
206
|
+
code: {app1.code},
|
|
207
|
+
name: {app1.name},
|
|
208
|
+
context: {app1.context},
|
|
209
|
+
tablePrefix: {app1.tablePrefix},
|
|
210
|
+
icon: {app1.icon},
|
|
211
|
+
description: {app1.description},
|
|
212
|
+
applicationRoles: [{...}],
|
|
213
|
+
scope: { mustHave: [...], shouldHave: [...], couldHave: [...] },
|
|
214
|
+
modules: [],
|
|
215
|
+
dependencies: [{...}],
|
|
216
|
+
status: "pending",
|
|
217
|
+
featureJsonPath: {app1.featureJsonPath},
|
|
218
|
+
estimatedComplexity: {app1.estimatedComplexity}
|
|
219
|
+
},
|
|
220
|
+
// ... more applications
|
|
221
|
+
],
|
|
222
|
+
applicationDependencyGraph: {
|
|
223
|
+
edges: [...],
|
|
224
|
+
topologicalOrder: [...],
|
|
225
|
+
layers: [...]
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
ba-writer.updateStatus({project_id}, "decomposed")
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 7. Display Summary
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
{language == "fr"
|
|
236
|
+
? "### Décomposition en applications terminée\n\n"
|
|
237
|
+
: "### Application decomposition complete\n\n"}
|
|
238
|
+
|
|
239
|
+
| Application | Contexte | Préfixe | Feature ID |
|
|
240
|
+
|-------------|----------|---------|------------|
|
|
241
|
+
{for each app: name | context | prefix | FEAT-NNN}
|
|
242
|
+
|
|
243
|
+
{language == "fr"
|
|
244
|
+
? "→ Prochaine étape : décomposition en modules pour **{firstApp}** (application {1}/{total})"
|
|
245
|
+
: "→ Next step: module decomposition for **{firstApp}** (application {1}/{total})"}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## NEXT STEP
|
|
251
|
+
|
|
252
|
+
Load: `./step-02-decomposition.md` (for the first application in topological order)
|
|
@@ -28,12 +28,27 @@ Decompose the application scope into ordered modules. Identify dependencies betw
|
|
|
28
28
|
### 1. Read Cadrage Results
|
|
29
29
|
|
|
30
30
|
```
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
// Determine context source based on workflow mode
|
|
32
|
+
IF workflow.mode === "project":
|
|
33
|
+
projectFeature = ba-reader.findProjectFeature()
|
|
34
|
+
currentAppCode = projectFeature.metadata.workflow.currentApplication
|
|
35
|
+
currentApp = projectFeature.applications.find(a => a.code === currentAppCode)
|
|
36
|
+
appFeature = ba-reader.findFeature(currentApp.featureJsonPath)
|
|
37
|
+
|
|
38
|
+
// Scope decomposition to current application only
|
|
39
|
+
→ Read appFeature.cadrage.globalScope (application-specific scope from step-01b)
|
|
40
|
+
→ Read appFeature.cadrage.stakeholders (filtered to this application)
|
|
41
|
+
→ Read appFeature.cadrage.applicationRoles
|
|
42
|
+
→ Read appFeature.metadata.workflow.mode
|
|
43
|
+
|
|
44
|
+
Display: "═══ Module decomposition for application: {currentApp.name} ({currentAppIndex + 1}/{total}) ═══"
|
|
45
|
+
ELSE:
|
|
46
|
+
ba-reader.findFeature({feature_id})
|
|
47
|
+
→ Read cadrage.globalScope (mustHave, shouldHave, couldHave)
|
|
48
|
+
→ Read cadrage.stakeholders (roles, tasks, pain points)
|
|
49
|
+
→ Read cadrage.applicationRoles
|
|
50
|
+
→ Read cadrage.codebaseContext (existing modules found)
|
|
51
|
+
→ Read metadata.workflow.mode
|
|
37
52
|
```
|
|
38
53
|
|
|
39
54
|
IF status already "decomposed":
|
|
@@ -368,3 +383,5 @@ When `workflow.mode = "module"` or only 1 scope item identified:
|
|
|
368
383
|
|
|
369
384
|
> **FORBIDDEN:** Asking any question between decomposition summary and step-03 load.
|
|
370
385
|
> The client checkpoint was at step 6. Do NOT add another one.
|
|
386
|
+
|
|
387
|
+
> **PROJECT MODE NOTE:** In project mode, this step runs once per application. After all modules for the current application are specified (via the module loop in step-03d), the application loop in `_module-loop.md` will advance to the next application and re-load this step for module decomposition of the next application. Module registries and dependency graphs are written to the APPLICATION-level feature.json (not the project level). The project-level feature.json tracks application status via `ba-writer.updateApplicationStatus()`.
|
|
@@ -548,8 +548,6 @@ IF currentModuleIndex < moduleOrder.length:
|
|
|
548
548
|
Load: steps/step-03a1-setup.md
|
|
549
549
|
|
|
550
550
|
IF currentModuleIndex >= moduleOrder.length:
|
|
551
|
-
Display: "═══ Tous les modules spécifiés! Passage à la consolidation (04a→04c) puis handoff (05a→05c)... ═══"
|
|
552
|
-
Display: "⚠ NE PAS lancer /ralph-loop — la consolidation et le handoff sont encore nécessaires."
|
|
553
551
|
ba-writer.updateStatus({feature_id}, "specified")
|
|
554
552
|
|
|
555
553
|
// CHECKPOINT: Save progress BEFORE transition (protects against context exhaustion)
|
|
@@ -562,10 +560,33 @@ IF currentModuleIndex >= moduleOrder.length:
|
|
|
562
560
|
}
|
|
563
561
|
})
|
|
564
562
|
|
|
565
|
-
//
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
563
|
+
// CHECK: Are we in project mode (multi-application)?
|
|
564
|
+
IF workflow.mode === "project":
|
|
565
|
+
// APPLICATION LOOP: Check if more applications remain
|
|
566
|
+
projectFeature = ba-reader.findProjectFeature()
|
|
567
|
+
ba-writer.updateApplicationStatus(projectId, currentApp.code, "specified")
|
|
568
|
+
ba-writer.advanceApplicationLoop(projectId)
|
|
569
|
+
|
|
570
|
+
IF projectFeature.metadata.workflow.currentApplicationIndex + 1 < projectFeature.metadata.workflow.applicationOrder.length:
|
|
571
|
+
nextApp = projectFeature.metadata.workflow.applicationOrder[currentApplicationIndex + 1]
|
|
572
|
+
Display: "═══ Application {currentApp.name} terminée ({N}/{total}). Prochaine : {nextApp} ═══"
|
|
573
|
+
Display: "⚠ NE PAS lancer /ralph-loop — d'autres applications et la consolidation sont encore nécessaires."
|
|
574
|
+
// Load step-02 for next application's module decomposition
|
|
575
|
+
Load: steps/step-02-decomposition.md
|
|
576
|
+
ELSE:
|
|
577
|
+
Display: "═══ Toutes les applications spécifiées! Passage à la consolidation cross-application... ═══"
|
|
578
|
+
Display: "⚠ NE PAS lancer /ralph-loop — la consolidation et le handoff sont encore nécessaires."
|
|
579
|
+
ba-writer.updateStatus(projectId, "specified")
|
|
580
|
+
Load: steps/step-04a-collect.md
|
|
581
|
+
ELSE:
|
|
582
|
+
// SINGLE APPLICATION: Current behavior
|
|
583
|
+
Display: "═══ Tous les modules spécifiés! Passage à la consolidation (04a→04c) puis handoff (05a→05c)... ═══"
|
|
584
|
+
Display: "⚠ NE PAS lancer /ralph-loop — la consolidation et le handoff sont encore nécessaires."
|
|
585
|
+
|
|
586
|
+
// MANDATORY TRANSITION — DO NOT STOP HERE
|
|
587
|
+
// If context is near exhaustion, the checkpoint above ensures the user
|
|
588
|
+
// can resume with /business-analyse and it will route to step-04a automatically.
|
|
589
|
+
Load: steps/step-04a-collect.md
|
|
569
590
|
```
|
|
570
591
|
|
|
571
592
|
---
|
|
@@ -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:
|