@atlashub/smartstack-cli 3.14.0 → 3.16.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/dist/index.js +26 -28
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +626 -141
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/agents/efcore/migration.md +15 -0
- package/templates/skills/apex/steps/step-04-validate.md +64 -5
- package/templates/skills/application/references/frontend-verification.md +20 -0
- package/templates/skills/application/steps/step-04-backend.md +17 -1
- package/templates/skills/application/steps/step-05-frontend.md +49 -23
- package/templates/skills/application/templates-seed.md +14 -4
- package/templates/skills/business-analyse/html/ba-interactive.html +165 -0
- package/templates/skills/business-analyse/html/src/scripts/01-data-init.js +2 -0
- package/templates/skills/business-analyse/html/src/scripts/06-render-consolidation.js +85 -0
- package/templates/skills/business-analyse/html/src/styles/05-modules.css +65 -0
- package/templates/skills/business-analyse/html/src/template.html +13 -0
- package/templates/skills/business-analyse/schemas/application-schema.json +5 -0
- package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +1 -0
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +90 -0
- package/templates/skills/business-analyse/steps/step-02-decomposition.md +4 -0
- package/templates/skills/business-analyse/steps/step-03a1-setup.md +39 -0
- package/templates/skills/efcore/steps/shared/step-00-init.md +55 -0
- package/templates/skills/ralph-loop/SKILL.md +1 -0
- package/templates/skills/ralph-loop/references/category-rules.md +131 -27
- package/templates/skills/ralph-loop/references/compact-loop.md +61 -3
- package/templates/skills/ralph-loop/references/core-seed-data.md +251 -5
- package/templates/skills/ralph-loop/references/error-classification.md +143 -0
- package/templates/skills/ralph-loop/steps/step-05-report.md +54 -0
- package/templates/skills/review-code/references/smartstack-conventions.md +16 -0
- package/templates/skills/validate-feature/SKILL.md +11 -1
- package/templates/skills/validate-feature/steps/step-00-dependencies.md +121 -0
- package/templates/skills/validate-feature/steps/step-04-api-smoke.md +61 -13
- package/templates/skills/validate-feature/steps/step-05-db-validation.md +250 -0
|
@@ -2,10 +2,95 @@
|
|
|
2
2
|
CONSOLIDATION
|
|
3
3
|
============================================ */
|
|
4
4
|
function renderConsolidation() {
|
|
5
|
+
renderDataModel();
|
|
5
6
|
renderConsolInteractions();
|
|
6
7
|
renderConsolPermissions();
|
|
7
8
|
}
|
|
8
9
|
|
|
10
|
+
/* ============================================
|
|
11
|
+
DATA MODEL (cross-module entity overview)
|
|
12
|
+
============================================ */
|
|
13
|
+
function renderDataModel() {
|
|
14
|
+
const container = document.getElementById('dataModelContainer');
|
|
15
|
+
if (!container) return;
|
|
16
|
+
|
|
17
|
+
// Collect all entities from all modules
|
|
18
|
+
const allEntities = [];
|
|
19
|
+
data.modules.forEach(m => {
|
|
20
|
+
const spec = data.moduleSpecs[m.code] || {};
|
|
21
|
+
(spec.entities || []).forEach(ent => {
|
|
22
|
+
allEntities.push({ ...ent, moduleCode: m.code, moduleName: m.name || m.code });
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (allEntities.length === 0) {
|
|
27
|
+
container.innerHTML = '<p style="color:var(--text-muted);text-align:center;padding:2rem;">Aucune entite definie. Specifiez les donnees dans chaque domaine (Phase 3 > onglet Donnees).</p>';
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Build relationship index for cross-module links
|
|
32
|
+
const entityModuleMap = {};
|
|
33
|
+
allEntities.forEach(e => { entityModuleMap[e.name] = e.moduleName; });
|
|
34
|
+
|
|
35
|
+
// Render grouped by module
|
|
36
|
+
let html = '';
|
|
37
|
+
|
|
38
|
+
// Summary bar
|
|
39
|
+
const moduleCount = data.modules.filter(m => (data.moduleSpecs[m.code]?.entities || []).length > 0).length;
|
|
40
|
+
const relCount = allEntities.reduce((sum, e) => sum + (e.relationships || []).length, 0);
|
|
41
|
+
html += `
|
|
42
|
+
<div class="dm-summary">
|
|
43
|
+
<div class="dm-summary-item"><span class="dm-summary-value">${allEntities.length}</span><span class="dm-summary-label">Entites</span></div>
|
|
44
|
+
<div class="dm-summary-item"><span class="dm-summary-value">${moduleCount}</span><span class="dm-summary-label">Domaines</span></div>
|
|
45
|
+
<div class="dm-summary-item"><span class="dm-summary-value">${relCount}</span><span class="dm-summary-label">Relations</span></div>
|
|
46
|
+
</div>`;
|
|
47
|
+
|
|
48
|
+
// Entity cards grouped by module
|
|
49
|
+
data.modules.forEach(m => {
|
|
50
|
+
const spec = data.moduleSpecs[m.code] || {};
|
|
51
|
+
const entities = spec.entities || [];
|
|
52
|
+
if (entities.length === 0) return;
|
|
53
|
+
|
|
54
|
+
html += `<div class="dm-module-group">`;
|
|
55
|
+
html += `<div class="dm-module-header">
|
|
56
|
+
<span class="dm-module-name">${m.name || m.code}</span>
|
|
57
|
+
<span class="dm-module-count">${entities.length} entite${entities.length > 1 ? 's' : ''}</span>
|
|
58
|
+
</div>`;
|
|
59
|
+
|
|
60
|
+
html += `<div class="dm-entity-grid">`;
|
|
61
|
+
entities.forEach(ent => {
|
|
62
|
+
const attrs = ent.attributes || [];
|
|
63
|
+
const rels = ent.relationships || [];
|
|
64
|
+
html += `
|
|
65
|
+
<div class="dm-entity-card">
|
|
66
|
+
<div class="dm-entity-header">
|
|
67
|
+
<span class="dm-entity-name">${ent.name}</span>
|
|
68
|
+
<span class="dm-entity-attr-count">${attrs.length} champ${attrs.length > 1 ? 's' : ''}</span>
|
|
69
|
+
</div>
|
|
70
|
+
${ent.description ? `<div class="dm-entity-desc">${ent.description}</div>` : ''}
|
|
71
|
+
${attrs.length > 0 ? `
|
|
72
|
+
<table class="dm-attr-table">
|
|
73
|
+
<thead><tr><th>Champ</th><th>Description</th></tr></thead>
|
|
74
|
+
<tbody>
|
|
75
|
+
${attrs.map(a => `<tr><td class="dm-attr-name">${a.name}</td><td class="dm-attr-desc">${a.description || ''}</td></tr>`).join('')}
|
|
76
|
+
</tbody>
|
|
77
|
+
</table>` : ''}
|
|
78
|
+
${rels.length > 0 ? `
|
|
79
|
+
<div class="dm-relations">
|
|
80
|
+
<div class="dm-relations-title">Relations</div>
|
|
81
|
+
${rels.map(r => {
|
|
82
|
+
const relText = typeof r === 'string' ? r : (r.target + ' (' + r.type + ') - ' + (r.description || ''));
|
|
83
|
+
return `<div class="dm-relation-item">${relText}</div>`;
|
|
84
|
+
}).join('')}
|
|
85
|
+
</div>` : ''}
|
|
86
|
+
</div>`;
|
|
87
|
+
});
|
|
88
|
+
html += `</div></div>`;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
container.innerHTML = html;
|
|
92
|
+
}
|
|
93
|
+
|
|
9
94
|
function renderConsolInteractions() {
|
|
10
95
|
const container = document.getElementById('consolInteractions');
|
|
11
96
|
if (!container || data.dependencies.length === 0) return;
|
|
@@ -323,3 +323,68 @@
|
|
|
323
323
|
}
|
|
324
324
|
.e2e-step-module { font-weight: 600; color: var(--primary-light); font-size: 0.65rem; }
|
|
325
325
|
.e2e-step-action { color: var(--text-bright); }
|
|
326
|
+
|
|
327
|
+
/* ============================================
|
|
328
|
+
DATA MODEL (Consolidation)
|
|
329
|
+
============================================ */
|
|
330
|
+
.dm-summary {
|
|
331
|
+
display: flex; gap: 1.5rem; margin-bottom: 1.5rem;
|
|
332
|
+
padding: 1rem 1.5rem; background: var(--bg-card);
|
|
333
|
+
border: 1px solid var(--border); border-radius: 10px;
|
|
334
|
+
}
|
|
335
|
+
.dm-summary-item { display: flex; align-items: baseline; gap: 0.4rem; }
|
|
336
|
+
.dm-summary-value { font-size: 1.4rem; font-weight: 700; color: var(--text-bright); }
|
|
337
|
+
.dm-summary-label { font-size: 0.8rem; color: var(--text-muted); }
|
|
338
|
+
.dm-module-group { margin-bottom: 1.5rem; }
|
|
339
|
+
.dm-module-header {
|
|
340
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
341
|
+
padding: 0.5rem 0; margin-bottom: 0.75rem;
|
|
342
|
+
border-bottom: 2px solid var(--primary);
|
|
343
|
+
}
|
|
344
|
+
.dm-module-name { font-weight: 700; color: var(--primary-light); font-size: 1rem; }
|
|
345
|
+
.dm-module-count { font-size: 0.75rem; color: var(--text-muted); }
|
|
346
|
+
.dm-entity-grid {
|
|
347
|
+
display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 1rem;
|
|
348
|
+
}
|
|
349
|
+
.dm-entity-card {
|
|
350
|
+
background: var(--bg-card); border: 1px solid var(--border);
|
|
351
|
+
border-radius: 10px; overflow: hidden;
|
|
352
|
+
transition: border-color var(--transition-fast);
|
|
353
|
+
}
|
|
354
|
+
.dm-entity-card:hover { border-color: var(--border-light); }
|
|
355
|
+
.dm-entity-header {
|
|
356
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
357
|
+
padding: 0.6rem 0.75rem; background: var(--bg-hover);
|
|
358
|
+
border-bottom: 1px solid var(--border);
|
|
359
|
+
}
|
|
360
|
+
.dm-entity-name { font-weight: 600; color: var(--text-bright); font-size: 0.95rem; }
|
|
361
|
+
.dm-entity-attr-count {
|
|
362
|
+
font-size: 0.65rem; color: var(--text-muted);
|
|
363
|
+
background: rgba(99,102,241,0.1); padding: 0.1rem 0.4rem; border-radius: 4px;
|
|
364
|
+
}
|
|
365
|
+
.dm-entity-desc {
|
|
366
|
+
padding: 0.5rem 0.75rem; font-size: 0.8rem; color: var(--text-muted);
|
|
367
|
+
border-bottom: 1px solid var(--border);
|
|
368
|
+
}
|
|
369
|
+
.dm-attr-table { width: 100%; border-collapse: collapse; }
|
|
370
|
+
.dm-attr-table th {
|
|
371
|
+
text-align: left; font-size: 0.65rem; text-transform: uppercase;
|
|
372
|
+
letter-spacing: 0.05em; color: var(--text-muted); padding: 0.4rem 0.75rem;
|
|
373
|
+
border-bottom: 1px solid var(--border); font-weight: 600;
|
|
374
|
+
}
|
|
375
|
+
.dm-attr-table td { padding: 0.35rem 0.75rem; font-size: 0.8rem; border-bottom: 1px solid rgba(51,65,85,0.2); }
|
|
376
|
+
.dm-attr-name { font-weight: 500; color: var(--text-bright); white-space: nowrap; }
|
|
377
|
+
.dm-attr-desc { color: var(--text-muted); }
|
|
378
|
+
.dm-relations {
|
|
379
|
+
padding: 0.5rem 0.75rem; border-top: 1px solid var(--border);
|
|
380
|
+
background: rgba(6,182,212,0.03);
|
|
381
|
+
}
|
|
382
|
+
.dm-relations-title {
|
|
383
|
+
font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.05em;
|
|
384
|
+
color: var(--accent); font-weight: 600; margin-bottom: 0.3rem;
|
|
385
|
+
}
|
|
386
|
+
.dm-relation-item {
|
|
387
|
+
font-size: 0.8rem; color: var(--text); padding: 0.15rem 0;
|
|
388
|
+
padding-left: 0.75rem; border-left: 2px solid var(--accent);
|
|
389
|
+
margin-bottom: 0.2rem;
|
|
390
|
+
}
|
|
@@ -96,6 +96,10 @@
|
|
|
96
96
|
<!-- Phase 4 : Consolidation -->
|
|
97
97
|
<div class="nav-group">
|
|
98
98
|
<div class="nav-group-title">4. Consolidation</div>
|
|
99
|
+
<a class="nav-item" onclick="showSection('consol-datamodel')" data-section="consol-datamodel">
|
|
100
|
+
<span class="nav-icon">●</span> Modele de donnees
|
|
101
|
+
<span class="nav-badge" id="entityCount">0</span>
|
|
102
|
+
</a>
|
|
99
103
|
<a class="nav-item" onclick="showSection('consol-interactions')" data-section="consol-interactions">
|
|
100
104
|
<span class="nav-icon">●</span> Interactions
|
|
101
105
|
</a>
|
|
@@ -500,6 +504,15 @@
|
|
|
500
504
|
PHASE 4 : CONSOLIDATION
|
|
501
505
|
================================================================ -->
|
|
502
506
|
|
|
507
|
+
<!-- SECTION: Modele de donnees -->
|
|
508
|
+
<div class="section" id="consol-datamodel" style="display:none;">
|
|
509
|
+
<h2 class="section-title">Modele de donnees</h2>
|
|
510
|
+
<p class="section-subtitle">Vue d'ensemble de toutes les entites metier, leurs attributs et leurs relations entre domaines.</p>
|
|
511
|
+
<div id="dataModelContainer">
|
|
512
|
+
<p style="color:var(--text-muted);text-align:center;padding:2rem;">Le modele de donnees sera genere a partir des specifications de chaque domaine.</p>
|
|
513
|
+
</div>
|
|
514
|
+
</div>
|
|
515
|
+
|
|
503
516
|
<!-- SECTION: Interactions cross-module -->
|
|
504
517
|
<div class="section" id="consol-interactions" style="display:none;">
|
|
505
518
|
<h2 class="section-title">Interactions entre domaines</h2>
|
|
@@ -48,6 +48,11 @@
|
|
|
48
48
|
"const": "interactive",
|
|
49
49
|
"description": "Analysis mode — always interactive (AI listens, reformulates, challenges, validates)"
|
|
50
50
|
},
|
|
51
|
+
"tablePrefix": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"pattern": "^[a-z]{2,5}_$",
|
|
54
|
+
"description": "Application table prefix for database tables (e.g., rh_, fi_, crm_). Defined during cadrage, used by all entities in this application."
|
|
55
|
+
},
|
|
51
56
|
"workflow": {
|
|
52
57
|
"type": "object",
|
|
53
58
|
"description": "Iterative module loop state",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"previousVersion": { "type": ["string", "null"] },
|
|
26
26
|
"changeReason": { "type": ["string", "null"] },
|
|
27
27
|
"analysisMode": { "type": "string", "const": "interactive", "description": "Analysis mode — always interactive (AI listens, reformulates, challenges, validates)" },
|
|
28
|
+
"tablePrefix": { "type": "string", "pattern": "^[a-z]{2,5}_$", "description": "Application table prefix inherited from parent (e.g., rh_, fi_, crm_)" },
|
|
28
29
|
"mcpAvailable": { "type": "boolean" },
|
|
29
30
|
"scope": { "type": "string", "enum": ["application", "module"], "default": "module" },
|
|
30
31
|
"applicationRef": { "type": ["string", "null"], "description": "Parent application feature ID (FEAT-XXX)" },
|
|
@@ -241,6 +241,49 @@ Use these techniques:
|
|
|
241
241
|
|
|
242
242
|
Ask challenge questions via AskUserQuestion (1-2 batches of max 4).
|
|
243
243
|
|
|
244
|
+
#### 4d-bis. Entity Sourcing Pattern (MANDATORY for detected dependencies)
|
|
245
|
+
|
|
246
|
+
> **When the analysis detects a referenced entity/concept (e.g., "Projets" referenced by activities, "Clients" referenced by orders), ALWAYS ask how this entity is sourced.**
|
|
247
|
+
> This question detects potential new modules that were not mentioned in the original brief.
|
|
248
|
+
|
|
249
|
+
For EACH referenced entity/concept detected during phases 2-4 that is NOT already covered by an identified module:
|
|
250
|
+
|
|
251
|
+
Ask via AskUserQuestion:
|
|
252
|
+
```
|
|
253
|
+
question: "{language == 'fr'
|
|
254
|
+
? 'Les {entity_plural} auxquel(le)s les {parent_entity_plural} sont lié(e)s : comment sont-ils gérés ?'
|
|
255
|
+
: 'The {entity_plural} that {parent_entity_plural} are linked to: how are they managed?'}"
|
|
256
|
+
header: "{entity_name}"
|
|
257
|
+
options:
|
|
258
|
+
- label: "{language == 'fr' ? 'Gérés dans l\'app' : 'Managed in app'}"
|
|
259
|
+
description: "{language == 'fr'
|
|
260
|
+
? 'Les {entity_plural} sont créés et gérés dans cette application (liste simple)'
|
|
261
|
+
: '{entity_plural} are created and managed in this application (simple list)'}"
|
|
262
|
+
- label: "{language == 'fr' ? 'Nouveau module dédié' : 'New dedicated module'}"
|
|
263
|
+
description: "{language == 'fr'
|
|
264
|
+
? 'Les {entity_plural} méritent leur propre module avec CRUD complet, permissions et navigation'
|
|
265
|
+
: '{entity_plural} deserve their own module with full CRUD, permissions and navigation'}"
|
|
266
|
+
- label: "{language == 'fr' ? 'Système externe' : 'External system'}"
|
|
267
|
+
description: "{language == 'fr'
|
|
268
|
+
? 'Les {entity_plural} viennent d\'un autre système (import ou API)'
|
|
269
|
+
: '{entity_plural} come from another system (import or API)'}"
|
|
270
|
+
- label: "{language == 'fr' ? 'Liste simple en config' : 'Simple config list'}"
|
|
271
|
+
description: "{language == 'fr'
|
|
272
|
+
? 'Juste une liste configurable par l\'admin, pas un module complet'
|
|
273
|
+
: 'Just a configurable list managed by admin, not a full module'}"
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Processing each answer:**
|
|
277
|
+
|
|
278
|
+
| Choice | Action |
|
|
279
|
+
|--------|--------|
|
|
280
|
+
| **Gérés dans l'app** | Entity stays as a child/section of the current module. Note in coverageMatrix. |
|
|
281
|
+
| **Nouveau module dédié** | **Add new module to `{pre_analysis}.detected_modules[]`**. Flag for inclusion in decomposition (step-02). Add to `coverageMatrix` as mustHave with anticipated sections (list, detail, create, edit). This module becomes a dependency of the referencing module. |
|
|
282
|
+
| **Système externe** | Flag for integration specification. Add to `coverageMatrix` as integration. Load `questionnaire/05-integrations.md` if not already loaded. |
|
|
283
|
+
| **Liste simple en config** | Entity becomes a lookup/reference table (no dedicated module). Note in coverageMatrix as config data. |
|
|
284
|
+
|
|
285
|
+
> **CRITICAL:** The "Nouveau module dédié" option is essential for detecting modules not mentioned in the original brief. Without it, complex entities get reduced to simple config lists when they deserve full CRUD management.
|
|
286
|
+
|
|
244
287
|
#### 4e. Risks & Success Criteria (ALWAYS — from `questionnaire/14-risk-assumptions.md` and `questionnaire/15-success-metrics.md`)
|
|
245
288
|
|
|
246
289
|
Select the most pertinent questions:
|
|
@@ -350,6 +393,45 @@ options:
|
|
|
350
393
|
IF single-module mode:
|
|
351
394
|
Same role definition but inferred from stakeholders
|
|
352
395
|
|
|
396
|
+
### 6b. Table Prefix Definition (MANDATORY)
|
|
397
|
+
|
|
398
|
+
> **Every business application MUST define a table prefix.**
|
|
399
|
+
> This prefix identifies which application a database table belongs to (e.g., `rh_Employees`, `fi_Invoices`).
|
|
400
|
+
|
|
401
|
+
**Process:**
|
|
402
|
+
|
|
403
|
+
1. Derive a suggested prefix from the application name:
|
|
404
|
+
- Use the most recognizable abbreviation (2-5 lowercase letters + `_`)
|
|
405
|
+
- Examples: HumanResources → `rh_`, SalesManagement → `sales_`, Finance → `fi_`, CRM → `crm_`
|
|
406
|
+
|
|
407
|
+
2. **Display as markdown** (direct text output):
|
|
408
|
+
|
|
409
|
+
```
|
|
410
|
+
{language == "fr"
|
|
411
|
+
? "### Préfixe de table\n\nToutes les tables de cette application en base de données porteront un préfixe pour identifier leur appartenance.\n\nPréfixe suggéré : **`{suggested_prefix}`**\n\nExemple : `{suggested_prefix}Employees`, `{suggested_prefix}Contracts`"
|
|
412
|
+
: "### Table Prefix\n\nAll database tables for this application will carry a prefix to identify their ownership.\n\nSuggested prefix: **`{suggested_prefix}`**\n\nExample: `{suggested_prefix}Employees`, `{suggested_prefix}Contracts`"}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
3. Ask via AskUserQuestion:
|
|
416
|
+
```
|
|
417
|
+
question: "{language == 'fr' ? 'Ce préfixe de table vous convient-il ?' : 'Does this table prefix work for you?'}"
|
|
418
|
+
header: "Préfixe"
|
|
419
|
+
options:
|
|
420
|
+
- label: "{language == 'fr' ? 'Oui, parfait' : 'Yes, perfect'}"
|
|
421
|
+
description: "{language == 'fr' ? 'Utiliser le préfixe suggéré' : 'Use the suggested prefix'}"
|
|
422
|
+
- label: "{language == 'fr' ? 'Personnaliser' : 'Customize'}"
|
|
423
|
+
description: "{language == 'fr' ? 'Choisir un autre préfixe (2-5 lettres minuscules + _)' : 'Choose a different prefix (2-5 lowercase letters + _)'}"
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
4. IF "Customize" → ask for custom prefix via AskUserQuestion (open-ended "Other" option)
|
|
427
|
+
|
|
428
|
+
5. **Validate the prefix:**
|
|
429
|
+
- Format: `^[a-z]{2,5}_$` (2-5 lowercase letters followed by underscore)
|
|
430
|
+
- Must NOT collide with platform prefixes: `auth_`, `nav_`, `usr_`, `ai_`, `cfg_`, `wkf_`, `support_`, `entra_`, `ref_`, `loc_`, `lic_`, `tenant_`
|
|
431
|
+
- If collision detected → ask the user to choose another prefix
|
|
432
|
+
|
|
433
|
+
6. Store in `metadata.tablePrefix`
|
|
434
|
+
|
|
353
435
|
### 7. Coverage Matrix with Sections & Resources (MANDATORY)
|
|
354
436
|
|
|
355
437
|
> **ENRICHMENT: The coverage matrix now includes anticipated sections (Level 4) and resources (Level 5).**
|
|
@@ -416,6 +498,14 @@ Use ba-writer to enrich master feature.json. **Follow the STRUCTURE CARDS exactl
|
|
|
416
498
|
See [references/cadrage-structure-cards.md](../references/cadrage-structure-cards.md) for exact JSON formats of: `stakeholders[]`, `applicationRoles[]`, `risks[]`, `acceptanceCriteria[]`, `coverageMatrix[]`, `codebaseContext`.
|
|
417
499
|
|
|
418
500
|
```
|
|
501
|
+
ba-writer.enrichSection({
|
|
502
|
+
featureId: {feature_id},
|
|
503
|
+
section: "metadata",
|
|
504
|
+
data: {
|
|
505
|
+
tablePrefix: "{from Phase 5, section 6b — validated prefix, e.g., rh_}"
|
|
506
|
+
}
|
|
507
|
+
})
|
|
508
|
+
|
|
419
509
|
ba-writer.enrichSection({
|
|
420
510
|
featureId: {feature_id},
|
|
421
511
|
section: "cadrage",
|
|
@@ -100,6 +100,10 @@ Display the identified modules as markdown:
|
|
|
100
100
|
```
|
|
101
101
|
## Modules identifiés pour {application_name}
|
|
102
102
|
|
|
103
|
+
{language == "fr"
|
|
104
|
+
? "**Préfixe de table :** `{metadata.tablePrefix}` — toutes les tables de cette application seront préfixées (ex: `{metadata.tablePrefix}Customers`, `{metadata.tablePrefix}Orders`)"
|
|
105
|
+
: "**Table prefix:** `{metadata.tablePrefix}` — all tables in this application will be prefixed (e.g., `{metadata.tablePrefix}Customers`, `{metadata.tablePrefix}Orders`)"}
|
|
106
|
+
|
|
103
107
|
| # | Module | Type | Priorité | Complexité | Sections pressenties | Entités |
|
|
104
108
|
|---|--------|------|----------|------------|---------------------|---------|
|
|
105
109
|
| 1 | Customers | data-centric | must | medium | list, detail, create, edit | Customer, Address, Contact |
|
|
@@ -349,6 +349,45 @@ options:
|
|
|
349
349
|
description: "Pas de référence à {completedModule}"
|
|
350
350
|
```
|
|
351
351
|
|
|
352
|
+
#### 5-bis. Unresolved Entity Dependencies (New Module Detection)
|
|
353
|
+
|
|
354
|
+
> **When an entity reference is detected that does NOT belong to any completed or planned module, apply the Entity Sourcing Pattern from step-01-cadrage (section 4d-bis).**
|
|
355
|
+
|
|
356
|
+
For each entity referenced by {currentModule} that is NOT covered by any existing/planned module:
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
question: "{language == 'fr'
|
|
360
|
+
? 'Les {entity_plural} référencés par {currentModule} ne font partie d\'aucun module. Comment les gérer ?'
|
|
361
|
+
: '{entity_plural} referenced by {currentModule} are not part of any module. How should they be managed?'}"
|
|
362
|
+
header: "{entity_name}"
|
|
363
|
+
options:
|
|
364
|
+
- label: "{language == 'fr' ? 'Dans ce module' : 'In this module'}"
|
|
365
|
+
description: "{language == 'fr'
|
|
366
|
+
? 'Gérer les {entity_plural} comme une section/entité de {currentModule}'
|
|
367
|
+
: 'Manage {entity_plural} as a section/entity of {currentModule}'}"
|
|
368
|
+
- label: "{language == 'fr' ? 'Nouveau module dédié' : 'New dedicated module'}"
|
|
369
|
+
description: "{language == 'fr'
|
|
370
|
+
? 'Créer un module complet avec CRUD, permissions et navigation'
|
|
371
|
+
: 'Create a full module with CRUD, permissions and navigation'}"
|
|
372
|
+
- label: "{language == 'fr' ? 'Système externe' : 'External system'}"
|
|
373
|
+
description: "{language == 'fr'
|
|
374
|
+
? 'Import ou API depuis un autre système'
|
|
375
|
+
: 'Import or API from another system'}"
|
|
376
|
+
- label: "{language == 'fr' ? 'Liste de référence' : 'Reference list'}"
|
|
377
|
+
description: "{language == 'fr'
|
|
378
|
+
? 'Table de lookup configurable par l\'admin'
|
|
379
|
+
: 'Admin-configurable lookup table'}"
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**IF "Nouveau module dédié" is selected:**
|
|
383
|
+
1. Add new module to master `modules[]` via ba-writer (status: "pending", sortOrder: after current module)
|
|
384
|
+
2. Update dependency graph: current module depends on the new module
|
|
385
|
+
3. **WARNING:** The new module will need specification AFTER the current one. Display:
|
|
386
|
+
```
|
|
387
|
+
"⚠ Nouveau module '{entity_name}' ajouté. Il sera spécifié après {currentModule}."
|
|
388
|
+
```
|
|
389
|
+
4. Update `metadata.workflow.moduleOrder` to include the new module (inserted after its dependents)
|
|
390
|
+
|
|
352
391
|
---
|
|
353
392
|
|
|
354
393
|
## NEXT STEP
|
|
@@ -16,6 +16,61 @@ Detect EF Core project structure, identify DbContext (Core vs Extensions), and l
|
|
|
16
16
|
|
|
17
17
|
## EXECUTION SEQUENCE:
|
|
18
18
|
|
|
19
|
+
### 0. Ensure dotnet ef Available (Platform-Aware)
|
|
20
|
+
|
|
21
|
+
> **CRITICAL:** On Windows (Git Bash, MSYS2), `dotnet ef` may not be on the shell PATH
|
|
22
|
+
> even though it's installed. This step fixes PATH before any EF Core command.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
ensure_dotnet_ef() {
|
|
26
|
+
# Quick check: already available?
|
|
27
|
+
if dotnet ef --version &>/dev/null; then
|
|
28
|
+
DOTNET_EF_VERSION=$(dotnet ef --version 2>/dev/null)
|
|
29
|
+
echo "dotnet-ef: $DOTNET_EF_VERSION"
|
|
30
|
+
return 0
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
echo "dotnet-ef not on PATH, attempting platform-aware fix..."
|
|
34
|
+
|
|
35
|
+
# Try all known .NET global tools locations
|
|
36
|
+
# - $USERPROFILE/.dotnet/tools → Windows via Git Bash (USERPROFILE=C:\Users\xxx)
|
|
37
|
+
# - $HOME/.dotnet/tools → Linux/macOS or Git Bash fallback
|
|
38
|
+
# - $LOCALAPPDATA/Microsoft/dotnet/tools → Windows alternate location
|
|
39
|
+
for TOOLS_DIR in \
|
|
40
|
+
"$USERPROFILE/.dotnet/tools" \
|
|
41
|
+
"$HOME/.dotnet/tools" \
|
|
42
|
+
"$LOCALAPPDATA/Microsoft/dotnet/tools"; do
|
|
43
|
+
if [ -n "$TOOLS_DIR" ] && [ -d "$TOOLS_DIR" ]; then
|
|
44
|
+
export PATH="$TOOLS_DIR:$PATH"
|
|
45
|
+
echo " PATH += $TOOLS_DIR"
|
|
46
|
+
fi
|
|
47
|
+
done
|
|
48
|
+
|
|
49
|
+
# Verify after PATH fix
|
|
50
|
+
if dotnet ef --version &>/dev/null; then
|
|
51
|
+
DOTNET_EF_VERSION=$(dotnet ef --version 2>/dev/null)
|
|
52
|
+
echo "dotnet-ef: $DOTNET_EF_VERSION (found after PATH fix)"
|
|
53
|
+
return 0
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
echo "ERROR: dotnet-ef not available"
|
|
57
|
+
echo "Install with: dotnet tool install --global dotnet-ef"
|
|
58
|
+
echo ""
|
|
59
|
+
echo "If installed but not found, check:"
|
|
60
|
+
echo " Windows: %USERPROFILE%\\.dotnet\\tools must be in PATH"
|
|
61
|
+
echo " Linux: ~/.dotnet/tools must be in PATH"
|
|
62
|
+
exit 1
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
ensure_dotnet_ef
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**IMPORTANT — WSL pitfall:**
|
|
69
|
+
If the shell resolves `$HOME` to `/home/{user}` (WSL path) instead of `/c/Users/{user}` (Git Bash),
|
|
70
|
+
the .NET SDK may not be found even if `dotnet-ef` is. Use `$USERPROFILE` first on Windows.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
19
74
|
### 1. Detect EF Core Project
|
|
20
75
|
|
|
21
76
|
```bash
|
|
@@ -115,6 +115,7 @@ LOAD → GENERATE → COMPILE → TEST → [FAIL?] → FIX → RE-TEST → [PASS
|
|
|
115
115
|
| `references/category-rules.md` | Step-02 and compact loop (execution rules per category) |
|
|
116
116
|
| `references/compact-loop.md` | Step-04 section 5 (inline execution after first iteration) |
|
|
117
117
|
| `references/core-seed-data.md` | Infrastructure task with seed data keywords |
|
|
118
|
+
| `references/error-classification.md` | Build failure in compact loop or validation (error diagnosis) |
|
|
118
119
|
| `references/team-orchestration.md` | Step-00 when multi-module detected (2+ PRDs) |
|
|
119
120
|
</step_files>
|
|
120
121
|
|