@atlashub/smartstack-cli 4.48.0 → 4.50.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/testing-ba-e2e.md +76 -24
- package/package.json +1 -1
- package/templates/agents/gitflow/init.md +26 -0
- package/templates/skills/apex/references/parallel-execution.md +22 -4
- package/templates/skills/apex/steps/step-00-init.md +38 -0
- package/templates/skills/apex/steps/step-03a-layer0-domain.md +21 -0
- package/templates/skills/apex/steps/step-03b-layer1-seed.md +60 -0
- package/templates/skills/apex/steps/step-03c-layer2-backend.md +124 -13
- package/templates/skills/apex/steps/step-03d-layer3-frontend.md +32 -0
- package/templates/skills/application/references/backend-controller-hierarchy.md +14 -4
- package/templates/skills/business-analyse/patterns/suggestion-catalog.md +2 -0
- package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +2 -0
- package/templates/skills/business-analyse/schemas/application-schema.json +36 -1
- package/templates/skills/business-analyse/schemas/sections/specification-schema.json +19 -0
- package/templates/skills/business-analyse/steps/step-00-init.md +64 -14
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +49 -2
- package/templates/skills/business-analyse/steps/step-02-structure.md +41 -17
- package/templates/skills/business-analyse/steps/step-04-consolidate.md +171 -0
- package/templates/skills/business-analyse-develop/references/quality-gates.md +91 -1
- package/templates/skills/business-analyse-develop/steps/step-01-task.md +147 -1
- package/templates/skills/business-analyse-handoff/references/acceptance-criteria.md +53 -1
- package/templates/skills/business-analyse-handoff/references/handoff-file-templates.md +42 -0
- package/templates/skills/business-analyse-handoff/references/handoff-mappings.md +15 -1
- package/templates/skills/business-analyse-handoff/references/prd-generation.md +59 -0
- package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +25 -1
- package/templates/skills/business-analyse-handoff/steps/step-02-export.md +32 -4
- package/templates/skills/business-analyse-html/html/ba-interactive.html +80 -11
- package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +4 -2
- package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +16 -2
- package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +19 -4
- package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +1 -1
- package/templates/skills/business-analyse-html/html/src/styles/03-navigation.css +2 -2
- package/templates/skills/business-analyse-html/html/src/styles/05-modules.css +38 -0
- package/templates/skills/business-analyse-html/references/data-build.md +4 -1
- package/templates/skills/business-analyse-html/references/data-mapping.md +4 -1
- package/templates/skills/business-analyse-html/steps/step-02-build-data.md +113 -1
- package/templates/skills/business-analyse-html/steps/step-04-verify.md +17 -1
- package/templates/skills/controller/references/mcp-scaffold-workflow.md +8 -4
- package/templates/skills/controller/steps/step-05-validate.md +2 -2
- package/templates/skills/controller/templates.md +4 -3
- package/templates/skills/feature-full/steps/step-01-implementation.md +18 -5
|
@@ -9,6 +9,38 @@ parent_step: steps/step-03-execute.md
|
|
|
9
9
|
|
|
10
10
|
# Layer 3 — Frontend (Pages + I18n + Documentation)
|
|
11
11
|
|
|
12
|
+
### Companion Specs Loading (delegate mode)
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
if (delegate_mode && specification_loading_plan) {
|
|
16
|
+
const specsDir = path.dirname(delegate_prd_path);
|
|
17
|
+
// Layer 3 loads: screens + usecases companions
|
|
18
|
+
for (const file of specification_loading_plan.layer3_frontend) {
|
|
19
|
+
const specPath = path.join(specsDir, file);
|
|
20
|
+
if (fileExists(specPath)) {
|
|
21
|
+
const specData = readJSON(specPath);
|
|
22
|
+
if (specData.screens) {
|
|
23
|
+
// Full screen definitions: columns[], fields[], filters[], actions[], kpis[]
|
|
24
|
+
// Use for: DataTable columns, form fields, filter configs, action buttons, dashboard KPIs
|
|
25
|
+
console.log(`Loaded screens: ${specData.screens.length} screen specs with columns/fields/filters`);
|
|
26
|
+
}
|
|
27
|
+
if (specData.useCases || specData.usecases) {
|
|
28
|
+
const ucs = specData.useCases || specData.usecases;
|
|
29
|
+
// UC steps inform form validation, navigation flows, error states
|
|
30
|
+
console.log(`Loaded usecases: ${ucs.length} use cases for form flows`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> When companion specs are loaded:
|
|
38
|
+
> - **List pages**: use `screen.columns[]` for exact DataTable column definitions (key, label, type, sortable)
|
|
39
|
+
> - **Form pages**: use `screen.fields[]` for exact form field definitions (name, type, required, validation)
|
|
40
|
+
> - **Filter configs**: use `screen.filters[]` for search/filter UI generation
|
|
41
|
+
> - **Dashboard pages**: use `screen.kpis[]` for KPI card and chart definitions
|
|
42
|
+
> - **Actions**: use `screen.actions[]` for action buttons (create, export, bulk operations)
|
|
43
|
+
|
|
12
44
|
### ⛔ HARD RULE — /ui-components is NON-NEGOTIABLE (read BEFORE any Layer 3 action)
|
|
13
45
|
|
|
14
46
|
> **VIOLATION CHECK:** If ANY .tsx page file was created by Write tool WITHOUT
|
|
@@ -38,14 +38,24 @@ Api/Controllers/
|
|
|
38
38
|
The generated controller uses NavRoute attribute:
|
|
39
39
|
|
|
40
40
|
```csharp
|
|
41
|
-
[NavRoute("{full_path}")]
|
|
42
41
|
[ApiController]
|
|
43
|
-
[
|
|
42
|
+
[NavRoute("{full_path}")]
|
|
43
|
+
[Microsoft.AspNetCore.Authorization.Authorize]
|
|
44
|
+
[Produces("application/json")]
|
|
45
|
+
[Tags("{EntityNamePlural}")]
|
|
44
46
|
public class {EntityName}Controller : ControllerBase
|
|
45
47
|
{
|
|
48
|
+
private readonly ISender _mediator;
|
|
49
|
+
|
|
50
|
+
public {EntityName}Controller(ISender mediator) => _mediator = mediator;
|
|
51
|
+
|
|
46
52
|
[HttpGet]
|
|
47
|
-
[RequirePermission(Permissions.{Application}.{Module}.
|
|
48
|
-
|
|
53
|
+
[RequirePermission(Permissions.{Application}.{Module}.View)]
|
|
54
|
+
[ProducesResponseType(typeof(List<{EntityName}ListDto>), StatusCodes.Status200OK)]
|
|
55
|
+
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
|
56
|
+
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
|
57
|
+
public async Task<ActionResult<List<{EntityName}ListDto>>> GetAll(CancellationToken ct)
|
|
58
|
+
=> Ok(await _mediator.Send(new Get{EntityNamePlural}Query(), ct));
|
|
49
59
|
|
|
50
60
|
// ... other CRUD methods
|
|
51
61
|
}
|
|
@@ -27,6 +27,7 @@ Suggests companion modules based on primary module type:
|
|
|
27
27
|
| **Notifications** | notification, alert, email, message, broadcast | Templates, Channels, Scheduling, Preferences | Notification systems need template management, multi-channel support, scheduling |
|
|
28
28
|
| **Reporting** | report, dashboard, analytics, BI, metrics | Dashboards, Exports, Scheduling, AlertRules | Reporting needs visualization, scheduled distribution, and data export |
|
|
29
29
|
| **API Management / Integrations** | api, external, integration, webhook, export, data-export, machine-to-machine | ExternalApps, DataExportEndpoints, ExportAccess, AuditLogs, ApiKeys | API platforms need app registration, key management, granular endpoint access, rate limiting, and audit logging |
|
|
30
|
+
| **Client Portal** | portal, external, client, fournisseur, partenaire, tiers | MyRequests, ClientDashboard, PortalNotifications | Les utilisateurs externes ont besoin de vues self-service, suivi de statut et soumission limitée |
|
|
30
31
|
|
|
31
32
|
---
|
|
32
33
|
|
|
@@ -48,6 +49,7 @@ Suggests standard sections based on detected conditions:
|
|
|
48
49
|
| **Report generation** | Reporting Engine | Automated business reporting | Add section with template library, scheduling, distribution |
|
|
49
50
|
| **External integrations** | Integration Layer | System-to-system communication | Add section with API specifications, webhook handling, sync strategy |
|
|
50
51
|
| **Regulatory compliance** | Compliance & Audit | Legal/industry requirements | Add section with audit logging, data retention, retention periods |
|
|
52
|
+
| **Utilisateurs externes / portail détecté** | Sections portail client | Les utilisateurs externes ont besoin d'un espace dédié simplifié | Pour chaque module "shared" : suggérer section portal-specific (ex: `my-requests`, `portal-dashboard`) avec permissions read-only ou write limitée. Pour modules "external" : s'assurer que les sections ont une UX adaptée portail (navigation simplifiée, pas de fonctions admin). |
|
|
51
53
|
|
|
52
54
|
---
|
|
53
55
|
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
| Question | Si la réponse est vague | Relance recommandée |
|
|
89
89
|
|----------|------------------------|---------------------|
|
|
90
90
|
| Q2.1 (utilisateurs) | Un seul type mentionné | "Pensez aux différents moments de la journée : qui saisit ? Qui consulte les rapports ? Qui gère les cas particuliers ?" |
|
|
91
|
+
| Q2.1 (utilisateurs) | Utilisateurs hors entreprise mentionnés (clients, fournisseurs, partenaires) | "Ces utilisateurs externes accéderont-ils via un espace dédié (portail) ou la même interface que vos employés ?" |
|
|
91
92
|
| Q2.5 (tâches) | Tâches génériques | "Quand il arrive le matin et ouvre le système, quelle est sa première action ?" |
|
|
92
93
|
| Q2.9 (restrictions) | Réponse ambiguë | "Un employé voit-il les données salariales ? Un manager voit-il uniquement son équipe ou toute l'entreprise ?" |
|
|
93
94
|
| Q2.13 (indispensable) | Tout est indispensable | "Si vous ne pouviez garder que 3 fonctionnalités pour un premier lancement, lesquelles ?" |
|
|
@@ -103,6 +104,7 @@
|
|
|
103
104
|
| Tout est vital (> 10 vitaux) | Classification non réfléchie | Appliquer le test de classification : "Si on enlevait X, le système aurait-il encore de la valeur ?" |
|
|
104
105
|
| Aucune exclusion identifiée | Périmètre non borné | "Y a-t-il des aspects qui relèvent d'un autre projet ou d'une version future ?" |
|
|
105
106
|
| Parcours linéaire sans alternative | Seul le cas idéal est décrit | "Que se passe-t-il à l'étape X si la condition Y n'est pas remplie ?" |
|
|
107
|
+
| "Nos clients doivent pouvoir..." ou "Les fournisseurs voient..." | Utilisateurs externes accédant au système | Déclencher détection portail : classifier les profils en interne/externe. SmartStack gère le déploiement multi-tenant automatiquement. |
|
|
106
108
|
|
|
107
109
|
---
|
|
108
110
|
|
|
@@ -66,6 +66,12 @@
|
|
|
66
66
|
"type": "string",
|
|
67
67
|
"description": "Lucide icon name for application navigation entry (e.g., users, shopping-cart). Confirmed in step-02."
|
|
68
68
|
},
|
|
69
|
+
"portalMode": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"enum": ["internal-only", "portal-only", "dual"],
|
|
72
|
+
"default": "internal-only",
|
|
73
|
+
"description": "Whether the app serves internal users, external portal users, or both"
|
|
74
|
+
},
|
|
69
75
|
"workflow": {
|
|
70
76
|
"type": "object",
|
|
71
77
|
"description": "Iterative module loop state",
|
|
@@ -126,7 +132,12 @@
|
|
|
126
132
|
"involvement": { "type": "string", "enum": ["approver", "decision-maker", "consulted", "informed", "end-user"] },
|
|
127
133
|
"tasks": { "type": "array", "items": { "type": "string" } },
|
|
128
134
|
"frequency": { "type": "string" },
|
|
129
|
-
"painPoints": { "type": "array", "items": { "type": "string" } }
|
|
135
|
+
"painPoints": { "type": "array", "items": { "type": "string" } },
|
|
136
|
+
"audience": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"enum": ["internal", "external", "shared"],
|
|
139
|
+
"description": "Whether this stakeholder is internal, external portal user, or both"
|
|
140
|
+
}
|
|
130
141
|
}
|
|
131
142
|
}
|
|
132
143
|
},
|
|
@@ -204,6 +215,11 @@
|
|
|
204
215
|
"type": "array",
|
|
205
216
|
"items": { "type": "string" },
|
|
206
217
|
"description": "Anticipated resources (Level 5) for this requirement — e.g., user-grid, user-form, user-card"
|
|
218
|
+
},
|
|
219
|
+
"audience": {
|
|
220
|
+
"type": "string",
|
|
221
|
+
"enum": ["internal", "external", "shared"],
|
|
222
|
+
"description": "Target audience. Only set when portalMode is 'dual'."
|
|
207
223
|
}
|
|
208
224
|
}
|
|
209
225
|
}
|
|
@@ -257,6 +273,11 @@
|
|
|
257
273
|
"type": "string",
|
|
258
274
|
"enum": ["simple", "medium", "complex"]
|
|
259
275
|
},
|
|
276
|
+
"audience": {
|
|
277
|
+
"type": "string",
|
|
278
|
+
"enum": ["internal", "external", "shared"],
|
|
279
|
+
"description": "Target audience. Derived from coverage matrix."
|
|
280
|
+
},
|
|
260
281
|
"anticipatedSections": {
|
|
261
282
|
"type": "array",
|
|
262
283
|
"description": "Anticipated sections (Level 4) with their resources (Level 5), from cadrage coverage matrix",
|
|
@@ -266,6 +287,20 @@
|
|
|
266
287
|
"properties": {
|
|
267
288
|
"code": { "type": "string", "description": "Section code (e.g., list, detail, create, edit, dashboard)" },
|
|
268
289
|
"description": { "type": "string" },
|
|
290
|
+
"sectionType": {
|
|
291
|
+
"type": "string",
|
|
292
|
+
"enum": ["primary", "functional", "view", "embedded"],
|
|
293
|
+
"description": "Section classification: primary (menu entry), functional (independent), view (sub-page of parent), embedded (widget in parent)"
|
|
294
|
+
},
|
|
295
|
+
"permissionMode": {
|
|
296
|
+
"type": "string",
|
|
297
|
+
"enum": ["crud", "custom", "read-only", "inherit"],
|
|
298
|
+
"description": "Permission model: crud (standard CRUD), custom (section-specific), read-only, inherit (from parent)"
|
|
299
|
+
},
|
|
300
|
+
"parentSectionCode": {
|
|
301
|
+
"type": ["string", "null"],
|
|
302
|
+
"description": "Parent section code for view/embedded sections (e.g., 'list'). Null for primary/functional sections."
|
|
303
|
+
},
|
|
269
304
|
"resources": {
|
|
270
305
|
"type": "array",
|
|
271
306
|
"items": { "type": "string" },
|
|
@@ -516,6 +516,20 @@
|
|
|
516
516
|
"required": ["code", "labels", "route", "permission", "wireframe", "useCases", "resources"],
|
|
517
517
|
"properties": {
|
|
518
518
|
"code": { "type": "string", "description": "Section code (kebab-case: list, detail, dashboard, approve, import, etc.)" },
|
|
519
|
+
"sectionType": {
|
|
520
|
+
"type": "string",
|
|
521
|
+
"enum": ["primary", "functional", "view", "embedded"],
|
|
522
|
+
"description": "Section classification: primary (menu entry), functional (independent), view (sub-page of parent), embedded (widget in parent)"
|
|
523
|
+
},
|
|
524
|
+
"permissionMode": {
|
|
525
|
+
"type": "string",
|
|
526
|
+
"enum": ["crud", "custom", "read-only", "inherit"],
|
|
527
|
+
"description": "Permission model: crud (standard CRUD), custom (section-specific), read-only, inherit (from parent)"
|
|
528
|
+
},
|
|
529
|
+
"parentSectionCode": {
|
|
530
|
+
"type": ["string", "null"],
|
|
531
|
+
"description": "Parent section code for view/embedded sections (e.g., 'list'). Null for primary/functional sections."
|
|
532
|
+
},
|
|
519
533
|
"labels": {
|
|
520
534
|
"type": "object",
|
|
521
535
|
"properties": {
|
|
@@ -531,6 +545,11 @@
|
|
|
531
545
|
"wireframe": { "type": "string", "description": "Reference to uiWireframes[].screen" },
|
|
532
546
|
"useCases": { "type": "array", "items": { "type": "string" } },
|
|
533
547
|
"businessRules": { "type": "array", "items": { "type": "string" } },
|
|
548
|
+
"audience": {
|
|
549
|
+
"type": "string",
|
|
550
|
+
"enum": ["internal", "external", "shared"],
|
|
551
|
+
"description": "Target audience. Inherited from module unless overridden."
|
|
552
|
+
},
|
|
534
553
|
"resources": {
|
|
535
554
|
"type": "array",
|
|
536
555
|
"description": "Level 5 (Resource) components within this section",
|
|
@@ -122,10 +122,10 @@ existing_projects: array of { projectName, projectId, applications[], version }
|
|
|
122
122
|
## Step 3b: Early Multi-Application Detection from Prompt (NEW)
|
|
123
123
|
|
|
124
124
|
> **Detect multi-app structure BEFORE asking for a single application name.**
|
|
125
|
-
> When the user's prompt
|
|
126
|
-
> and set `workflow.mode = "project"` to avoid doing cadrage for a single app.
|
|
125
|
+
> When the user's prompt describes multiple applications or spans multiple business domains,
|
|
126
|
+
> we must recognize this immediately and set `workflow.mode = "project"` to avoid doing cadrage for a single app.
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
### Tier 1 — Explicit patterns (ANY match = multi-app detected)
|
|
129
129
|
|
|
130
130
|
French patterns:
|
|
131
131
|
- "une application X ... une application Y" (two occurrences of "une application")
|
|
@@ -138,30 +138,65 @@ English patterns:
|
|
|
138
138
|
- "application #1: ... application #2: ..." (numbered)
|
|
139
139
|
- "first app ... second app"
|
|
140
140
|
|
|
141
|
-
If ANY of these patterns is found in `{feature_description}
|
|
141
|
+
If ANY of these patterns is found in `{feature_description}`:
|
|
142
|
+
→ `isMultiApp = true`, `detectionTier = "explicit"`
|
|
142
143
|
|
|
143
|
-
|
|
144
|
+
### Tier 2 — Domain diversity analysis (when Tier 1 does not match)
|
|
144
145
|
|
|
145
|
-
|
|
146
|
+
ULTRATHINK: Analyze `{feature_description}` to extract distinct business domains.
|
|
146
147
|
|
|
147
|
-
**
|
|
148
|
+
**Definition:** A "domain" is an autonomous business perimeter with its own entities and processes (e.g., HR, CRM, Finance, Projects, Sales, Inventory).
|
|
149
|
+
|
|
150
|
+
**Algorithm:**
|
|
151
|
+
1. List all business domains mentioned or implied in the description
|
|
152
|
+
2. Classify each domain:
|
|
153
|
+
- **DISTINCT** — has its own entities, processes, and lifecycle (e.g., HR vs CRM)
|
|
154
|
+
- **RELATED** — is a sub-domain of another (e.g., Payroll is a sub-domain of HR)
|
|
155
|
+
3. Count DISTINCT domains only
|
|
156
|
+
|
|
157
|
+
**Threshold:** 2+ DISTINCT domains → `isMultiApp = true`, `detectionTier = "domain-diversity"`
|
|
158
|
+
|
|
159
|
+
**False positive protection:**
|
|
160
|
+
- "RH complet avec employés, congés, paie, pointage" = 1 domain (HR) with 4 modules, NOT 4 domains
|
|
161
|
+
- "HR and Payroll management" = 1 domain (HR) with 2 modules — Payroll is RELATED to HR
|
|
162
|
+
- "gestion commerciale avec devis, commandes et facturation" = 1 domain (Sales) with 3 modules
|
|
163
|
+
- Only count as DISTINCT when domains have genuinely independent entity models and processes
|
|
164
|
+
|
|
165
|
+
### Extraction algorithm (depends on detection tier)
|
|
166
|
+
|
|
167
|
+
**IF Tier 1 (explicit):**
|
|
148
168
|
|
|
149
169
|
1. **Identify boundaries:** Split the prompt at each "une application" / "an application" occurrence. Each block = one candidate.
|
|
150
170
|
2. **Extract per candidate:** For each block, derive `name` (application name), `description` (summary of purpose), and `modules[]` (listed modules/features).
|
|
151
|
-
- Example
|
|
171
|
+
- Example: `[{ name: "RH", description: "gestion des employés, congés, temps", modules: ["Employés", "Congés", "Temps"] }, ...]`
|
|
152
172
|
3. **Detect shared modules:** Collect all module names across all candidates. Any module appearing in more than one candidate is a shared module.
|
|
153
173
|
- Example: `sharedModules = ["Temps"]` (appears in both RH and Projet)
|
|
154
174
|
|
|
155
|
-
|
|
175
|
+
**IF Tier 2 (domain-diversity):**
|
|
176
|
+
|
|
177
|
+
1. Each DISTINCT domain = 1 candidate application:
|
|
178
|
+
- `name` = short domain label (e.g., "RH", "CRM", "Finance")
|
|
179
|
+
- `description` = user's expressed need for that domain
|
|
180
|
+
- `modules[]` = sub-functionalities mentioned (can be empty → "(à définir au cadrage)")
|
|
181
|
+
2. Group RELATED sub-domains under their parent DISTINCT domain as modules
|
|
182
|
+
3. **Detect shared modules:** Same logic as Tier 1 — modules appearing in multiple candidates
|
|
183
|
+
|
|
184
|
+
### Confirmation dialogue
|
|
185
|
+
|
|
186
|
+
Display detection result:
|
|
156
187
|
|
|
157
188
|
```
|
|
158
|
-
{
|
|
159
|
-
?
|
|
160
|
-
|
|
189
|
+
{detectionTier == "explicit"
|
|
190
|
+
? (language == "fr"
|
|
191
|
+
? "### Détection multi-application\n\nJ'ai détecté **{candidates.length} applications** dans votre description :"
|
|
192
|
+
: "### Multi-application detection\n\nI detected **{candidates.length} applications** in your description:")
|
|
193
|
+
: (language == "fr"
|
|
194
|
+
? "### Détection multi-application\n\nVotre description couvre **{candidates.length} domaines métier distincts**. Chaque domaine pourrait constituer une application séparée :"
|
|
195
|
+
: "### Multi-application detection\n\nYour description covers **{candidates.length} distinct business domains**. Each domain could be a separate application:")}
|
|
161
196
|
|
|
162
197
|
| # | Application | Modules identifiés |
|
|
163
198
|
|---|-------------|-------------------|
|
|
164
|
-
{for each candidate: index | name | modules.join(", ")}
|
|
199
|
+
{for each candidate: index | name | modules.join(", ") || "(à définir au cadrage)"}
|
|
165
200
|
|
|
166
201
|
{sharedModules.length > 0
|
|
167
202
|
? "⚠️ **Modules partagés détectés :** {sharedModules.join(', ')} — ces modules apparaissent dans plusieurs applications. Ils pourraient constituer une application transversale dédiée."
|
|
@@ -177,6 +212,8 @@ options:
|
|
|
177
212
|
description: "{language == 'fr' ? 'Créer un projet avec les applications identifiées' : 'Create a project with the identified applications'}"
|
|
178
213
|
- label: "{language == 'fr' ? 'Extraire les modules partagés' : 'Extract shared modules'}" (only if sharedModules.length > 0)
|
|
179
214
|
description: "{language == 'fr' ? 'Créer une application dédiée pour {sharedModules.join(', ')} ({candidates.length + 1} applications au total)' : 'Create a dedicated app for {sharedModules.join(', ')} ({candidates.length + 1} total)'}"
|
|
215
|
+
- label: "{language == 'fr' ? 'Regrouper certains domaines' : 'Regroup some domains'}" (only if detectionTier == "domain-diversity")
|
|
216
|
+
description: "{language == 'fr' ? 'Fusionner des domaines en moins d\\'applications' : 'Merge domains into fewer applications'}"
|
|
180
217
|
- label: "{language == 'fr' ? 'Application unique' : 'Single application'}"
|
|
181
218
|
description: "{language == 'fr' ? 'Tout regrouper en une seule application avec plusieurs modules' : 'Group everything into one application with multiple modules'}"
|
|
182
219
|
```
|
|
@@ -193,6 +230,19 @@ shared_modules_extracted: boolean # true if user chose extraction
|
|
|
193
230
|
→ Skip step 4 (application name) — applications will be confirmed in step-01-cadrage
|
|
194
231
|
→ Continue to step 5 (language selection)
|
|
195
232
|
|
|
233
|
+
**IF "Regrouper certains domaines" (Tier 2 only):**
|
|
234
|
+
|
|
235
|
+
Ask via AskUserQuestion:
|
|
236
|
+
```
|
|
237
|
+
question: "{language == 'fr' ? 'Comment souhaitez-vous regrouper ces domaines ? (ex: \"RH + Paie ensemble, CRM seul\")' : 'How would you like to regroup these domains? (e.g., \"HR + Payroll together, CRM alone\")'}"
|
|
238
|
+
header: "Regroupement"
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Process user response:
|
|
242
|
+
1. Parse the grouping instructions (natural language)
|
|
243
|
+
2. Rebuild `candidate_applications` based on the specified groups
|
|
244
|
+
3. Re-display the confirmation dialogue with the updated candidates
|
|
245
|
+
|
|
196
246
|
**IF "Application unique":**
|
|
197
247
|
|
|
198
248
|
```yaml
|
|
@@ -201,7 +251,7 @@ workflow_mode: "application"
|
|
|
201
251
|
|
|
202
252
|
→ Continue to step 4 normally
|
|
203
253
|
|
|
204
|
-
**IF no multi-app
|
|
254
|
+
**IF no multi-app detected (neither Tier 1 nor Tier 2):**
|
|
205
255
|
→ Continue to step 4 normally
|
|
206
256
|
|
|
207
257
|
## Step 4: Determine Application Name
|
|
@@ -239,6 +239,44 @@ Ask in 1-2 batches. After each batch:
|
|
|
239
239
|
- If "no restrictions" → probe: "Are there sensitive data (salary, contracts, personal info) that should be restricted to specific roles?"
|
|
240
240
|
- If tasks are generic → ask for a concrete scenario: "Walk me through a typical day"
|
|
241
241
|
|
|
242
|
+
#### 4b-bis. Détection Portail Client (ULTRATHINK — après batch stakeholders)
|
|
243
|
+
|
|
244
|
+
Analyser les réponses stakeholders pour signaux d'utilisateurs externes :
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
EXTERNAL_SIGNALS = ["client", "customer", "fournisseur", "supplier", "partenaire",
|
|
248
|
+
"partner", "portail", "portal", "externe", "external", "tiers", "third-party",
|
|
249
|
+
"organisation cliente"]
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
SI un profil stakeholder match EXTERNAL_SIGNALS :
|
|
253
|
+
→ Stocker dans `{pre_analysis}`: `_portalDetected: true`
|
|
254
|
+
→ Poser la question via AskUserQuestion :
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
question: "{language == 'fr'
|
|
258
|
+
? 'J\'ai détecté des utilisateurs externes ({profiles}). Votre application comportera-t-elle un portail client en plus de la partie interne ?'
|
|
259
|
+
: 'I detected external users ({profiles}). Will your application include a client portal in addition to the internal part?'}"
|
|
260
|
+
header: "Portail client"
|
|
261
|
+
options:
|
|
262
|
+
- label: "{language == 'fr' ? 'Oui, portail + interne' : 'Yes, portal + internal'}"
|
|
263
|
+
description: "{language == 'fr' ? 'L\'application servira des utilisateurs internes ET externes via un portail dédié' : 'The app will serve internal AND external users via a dedicated portal'}"
|
|
264
|
+
- label: "{language == 'fr' ? 'Non, interne uniquement' : 'No, internal only'}"
|
|
265
|
+
description: "{language == 'fr' ? 'Seuls les employés internes utiliseront l\'application' : 'Only internal employees will use the application'}"
|
|
266
|
+
- label: "{language == 'fr' ? 'Non, portail uniquement' : 'No, portal only'}"
|
|
267
|
+
description: "{language == 'fr' ? 'L\'application est exclusivement destinée aux utilisateurs externes' : 'The application is exclusively for external users'}"
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
| Réponse | Action |
|
|
271
|
+
|---------|--------|
|
|
272
|
+
| **Oui, portail + interne** | `_portalMode = "dual"` → Follow-up : classifier chaque stakeholder comme `audience: "internal" \| "external" \| "shared"` |
|
|
273
|
+
| **Portail uniquement** | `_portalMode = "portal-only"` |
|
|
274
|
+
| **Interne uniquement** | `_portalMode = "internal-only"` (défaut, pas d'action supplémentaire) |
|
|
275
|
+
|
|
276
|
+
> **Note SmartStack :** Le déploiement multi-tenant est géré automatiquement par SmartStack. La partie interne et la partie portail seront déployées sur des tenants séparés.
|
|
277
|
+
|
|
278
|
+
SI aucun profil ne match EXTERNAL_SIGNALS → `_portalMode = "internal-only"` (défaut silencieux, rien à demander).
|
|
279
|
+
|
|
242
280
|
#### 4c. Functional Scope (ALWAYS — from `questionnaire/02-stakeholders-scope.md`)
|
|
243
281
|
|
|
244
282
|
**Mandatory minimum:** Q2.13 (in-scope), Q2.15 (exclusions), Q2.16 (main journey).
|
|
@@ -596,6 +634,14 @@ BEFORE transitioning to step-02:
|
|
|
596
634
|
- List anticipated resources (Level 5) for each section
|
|
597
635
|
- List detail page tabs — for entities accessible via click from `list`
|
|
598
636
|
|
|
637
|
+
**SI `_portalMode === "dual"` :**
|
|
638
|
+
- Chaque entrée `coverageMatrix` reçoit `audience: "internal" | "external" | "shared"`
|
|
639
|
+
- Règles de dérivation :
|
|
640
|
+
- Items mentionnés uniquement par stakeholders internes → `"internal"`
|
|
641
|
+
- Items mentionnés uniquement par stakeholders externes → `"external"`
|
|
642
|
+
- Items mentionnés par les deux ou cross-cutting → `"shared"`
|
|
643
|
+
- Afficher colonne "Audience" dans le tableau de la matrice
|
|
644
|
+
|
|
599
645
|
4. **RECONCILIATION CHECK (MANDATORY — BLOCKING):**
|
|
600
646
|
|
|
601
647
|
> **Every explicitly requested item MUST appear in the coverage matrix.**
|
|
@@ -641,12 +687,13 @@ ba-writer.enrichSection({
|
|
|
641
687
|
subsection: "cadrage.json",
|
|
642
688
|
data: {
|
|
643
689
|
metadata: {
|
|
644
|
-
tablePrefix: "{from Phase 5, section 6b — validated prefix, e.g., rh_}"
|
|
690
|
+
tablePrefix: "{from Phase 5, section 6b — validated prefix, e.g., rh_}",
|
|
691
|
+
portalMode: "{_portalMode || 'internal-only'}"
|
|
645
692
|
},
|
|
646
693
|
problem: {from Phase 3, section 4a — Q1.1 answer or refined problem},
|
|
647
694
|
asIs: {from Phase 3, section 4a — Q1.4 answer},
|
|
648
695
|
toBe: {from Phase 3, section 4a — Q1.8 answer},
|
|
649
|
-
stakeholders: [{from Phase 3, section 4b}],
|
|
696
|
+
stakeholders: [{from Phase 3, section 4b — each with audience: "internal"|"external"|"shared" if portalMode is "dual"}],
|
|
650
697
|
globalScope: {
|
|
651
698
|
inScope: [{from Phase 3, section 4c + Phase 4 accepted suggestions + coverage matrix}],
|
|
652
699
|
outOfScope: [{from Phase 3, section 4c — Q2.15 exclusions}]
|
|
@@ -70,6 +70,9 @@ For each module:
|
|
|
70
70
|
- Description
|
|
71
71
|
- FeatureType (data-centric | workflow | reporting | integration | full-module)
|
|
72
72
|
- Entities (preliminary list)
|
|
73
|
+
- Audience ("internal" | "external" | "shared") — if portalMode = "dual"
|
|
74
|
+
→ Derived from coverageMatrix: if ALL items of the module are internal → "internal",
|
|
75
|
+
if ALL external → "external", else → "shared"
|
|
73
76
|
```
|
|
74
77
|
|
|
75
78
|
### 3. Section & Resource Anticipation
|
|
@@ -89,18 +92,20 @@ For each section:
|
|
|
89
92
|
|
|
90
93
|
**Section classification rules:**
|
|
91
94
|
|
|
92
|
-
| sectionType | permissionMode | When to use | Examples |
|
|
93
|
-
|
|
94
|
-
| `primary` | `crud` | Main entry point of the module, visible in menu | list |
|
|
95
|
-
| `functional` | `crud` or `custom` | Independent functional section with own access control | approve, import, planning |
|
|
96
|
-
| `view` | `inherit` |
|
|
97
|
-
| `embedded` | `read-only` | Widget or tab embedded in another section | dashboard (when embedded in module) |
|
|
95
|
+
| sectionType | permissionMode | When to use | Parent | Examples |
|
|
96
|
+
|---|---|---|---|---|
|
|
97
|
+
| `primary` | `crud` | Main entry point of the module, visible in menu | none | list |
|
|
98
|
+
| `functional` | `crud` or `custom` | Independent functional section with own access control | none | approve, import, planning |
|
|
99
|
+
| `view` | `inherit` | Sub-page reached from a primary/functional section (e.g., click a row) | `parentSectionCode` | detail, edit |
|
|
100
|
+
| `embedded` | `read-only` | Widget or tab embedded in another section | `parentSectionCode` | dashboard (when embedded in module) |
|
|
101
|
+
|
|
102
|
+
**Parent-child rule:** `view` and `embedded` sections MUST specify `parentSectionCode` — the code of the section they are reached from. A detail page is NOT a sibling of list; it is a **child** of list (user clicks a row in the list to reach the detail).
|
|
98
103
|
|
|
99
104
|
Common patterns:
|
|
100
|
-
- **Data-centric
|
|
101
|
-
- **Workflow
|
|
102
|
-
- **Reporting
|
|
103
|
-
- **Full module**: list (`primary`/`crud`)
|
|
105
|
+
- **Data-centric**: list (`primary`/`crud`) → detail (`view`/`inherit`, parent: list)
|
|
106
|
+
- **Workflow**: list (`primary`/`crud`) → detail (`view`/`inherit`, parent: list) + approve (`functional`/`custom`)
|
|
107
|
+
- **Reporting**: dashboard (`primary`/`read-only`) → detail (`view`/`inherit`, parent: dashboard)
|
|
108
|
+
- **Full module**: list (`primary`/`crud`) → detail (`view`/`inherit`, parent: list) + dashboard (`embedded`/`read-only`, parent: list)
|
|
104
109
|
|
|
105
110
|
### 4. Dependency Graph
|
|
106
111
|
|
|
@@ -139,21 +144,40 @@ For EACH identified element, ask yourself:
|
|
|
139
144
|
- Does the form need tabs?
|
|
140
145
|
- Are there missing filter components?
|
|
141
146
|
|
|
147
|
+
**Split audience (if portalMode = "dual"):**
|
|
148
|
+
- Pour chaque module "shared" : le portail voit-il les MÊMES données ou un sous-ensemble filtré ?
|
|
149
|
+
- Y a-t-il des sections qui ne doivent apparaître QUE dans le portail ? (ex: "Mes demandes")
|
|
150
|
+
- Y a-t-il des sections qui ne doivent apparaître QUE en interne ? (ex: reporting admin)
|
|
151
|
+
|
|
142
152
|
### 6. Present to User
|
|
143
153
|
|
|
144
154
|
Display the complete hierarchy for validation:
|
|
145
155
|
|
|
156
|
+
**Tree nesting rules:**
|
|
157
|
+
- `view` sections are **indented under their parent** (the section they are reached from)
|
|
158
|
+
- `functional` and `primary` sections stay at module level
|
|
159
|
+
- `embedded` sections are indented under their parent section
|
|
160
|
+
- Tabs are indented under detail
|
|
161
|
+
|
|
146
162
|
```
|
|
147
163
|
[App: HumanResources]
|
|
148
164
|
├── [Module: Employees]
|
|
149
|
-
│ ├── list →
|
|
150
|
-
│ └── detail →
|
|
165
|
+
│ ├── list (primary/crud) → employees-grid, employees-filters
|
|
166
|
+
│ │ └── detail (view/inherit) → employee-form
|
|
167
|
+
│ │ └── Tabs: Infos, Contrats
|
|
151
168
|
├── [Module: Absences]
|
|
152
|
-
│ ├── list →
|
|
153
|
-
│
|
|
154
|
-
│ └── calendar →
|
|
169
|
+
│ ├── list (primary/crud) → absences-grid, absences-filters
|
|
170
|
+
│ │ └── detail (view/inherit) → absence-form
|
|
171
|
+
│ └── calendar (functional) → absences-calendar
|
|
155
172
|
└── [Module: Reports]
|
|
156
|
-
└── dashboard →
|
|
173
|
+
└── dashboard (primary/read-only) → hr-dashboard
|
|
174
|
+
|
|
175
|
+
IF portalMode = "dual", annotate each module with its audience:
|
|
176
|
+
|
|
177
|
+
[App: ServiceManagement]
|
|
178
|
+
├── [Module: Projects] [partagé]
|
|
179
|
+
├── [Module: TimeTracking] [interne]
|
|
180
|
+
└── [Module: ClientDashboard] [portail]
|
|
157
181
|
```
|
|
158
182
|
|
|
159
183
|
Ask: "Does this structure match your vision? Any missing modules, sections, or resources?"
|
|
@@ -181,7 +205,7 @@ Write via ba-writer:
|
|
|
181
205
|
"entities": ["Employee", "Contract"],
|
|
182
206
|
"anticipatedSections": [
|
|
183
207
|
{ "code": "list", "label": "Liste", "sectionType": "primary", "permissionMode": "crud", "resources": [{ "code": "employees-grid", "type": "SmartTable" }] },
|
|
184
|
-
{ "code": "detail", "label": "Fiche", "sectionType": "view", "permissionMode": "inherit", "resources": [{ "code": "employee-form", "type": "SmartForm" }] }
|
|
208
|
+
{ "code": "detail", "label": "Fiche", "sectionType": "view", "permissionMode": "inherit", "parentSectionCode": "list", "resources": [{ "code": "employee-form", "type": "SmartForm" }] }
|
|
185
209
|
]
|
|
186
210
|
}
|
|
187
211
|
],
|