@atlashub/smartstack-cli 4.25.0 → 4.27.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 (30) hide show
  1. package/dist/index.js +765 -517
  2. package/dist/index.js.map +1 -1
  3. package/dist/mcp-entry.mjs +33 -11
  4. package/dist/mcp-entry.mjs.map +1 -1
  5. package/package.json +1 -1
  6. package/templates/agents/ba-writer.md +46 -42
  7. package/templates/project/appsettings.json.template +4 -6
  8. package/templates/skills/apex/SKILL.md +1 -0
  9. package/templates/skills/apex/references/challenge-questions.md +17 -0
  10. package/templates/skills/apex/references/post-checks.md +48 -0
  11. package/templates/skills/apex/steps/step-03-execute.md +63 -2
  12. package/templates/skills/ba-generate-html/references/data-build.md +22 -13
  13. package/templates/skills/ba-generate-html/references/data-mapping.md +33 -24
  14. package/templates/skills/ba-generate-html/steps/step-01-collect.md +15 -6
  15. package/templates/skills/ba-generate-html/steps/step-02-build-data.md +37 -22
  16. package/templates/skills/business-analyse/steps/step-00-init.md +22 -14
  17. package/templates/skills/business-analyse/steps/step-04-consolidate.md +3 -0
  18. package/templates/skills/derive-prd/steps/step-01-transform.md +6 -2
  19. package/templates/skills/derive-prd/steps/step-02-export.md +12 -0
  20. package/templates/skills/ralph-loop/references/category-completeness.md +3 -3
  21. package/templates/skills/ralph-loop/references/compact-loop.md +81 -14
  22. package/templates/skills/ralph-loop/references/init-resume-recovery.md +1 -1
  23. package/templates/skills/ralph-loop/references/module-transition.md +30 -5
  24. package/templates/skills/ralph-loop/references/multi-module-queue.md +4 -4
  25. package/templates/skills/ralph-loop/references/section-splitting.md +6 -6
  26. package/templates/skills/ralph-loop/steps/step-01-task.md +14 -4
  27. package/templates/skills/ralph-loop/steps/step-02-execute.md +14 -6
  28. package/templates/skills/ralph-loop/steps/step-03-commit.md +15 -4
  29. package/templates/skills/ralph-loop/steps/step-04-check.md +19 -5
  30. package/templates/skills/ralph-loop/steps/step-05-report.md +35 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlashub/smartstack-cli",
3
- "version": "4.25.0",
3
+ "version": "4.27.0",
4
4
  "description": "SmartStack Claude Code automation toolkit - GitFlow, EF Core migrations, prompts and more",
5
5
  "author": {
6
6
  "name": "SmartStack",
@@ -18,17 +18,18 @@ Write and update granular JSON files for project-level (multi-app), application-
18
18
  - Module-level: `docs/{app}/{module}/business-analyse/v{X.Y}/index.json` + thematic files
19
19
 
20
20
  **Thematic files (v2 granular architecture):**
21
- - `index.json` — metadata, version, hash manifest, module registry
22
- - `cadrage.json` — stakeholders, problem/vision, risks, acceptance criteria
23
- - `entities.json` — entity definitions with attributes and relationships
24
- - `rules.json` — business rules with categories and conditions
25
- - `usecases.json` — use cases and functional requirements
26
- - `permissions.json` — permission matrix and role assignments
27
- - `screens.json` — UI wireframes and navigation
28
- - `validation.json` — validation rules and consistency checks
29
- - `handoff.json` — complexity, file catalog, BR-to-code mapping
30
- - `consolidation.json` — cross-module interactions and E2E flows (application-level only)
31
- - `review.json` — preserved review comments and change summary
21
+ - `index.json` — metadata, version, hash manifest, module registry (ALL scopes)
22
+ - `cadrage.json` — stakeholders, problem/vision, risks, acceptance criteria (ALL scopes)
23
+ - `validation.json` — validation rules and consistency checks (ALL scopes)
24
+ - `consolidation.json` — cross-module interactions and E2E flows (application/project ONLY)
25
+ - `navigation.json` — navigation tree (application/project ONLY, created by ba-design-ui)
26
+ - `entities.json` — entity definitions with attributes and relationships (**MODULE ONLY**)
27
+ - `rules.json` — business rules with categories and conditions (**MODULE ONLY**)
28
+ - `usecases.json` — use cases and functional requirements (**MODULE ONLY**)
29
+ - `permissions.json` — permission matrix and role assignments (**MODULE ONLY**)
30
+ - `screens.json` — UI wireframes and navigation (**MODULE ONLY**)
31
+ - `handoff.json` — complexity, file catalog, BR-to-code mapping (**MODULE ONLY**)
32
+ - `review.json` — preserved review comments and change summary (ALL scopes)
32
33
 
33
34
  > **Backward compatibility:** If only 1 application, the project level is NOT created. The application-level index.json remains the master.
34
35
 
@@ -62,9 +63,12 @@ Create initial index.json and empty thematic files with metadata and draft statu
62
63
  - For project scope: modules: []
63
64
  - For application scope: modules: []
64
65
  - For module scope: (no modules array)
65
- 5. Create empty thematic files appropriate for scope:
66
- - Project/application: cadrage.json, entities.json, rules.json, usecases.json, permissions.json, screens.json, validation.json, handoff.json, consolidation.json
67
- - Module: discovery.json, analysis.json, specification.json, validation.json, handoff.json
66
+ 5. Create empty thematic files ONLY the files listed for the scope. Creating ANY unlisted file is a **BLOCKING ERROR**.
67
+ - Project: cadrage.json, validation.json, consolidation.json **EXACTLY 3 files, NO OTHERS**
68
+ - Application: cadrage.json, validation.json, consolidation.json — **EXACTLY 3 files, NO OTHERS**
69
+ - Module: entities.json, rules.json, usecases.json, permissions.json, screens.json, validation.json, handoff.json — **EXACTLY 7 files**
70
+
71
+ **FORBIDDEN at project/application level:** entities.json, rules.json, usecases.json, permissions.json, screens.json, handoff.json — these exist ONLY at module level.
68
72
  6. Update `.business-analyse/config.json` with new lastFeatureId
69
73
  7. IF scope = "module" AND applicationRef provided AND moduleCode provided:
70
74
  a. Read master index.json (via applicationRef FEAT-NNN)
@@ -107,7 +111,8 @@ Create a project-level index.json for multi-application analysis. Only used when
107
111
  - fileHashes: {}
108
112
  - applications: []
109
113
  - applicationDependencyGraph: {}
110
- 5. Create thematic files (cadrage.json, entities.json, rules.json, usecases.json, permissions.json, screens.json, validation.json, consolidation.json)
114
+ 5. Create thematic files **EXACTLY 3 files, NO OTHERS:** cadrage.json, validation.json, consolidation.json
115
+ **FORBIDDEN at project level:** entities.json, rules.json, usecases.json, permissions.json, screens.json, handoff.json — these exist ONLY at module level.
111
116
  6. Update `.business-analyse/config.json` with new lastProjectId
112
117
  7. Deploy schemas to `docs/business-analyse/schemas/` (including project-schema.json)
113
118
  8. Return project ID (PROJ-NNN) and path
@@ -174,6 +179,10 @@ Write a complete thematic file and update its hash in index.json.
174
179
 
175
180
  **Process:**
176
181
  1. Find and read index.json (use findFeature if given ID)
182
+ 1b. **SCOPE GUARD (BLOCKING):** If index.json scope is "project" or "application", verify themeName is ALLOWED:
183
+ - Allowed: [cadrage, validation, consolidation, navigation, review]
184
+ - FORBIDDEN: [entities, rules, usecases, permissions, screens, handoff]
185
+ If themeName is FORBIDDEN → **REJECT with BLOCKING ERROR.** Do NOT create the file.
177
186
  2. Determine thematic filename: `{themeName}.json`
178
187
  3. Create full path: `{version_dir}/{themeName}.json`
179
188
  4. Write thematic file with pretty-print (2-space indent)
@@ -331,6 +340,20 @@ Increment the module loop counter in the master index.json.
331
340
  9. Write back index.json
332
341
  10. Return new index and whether loop is complete
333
342
 
343
+ ### cleanupAppLevelFiles
344
+ Remove forbidden thematic files at project/application level and clean their entries from fileHashes.
345
+
346
+ **Input:** featureId: FEAT-NNN
347
+
348
+ **Process:**
349
+ 1. Read index.json (verify scope is "project" or "application")
350
+ 2. FORBIDDEN = [entities.json, rules.json, usecases.json, permissions.json, screens.json, handoff.json]
351
+ 3. For each FORBIDDEN file: if file exists in version directory → DELETE it
352
+ 4. For each FORBIDDEN file: if referenced in fileHashes → REMOVE entry
353
+ 5. If `files` property exists in index.json: remove entries for forbidden files
354
+ 6. Update metadata.updatedAt, write index.json
355
+ 7. Return list of cleaned files
356
+
334
357
  ### createVersion
335
358
  Create a new version for refactoring or major changes.
336
359
 
@@ -466,43 +489,29 @@ docs/business-analyse/
466
489
  v1.0/
467
490
  index.json ← PROJECT metadata
468
491
  cadrage.json
469
- entities.json
470
- rules.json
471
- usecases.json
472
- permissions.json
473
- screens.json
474
492
  validation.json
475
493
  consolidation.json
494
+ # NO entities/rules/usecases/permissions/screens/handoff — MODULE ONLY
476
495
 
477
496
  docs/{app}/business-analyse/
478
497
  v1.0/
479
498
  index.json ← APPLICATION metadata
480
499
  cadrage.json
481
- entities.json
482
- rules.json
483
- usecases.json
484
- permissions.json
485
- screens.json
486
500
  validation.json
487
501
  consolidation.json
488
- v1.1/
489
- index.json
490
- cadrage.json
491
- entities.json
492
- ...
502
+ navigation.json ← (created by ba-design-ui)
503
+ # NO entities/rules/usecases/permissions/screens/handoff — MODULE ONLY
493
504
 
494
505
  docs/{app}/{module}/business-analyse/
495
506
  v1.0/
496
507
  index.json ← MODULE metadata
497
- discovery.json
498
- analysis.json
499
- specification.json
508
+ entities.json
509
+ rules.json
510
+ usecases.json
511
+ permissions.json
512
+ screens.json
500
513
  validation.json
501
514
  handoff.json
502
- v1.1/
503
- index.json
504
- discovery.json
505
- ...
506
515
  ```
507
516
 
508
517
  Versions are stored as separate directories. Each directory contains index.json + thematic files.
@@ -722,11 +731,6 @@ if (estimatedNewSize > 500 * 1024) { // 500KB
722
731
  "fileHashes": {
723
732
  "index.json": "pqr678...",
724
733
  "cadrage.json": "stu901...",
725
- "entities.json": "vwx234...",
726
- "rules.json": "yza567...",
727
- "usecases.json": "bcd890...",
728
- "permissions.json": "efg123...",
729
- "screens.json": "hij456...",
730
734
  "validation.json": "klm789...",
731
735
  "consolidation.json": "nop012..."
732
736
  },
@@ -7,10 +7,8 @@
7
7
  "FailOnMigrationError": true,
8
8
  "EnableDevSeeding": false,
9
9
  "CorsOrigins": [
10
- "http://localhost:5173",
11
- "http://localhost:5174",
12
- "http://localhost:5175",
13
- "http://localhost:6173"
10
+ "http://localhost:3000",
11
+ "http://localhost:5173"
14
12
  ]
15
13
  },
16
14
  "Jwt": {
@@ -34,7 +32,7 @@
34
32
  "SecretExpiresAt": "",
35
33
  "CallbackPath": "/api/auth/google/callback"
36
34
  },
37
- "FrontendUrl": "http://localhost:6173"
35
+ "FrontendUrl": "http://localhost:3000"
38
36
  },
39
37
  "Session": {
40
38
  "IdleTimeoutMinutes": 20,
@@ -125,7 +123,7 @@
125
123
  "Provider": "Development",
126
124
  "FromEmail": "noreply@{{ProjectDomain}}",
127
125
  "FromName": "{{ProjectName}}",
128
- "BaseUrl": "http://localhost:5173",
126
+ "BaseUrl": "http://localhost:3000",
129
127
  "TokenExpiration": {
130
128
  "EmailConfirmation": "24:00:00",
131
129
  "PasswordReset": "01:00:00"
@@ -149,6 +149,7 @@ Execute incremental SmartStack development using the APEX methodology. This skil
149
149
  - **Parallel Agent tool** - Parallel execution for scan (step-01) and within Layer 2/3 (step-03) for multi-entity, unless economy_mode
150
150
  - **Tests inline** - Backend tests run after Layer 2, frontend tests run after Layer 3 (max 3 fix iterations each). Step-07 = final sweep (security + coverage).
151
151
  - **Exception: seed data** — The templates in core-seed-data.md and person-extension-pattern.md are generated directly because no MCP tool covers seed data creation. This is a documented exception to the "orchestrate, never generate" rule.
152
+ - **Frontend pages: ALWAYS via Skill("ui-components")** — economy_mode affects parallelization only, NOT whether /ui-components is called. NEVER generate .tsx pages directly, even in delegate or economy mode.
152
153
  - **Save outputs** if `{save_mode}` = true
153
154
  - **Commits per layer** - Atomic commits after each execution layer
154
155
  - **Delegate mode** (`-d`): Read PRD context, skip challenge questions, auto+economy mode implied. Used when `/ralph-loop` delegates code generation to `/apex`.
@@ -82,8 +82,25 @@ questions:
82
82
  multiSelect: true
83
83
  ```
84
84
 
85
+ **Reserved codes (NOT valid sections):**
86
+ - `detail` — auto-generated as `/:id` route when "list" section exists
87
+ - `create` — auto-generated as `/create` route when "list" section exists
88
+ - `edit` — auto-generated as `/:id/edit` route when "list" section exists
89
+
90
+ These are **view modes**, not sections. A "list" section automatically generates 4 pages: ListPage (index), DetailPage (/:id), CreatePage (/create), EditPage (/:id/edit).
91
+
85
92
  **Validation:**
86
93
  ```
94
+ RESERVED_SECTION_CODES = ["detail", "create", "edit"]
95
+
96
+ IF any section.code IN RESERVED_SECTION_CODES:
97
+ DISPLAY: "'{section.code}' is a view mode, not a section.
98
+ The 'list' section automatically includes detail (/:id), create (/create),
99
+ and edit (/:id/edit) pages. Remove '{section.code}' from your sections."
100
+ → Remove the offending section(s) from the list
101
+ → Re-ask the sections question if {sections}.length == 0
102
+ → DO NOT proceed
103
+
87
104
  IF {sections}.length == 0:
88
105
  DISPLAY: "Every module must have at least one section. Please select or define at least one."
89
106
  → Re-ask the sections question
@@ -117,6 +117,21 @@ if [ -n "$APP_TSX" ]; then
117
117
  fi
118
118
  ```
119
119
 
120
+ ### POST-CHECK S7: Controllers must NOT use Guid.Empty for tenantId/userId (OWASP A01)
121
+
122
+ ```bash
123
+ CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
124
+ if [ -n "$CTRL_FILES" ]; then
125
+ BAD_GUID=$(grep -Pn 'Guid\.Empty' $CTRL_FILES 2>/dev/null)
126
+ if [ -n "$BAD_GUID" ]; then
127
+ echo "BLOCKING (OWASP A01): Controller uses Guid.Empty — tenant isolation bypassed"
128
+ echo "$BAD_GUID"
129
+ echo "Fix: Use _currentTenant.TenantId from ICurrentTenantService"
130
+ exit 1
131
+ fi
132
+ fi
133
+ ```
134
+
120
135
  ---
121
136
 
122
137
  ## Backend — Entity, Service & Controller Checks
@@ -154,6 +169,39 @@ fi
154
169
 
155
170
  ## Frontend — CSS, Forms, Components, I18n
156
171
 
172
+ ### POST-CHECK C3a: Frontend must not be empty if Layer 3 was planned (BLOCKING)
173
+
174
+ ```bash
175
+ # If foundation_mode is false AND App.tsx exists, verify frontend was generated
176
+ APP_TSX=$(find web/ src/ -name "App.tsx" -not -path "*/node_modules/*" 2>/dev/null | head -1)
177
+ if [ -n "$APP_TSX" ]; then
178
+ # Check if applicationRoutes is an empty object
179
+ EMPTY_ROUTES=$(grep -P "applicationRoutes.*=\s*\{[\s/]*\}" "$APP_TSX" 2>/dev/null)
180
+ if [ -n "$EMPTY_ROUTES" ]; then
181
+ echo "BLOCKING: applicationRoutes in App.tsx is empty — Layer 3 frontend was NOT executed"
182
+ echo "Expected: at least one application key with route definitions"
183
+ echo "Fix: Run Layer 3 (scaffold_routes + scaffold_extension + route wiring)"
184
+ exit 1
185
+ fi
186
+
187
+ # Check pages/ directory is not empty
188
+ PAGE_COUNT=$(find web/ src/ -path "*/pages/*" -name "*.tsx" -not -path "*/node_modules/*" 2>/dev/null | wc -l)
189
+ if [ "$PAGE_COUNT" -eq 0 ]; then
190
+ echo "BLOCKING: No page components found in pages/ directory"
191
+ echo "Fix: Generate pages via scaffold_extension or /ui-components"
192
+ exit 1
193
+ fi
194
+
195
+ # Check navRoutes.generated.ts exists
196
+ NAV_ROUTES=$(find web/ src/ -name "navRoutes.generated.ts" -not -path "*/node_modules/*" 2>/dev/null | head -1)
197
+ if [ -z "$NAV_ROUTES" ]; then
198
+ echo "BLOCKING: navRoutes.generated.ts not found — scaffold_routes was never called"
199
+ echo "Fix: Run scaffold_routes(source: 'controllers', outputFormat: 'applicationRoutes')"
200
+ exit 1
201
+ fi
202
+ fi
203
+ ```
204
+
157
205
  ### POST-CHECK C3: Translation files must exist for all 4 languages (if frontend)
158
206
 
159
207
  ```bash
@@ -290,6 +290,24 @@ When launching agents for multi-entity layers:
290
290
  - Agent principal updates activeForm after each entity completion:
291
291
  `TaskUpdate(taskId: layer2_task_id, activeForm: "Building {EntityName} backend (2/5 entities)")`
292
292
 
293
+ ### Controller NavRoute Attribute (MANDATORY)
294
+
295
+ After controller generation, verify `[NavRoute]` attribute is present on every controller:
296
+ - Expected: `[NavRoute("{app_name}.{module_code}.{section_code}")]` on the controller class
297
+ - If missing: Add it manually above `[Authorize]`
298
+ - When calling `scaffold_extension(type: "controller")`, always pass `navRoute` in options
299
+ - This is REQUIRED for `scaffold_routes` to auto-detect routes in Layer 3
300
+
301
+ ```bash
302
+ # Quick check: all controllers must have [NavRoute] (not just [Route])
303
+ CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
304
+ for f in $CTRL_FILES; do
305
+ if ! grep -q "\[NavRoute" "$f" && grep -q "\[Route" "$f"; then
306
+ echo "WARNING: $f has [Route] but no [NavRoute] — add [NavRoute] for route auto-detection"
307
+ fi
308
+ done
309
+ ```
310
+
293
311
  ### Post-Layer 2 Build Gate
294
312
 
295
313
  ```bash
@@ -377,7 +395,18 @@ For each module:
377
395
  → All business applications use `<AppLayout />` as layout wrapper
378
396
  → See `references/frontend-route-wiring-app-tsx.md` for full Pattern A/B detection and examples
379
397
  → Verify: `mcp__smartstack__validate_frontend_routes (scope: 'routes')`
380
- - Pages: use /ui-components skill follow smartstack-frontend.md patterns:
398
+ - Pages per section: When a section exists (e.g., "list"), generate ALL 4 page types:
399
+ → {Section}ListPage.tsx (index route)
400
+ → {Section}DetailPage.tsx (/:id route) — click on list item navigates here
401
+ → Create{Section}Page.tsx (/create route)
402
+ → Edit{Section}Page.tsx (/:id/edit route)
403
+ "detail" is NEVER a separate section — it's the /:id route of the list section.
404
+ - Pages: **MANDATORY — INVOKE Skill("ui-components")** for ALL page generation.
405
+ ⚠ BLOCKING REQUIREMENT: You MUST call Skill("ui-components") for EVERY page (.tsx).
406
+ NEVER generate .tsx page code directly. NEVER write page content in Agent prompts.
407
+ NEVER use Write tool to create pages without first calling Skill("ui-components").
408
+ The skill loads the full style guide + patterns (entity-card, data-table, dashboard-chart, grid-layout).
409
+ Follow smartstack-frontend.md patterns:
381
410
  → React.lazy() for all page imports (named export wrapping)
382
411
  → `<Suspense fallback={<PageLoader />}>` around all lazy components
383
412
  → Page structure: hooks → useEffect(load) → loading → error → content
@@ -466,7 +495,21 @@ IF NOT economy_mode AND entities.length > 1:
466
495
  # All agents launched in parallel
467
496
 
468
497
  ELSE:
469
- # Agent principal handles all entities sequentially
498
+ # Economy mode: Agent principal handles all entities SEQUENTIALLY.
499
+ # MANDATORY: You MUST still call Skill("ui-components") for page generation.
500
+ # economy_mode only disables parallel agents — it does NOT skip /ui-components.
501
+ For each entity (sequentially):
502
+ 1. MCP scaffold_api_client
503
+ 2. MCP scaffold_routes (outputFormat: 'applicationRoutes')
504
+ 3. Wire routes to App.tsx (Pattern A/B — see references/frontend-route-wiring-app-tsx.md)
505
+ 4. **INVOKE Skill("ui-components")** — pass entity context:
506
+ - Entity: {EntityName}, Module: {ModuleName}, App: {AppName}
507
+ - Page types: List, Detail, Create, Edit (+ Dashboard if applicable)
508
+ - "CSS: Use CSS variables ONLY — bg-[var(--bg-card)], text-[var(--text-primary)]"
509
+ - "Forms: Create/Edit are FULL PAGES with own routes (/create, /:id/edit)"
510
+ - "I18n: ALL text uses t('namespace:key', 'Fallback')"
511
+ 5. I18n: 4 JSON files (fr, en, it, de) + register namespace in i18n config
512
+ 6. Form tests: co-located .test.tsx for Create and Edit pages
470
513
  ```
471
514
 
472
515
  ### Parallel Agents + TaskCreate Integration
@@ -495,6 +538,24 @@ When delegating to `/ui-components` skill, include explicit instructions:
495
538
  - "Forms: Create/Edit forms are FULL PAGES with own routes (e.g., `/create`, `/:id/edit`)."
496
539
  - "I18n: ALL text must use `t('namespace:key', 'Fallback')`. Generate JSON files in `src/i18n/locales/`."
497
540
 
541
+ ### HARD RULE — /ui-components is NON-NEGOTIABLE
542
+
543
+ > **VIOLATION CHECK:** If ANY .tsx page file was created by Write tool WITHOUT
544
+ > a prior Skill("ui-components") call in this execution, the frontend layer is INVALID.
545
+ >
546
+ > **You MUST NOT:**
547
+ > - Generate .tsx page code in Agent prompts and dispatch to Snipper agents
548
+ > - Write page content directly via the Write tool
549
+ > - Copy-paste page templates from your knowledge
550
+ >
551
+ > **You MUST:**
552
+ > - Call Skill("ui-components") which loads the style guide, responsive guidelines,
553
+ > accessibility rules, and pattern files (entity-card, data-table, dashboard-chart, grid-layout, kanban)
554
+ > - Let /ui-components generate all pages with correct conventions
555
+ >
556
+ > **Why this matters:** Without the skill, pages miss CSS variables, DataTable/EntityCard,
557
+ > memo()/useCallback, responsive mobile-first design, and accessibility patterns.
558
+
498
559
  ### Frontend Tests Inline
499
560
 
500
561
  > **Tests are scaffolded and run WITHIN Layer 3, not deferred to step-07.**
@@ -63,11 +63,13 @@ const FEATURE_DATA = {
63
63
  ],
64
64
  moduleSpecs: {
65
65
  // CRITICAL: Must have ONE entry per module with ALL module data
66
+ // FLAT-FILE: Data comes from collected_data.modules[moduleCode] (flat files), NOT module index.json
66
67
  "{moduleCode}": {
67
- useCases: module.specification.useCases || [],
68
- businessRules: module.analysis.businessRules || [],
68
+ // const mod = collected_data.modules[moduleCode];
69
+ useCases: mod.usecases?.useCases || [],
70
+ businessRules: mod.rules?.rules || [],
69
71
  // ENTITY SAFETY NET: map fields[] → attributes[] if agent deviated from canonical format
70
- entities: (module.analysis.entities || []).map(ent => ({
72
+ entities: (mod.entities?.entities || []).map(ent => ({
71
73
  name: ent.name,
72
74
  description: ent.description || "",
73
75
  attributes: (ent.attributes || []).length > 0
@@ -79,8 +81,8 @@ const FEATURE_DATA = {
79
81
  : (ent.fields || []).filter(f => f.foreignKey)
80
82
  .map(f => `${f.foreignKey.table} (N:1) - ${f.description || f.name}`)
81
83
  })),
82
- permissions: module.specification.permissionMatrix?.permissions || [],
83
- apiEndpoints: module.specification.apiEndpoints || []
84
+ permissions: mod.permissions?.matrix || mod.permissions?.permissions || [],
85
+ apiEndpoints: mod.usecases?.apiEndpoints || []
84
86
  }
85
87
  },
86
88
  consolidation: {
@@ -102,10 +104,15 @@ const FEATURE_DATA = {
102
104
  ### Build Process
103
105
 
104
106
  1. Extract metadata from master index.json
105
- 2. Extract cadrage from master index.json (CONVERT scope keys)
106
- 3. Extract stakeholders from master.stakeholders
107
+ 2. Extract cadrage from master cadrage.json (CONVERT scope keys)
108
+ 3. Extract stakeholders from master cadrage.stakeholders
107
109
  4. Iterate ALL modules and populate moduleSpecs (THIS IS CRITICAL — empty moduleSpecs = BUG)
108
- 5. For EACH module, extract: useCases, businessRules, entities, permissions, apiEndpoints
110
+ 5. For EACH module, read FLAT FILES from `collected_data.modules[moduleCode]`:
111
+ - `entities.json` → entities
112
+ - `rules.json` → businessRules
113
+ - `usecases.json` → useCases
114
+ - `permissions.json` → permissions
115
+ - `screens.json` → wireframes
109
116
  6. Extract consolidation data (integrations, shared entities, E2E flows)
110
117
  7. Extract handoff section (complexity, strategy, module order, file counts)
111
118
 
@@ -119,10 +126,12 @@ const FEATURE_DATA = {
119
126
  const EMBEDDED_ARTIFACTS = {
120
127
  wireframes: {
121
128
  // PER-MODULE keyed object (NOT a flat array)
122
- // FOR EACH module: extract from specification.uiWireframes[] OR specification.wireframes[] (SAFETY NET)
123
- // IMPORTANT: The agent may write wireframes under either key name — always check BOTH
124
- // Read from module JSON files
125
- [moduleCode]: (moduleFeature.specification.uiWireframes || moduleFeature.specification.wireframes || []).map(wf => ({
129
+ // FLAT-FILE: Read from screens.json in each module directory (collected in step-01)
130
+ // const mod = collected_data.modules[moduleCode];
131
+ // const screens = mod.screens?.screens || [];
132
+ [moduleCode]: screens
133
+ .filter(s => s.wireframe || s.mockup || s.mockupFormat)
134
+ .map(wf => ({
126
135
  screen: wf.screen || wf.name || wf.title || wf.id || "", // SAFETY NET: fallback name/title/id → screen
127
136
  section: wf.section || "", // e.g. "list"
128
137
  format: wf.mockupFormat || "ascii", // RENAME: mockupFormat → format
@@ -160,7 +169,7 @@ const EMBEDDED_ARTIFACTS = {
160
169
 
161
170
  ### Artifact Gathering
162
171
 
163
- 1. For EACH module: read `specification.uiWireframes[]` OR `specification.wireframes[]` (check BOTH keys agent may use either), **rename fields** (`mockupFormat`→`format`, `mockup`/`ascii`/`content`→`content`, `screen`/`name`/`title`→`screen`), store under `wireframes[moduleCode]`
172
+ 1. For EACH module: read `screens.json` flat file from `collected_data.modules[moduleCode].screens`, filter screens with wireframe data, **rename fields** (`mockupFormat`→`format`, `mockup`/`ascii`/`content`→`content`, `screen`/`name`/`title`→`screen`), store under `wireframes[moduleCode]`
164
173
  2. Read master's `consolidation.e2eFlows[]` and build e2eFlows array with diagram generation
165
174
  3. Read master's `dependencyGraph` and build nodes/edges
166
175
  4. Serialize as JSON with 2-space indentation
@@ -93,29 +93,32 @@ Build a JSON object following this **exact mapping** from index.json to the HTML
93
93
  }
94
94
  ```
95
95
 
96
- ### Module Specs Mapping
96
+ ### Module Specs Mapping (FLAT-FILE ARCHITECTURE)
97
97
 
98
98
  For EACH module in `master.modules[]`:
99
99
 
100
- 1. Read the module index.json at `master.modules[i].featureJsonPath`
101
- 2. Map to `moduleSpecs[moduleCode]`:
100
+ 1. Use flat file data from `collected_data.modules[moduleCode]` (loaded in step-01)
101
+ 2. Data sources: `entities.json`, `rules.json`, `usecases.json`, `permissions.json`, `screens.json`
102
+ 3. Do NOT read from `moduleIndex.specification` or `moduleIndex.analysis` — these don't exist in flat-file format
102
103
 
103
104
  ```javascript
105
+ const mod = collected_data.modules[moduleCode];
106
+
104
107
  moduleSpecs[moduleCode] = {
105
- useCases: (moduleFeature.specification?.useCases || []).map(uc => ({
108
+ useCases: (mod.usecases?.useCases || []).map(uc => ({
106
109
  name: uc.name,
107
110
  actor: uc.primaryActor,
108
111
  steps: (uc.mainScenario || []).join("\n"), // array → newline-separated string
109
112
  alternative: (uc.alternativeScenarios || [])
110
113
  .map(a => a.name + ": " + (a.steps || []).join(", ")).join("\n")
111
114
  })),
112
- businessRules: (moduleFeature.analysis?.businessRules || []).map(br => ({
115
+ businessRules: (mod.rules?.rules || []).map(br => ({
113
116
  name: br.name,
114
117
  category: br.category, // "validation"|"calculation"|"workflow"|"security"|"data"
115
118
  statement: br.statement,
116
119
  example: (br.examples || []).map(e => e.input + " → " + e.expected).join("; ")
117
120
  })),
118
- entities: (moduleFeature.analysis?.entities || []).map(ent => ({
121
+ entities: (mod.entities?.entities || []).map(ent => ({
119
122
  name: ent.name,
120
123
  description: ent.description || "",
121
124
  attributes: (ent.attributes || []).map(a => ({
@@ -128,7 +131,7 @@ moduleSpecs[moduleCode] = {
128
131
  r.target + " (" + r.type + ") - " + (r.description || "")
129
132
  )
130
133
  })),
131
- permissions: buildPermissionKeys(moduleFeature), // see below
134
+ permissions: buildPermissionKeys(mod.permissions), // see below
132
135
  notes: "",
133
136
  mockupNotes: "" // Deprecated: wireframes now embedded separately in EMBEDDED_ARTIFACTS
134
137
  }
@@ -139,9 +142,10 @@ moduleSpecs[moduleCode] = {
139
142
  The HTML uses `"Role|Action"` format (e.g. `"RH Admin|Consulter"`):
140
143
 
141
144
  ```javascript
142
- function buildPermissionKeys(moduleFeature) {
145
+ // Input: permissions object from flat file (mod.permissions), NOT moduleFeature
146
+ function buildPermissionKeys(permissionsData) {
143
147
  const keys = [];
144
- const matrix = moduleFeature.specification?.permissionMatrix;
148
+ const matrix = permissionsData?.matrix || permissionsData?.permissionMatrix;
145
149
  if (!matrix) return keys;
146
150
  const actionMap = { read: "Consulter", create: "Creer", update: "Modifier",
147
151
  delete: "Supprimer", validate: "Valider", export: "Exporter",
@@ -207,25 +211,30 @@ Build a JSON object containing ALL visual artifacts from module JSON files (inde
207
211
  }
208
212
  ```
209
213
 
210
- ### Wireframes Mapping
214
+ ### Wireframes Mapping (FLAT-FILE: from screens.json)
211
215
 
212
216
  For EACH module in `master.modules[]`:
213
217
 
214
218
  ```javascript
215
- // Read the module index.json file
216
- const moduleFeature = readModuleFeature(moduleCode);
217
- const wireframes = (moduleFeature.specification?.uiWireframes || []).map(wf => ({
218
- screen: wf.screen, // e.g. "UM-list", "UM-form"
219
- section: wf.section, // e.g. "list", "form"
220
- format: wf.mockupFormat || "ascii", // "ascii" | "svg"
221
- content: wf.mockup, // ASCII art or SVG markup
222
- description: wf.description || "",
223
- elements: wf.elements || [], // ["DataGrid", "FilterBar", ...]
224
- actions: wf.actions || [], // ["filter", "sort", "create", ...]
225
- componentMapping: wf.componentMapping || [], // [{ wireframeElement, reactComponent }]
226
- layout: wf.layout || null, // { type, regions: [...] }
227
- permissionsRequired: wf.permissionsRequired || []
228
- }));
219
+ // Use flat file data from collected_data (loaded in step-01)
220
+ const mod = collected_data.modules[moduleCode];
221
+ const screens = mod.screens?.screens || [];
222
+
223
+ // Extract wireframes from screens that have mockup/wireframe data
224
+ const wireframes = screens
225
+ .filter(s => s.wireframe || s.mockup || s.mockupFormat)
226
+ .map(wf => ({
227
+ screen: wf.screen || wf.name || wf.id || "", // e.g. "UM-list", "UM-form"
228
+ section: wf.section || "", // e.g. "list", "form"
229
+ format: wf.mockupFormat || "ascii", // "ascii" | "svg"
230
+ content: wf.mockup || wf.ascii || wf.content || "", // ASCII art or SVG markup
231
+ description: wf.description || "",
232
+ elements: wf.elements || [], // ["DataGrid", "FilterBar", ...]
233
+ actions: wf.actions || [], // ["filter", "sort", "create", ...]
234
+ componentMapping: wf.componentMapping || [], // [{ wireframeElement, reactComponent }]
235
+ layout: wf.layout || null, // { type, regions: [...] }
236
+ permissionsRequired: wf.permissionsRequired || []
237
+ }));
229
238
 
230
239
  // Store in artifacts object
231
240
  EMBEDDED_ARTIFACTS.wireframes[moduleCode] = wireframes;
@@ -51,7 +51,11 @@ ELSE:
51
51
  BLOCKING ERROR: "Feature status: {feature.status}, expected consolidated"
52
52
  ```
53
53
 
54
- ### 4. Read All JSON Files
54
+ ### 4. Read All JSON Files (FLAT-FILE ARCHITECTURE)
55
+
56
+ > **CRITICAL:** Module data lives in separate flat files (entities.json, usecases.json, etc.),
57
+ > NOT inside index.json. The module index.json only contains metadata and file pointers.
58
+ > You MUST read each flat file individually.
55
59
 
56
60
  ```
57
61
  collected_data = {
@@ -63,13 +67,18 @@ collected_data = {
63
67
  }
64
68
 
65
69
  FOR each module in master.index.modules[]:
66
- moduleIndexPath = module.featureJsonPath || "{module.code}/business-analyse/v{version}/index.json"
67
- moduleIndex = READ(moduleIndexPath)
70
+ // Resolve module directory path
71
+ moduleDir = "{app}/{module.code}/business-analyse/v{version}/"
72
+ moduleIndex = READ(moduleDir + "index.json")
68
73
 
74
+ // Read ALL flat files from module directory
69
75
  collected_data.modules[module.code] = {
70
76
  index: moduleIndex,
71
- specification: moduleIndex.specification || {},
72
- analysis: moduleIndex.analysis || {}
77
+ entities: READ(moduleDir + "entities.json") || { entities: [] },
78
+ rules: READ(moduleDir + "rules.json") || { rules: [] },
79
+ usecases: READ(moduleDir + "usecases.json") || { useCases: [] },
80
+ permissions: READ(moduleDir + "permissions.json") || { roles: [], permissions: [], matrix: [] },
81
+ screens: READ(moduleDir + "screens.json") || { screens: [] }
73
82
  }
74
83
  ```
75
84
 
@@ -78,7 +87,7 @@ FOR each module in master.index.modules[]:
78
87
  ```
79
88
  JSON collected:
80
89
  Master: index.json + cadrage.json
81
- Modules: {module_count} module index files
90
+ Modules: {module_count} modules (flat files: entities, rules, usecases, permissions, screens)
82
91
  → Proceeding to data build...
83
92
  ```
84
93