@atlashub/smartstack-cli 4.74.0 → 4.76.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 (121) hide show
  1. package/dist/index.js +152 -31
  2. package/dist/index.js.map +1 -1
  3. package/dist/mcp-entry.mjs +14 -3
  4. package/dist/mcp-entry.mjs.map +1 -1
  5. package/package.json +1 -1
  6. package/templates/agents/ba-reader.md +17 -15
  7. package/templates/agents/ba-writer.md +49 -51
  8. package/templates/skills/apex/SKILL.md +2 -2
  9. package/templates/skills/apex/_shared.md +1 -1
  10. package/templates/skills/apex/references/checks/backend-checks.sh +21 -7
  11. package/templates/skills/apex/references/checks/frontend-checks.sh +26 -0
  12. package/templates/skills/apex/references/checks/infrastructure-checks.sh +47 -10
  13. package/templates/skills/apex/references/checks/seed-checks.sh +47 -7
  14. package/templates/skills/apex/references/core-seed-data.md +20 -18
  15. package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +3 -0
  16. package/templates/skills/apex/references/post-checks.md +23 -3
  17. package/templates/skills/apex/references/smartstack-api.md +4 -4
  18. package/templates/skills/apex/references/smartstack-frontend.md +54 -8
  19. package/templates/skills/apex/references/smartstack-layers.md +6 -6
  20. package/templates/skills/apex/steps/step-00-init.md +75 -1
  21. package/templates/skills/apex/steps/step-03-execute.md +16 -4
  22. package/templates/skills/apex/steps/step-03b-layer1-seed.md +65 -6
  23. package/templates/skills/apex/steps/step-03c-layer2-backend.md +50 -5
  24. package/templates/skills/apex/steps/step-03d-layer3-frontend.md +226 -4
  25. package/templates/skills/apex/steps/step-04-examine.md +163 -0
  26. package/templates/skills/apex-verify/SKILL.md +110 -0
  27. package/templates/skills/apex-verify/references/audit-rules.md +50 -0
  28. package/templates/skills/apex-verify/steps/step-00-init.md +119 -0
  29. package/templates/skills/apex-verify/steps/step-01-nav-audit.md +92 -0
  30. package/templates/skills/apex-verify/steps/step-02-crud-audit.md +127 -0
  31. package/templates/skills/apex-verify/steps/step-03-perm-audit.md +119 -0
  32. package/templates/skills/apex-verify/steps/step-04-route-audit.md +98 -0
  33. package/templates/skills/apex-verify/steps/step-05-report.md +110 -0
  34. package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +3 -0
  35. package/templates/skills/application/templates-frontend.md +2 -2
  36. package/templates/skills/business-analyse/SKILL.md +17 -3
  37. package/templates/skills/business-analyse/_shared.md +64 -0
  38. package/templates/skills/business-analyse/patterns/suggestion-catalog.md +34 -26
  39. package/templates/skills/business-analyse/questionnaire/01-context.md +13 -9
  40. package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +20 -27
  41. package/templates/skills/business-analyse/questionnaire.md +86 -9
  42. package/templates/skills/business-analyse/references/03-json-schemas.md +221 -0
  43. package/templates/skills/business-analyse/references/03-post-check-validation.md +208 -0
  44. package/templates/skills/business-analyse/references/03-smartstack-entity-guards.md +32 -0
  45. package/templates/skills/business-analyse/references/04-cross-module-validation.md +95 -0
  46. package/templates/skills/business-analyse/references/04-file-allocation.md +162 -0
  47. package/templates/skills/business-analyse/references/04-naming-audit-checks.md +174 -0
  48. package/templates/skills/business-analyse/references/04-semantic-validation-matrix.md +118 -0
  49. package/templates/skills/business-analyse/references/canonical-json-formats.md +7 -3
  50. package/templates/skills/business-analyse/references/domain-research-playbook.md +234 -0
  51. package/templates/skills/business-analyse/references/entity-sourcing-presentation.md +166 -0
  52. package/templates/skills/business-analyse/references/init-resume-logic.md +70 -0
  53. package/templates/skills/business-analyse/references/module-completeness-challenge.md +174 -0
  54. package/templates/skills/business-analyse/references/multi-app-detection.md +149 -0
  55. package/templates/skills/business-analyse/references/portal-classification.md +52 -0
  56. package/templates/skills/business-analyse/references/robustness-checks.md +1 -1
  57. package/templates/skills/business-analyse/references/validation-checklist.md +35 -6
  58. package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +50 -6
  59. package/templates/skills/business-analyse/steps/step-00-init.md +22 -190
  60. package/templates/skills/business-analyse/steps/step-01-cadrage.md +365 -269
  61. package/templates/skills/business-analyse/steps/step-02-structure.md +98 -20
  62. package/templates/skills/business-analyse/steps/step-03-specify.md +810 -229
  63. package/templates/skills/business-analyse/steps/step-04-consolidate.md +509 -278
  64. package/templates/skills/business-analyse-design/SKILL.md +10 -0
  65. package/templates/skills/business-analyse-design/references/screens-post-check.md +221 -0
  66. package/templates/skills/business-analyse-design/references/screens-type-mapping.md +138 -0
  67. package/templates/skills/business-analyse-design/references/smartcomponents-templates.md +225 -0
  68. package/templates/skills/{business-analyse → business-analyse-design}/references/spec-auto-inference.md +117 -117
  69. package/templates/skills/business-analyse-design/steps/step-01-screens.md +36 -162
  70. package/templates/skills/business-analyse-design/steps/step-02-wireframes.md +8 -7
  71. package/templates/skills/business-analyse-design/steps/step-03-navigation.md +89 -42
  72. package/templates/skills/business-analyse-develop/references/compact-loop.md +9 -0
  73. package/templates/skills/business-analyse-develop/references/handoff-quality-gate.md +132 -0
  74. package/templates/skills/business-analyse-develop/references/prd-v3-transformation.md +326 -0
  75. package/templates/skills/business-analyse-develop/references/report-reconciliation.md +140 -0
  76. package/templates/skills/business-analyse-develop/references/report-template.md +142 -0
  77. package/templates/skills/business-analyse-develop/steps/step-01-task.md +5 -177
  78. package/templates/skills/business-analyse-develop/steps/step-02-execute.md +17 -4
  79. package/templates/skills/business-analyse-develop/steps/step-03-commit.md +6 -2
  80. package/templates/skills/business-analyse-develop/steps/step-04-check.md +6 -0
  81. package/templates/skills/business-analyse-develop/steps/step-05-report.md +3 -269
  82. package/templates/skills/business-analyse-handoff/SKILL.md +10 -0
  83. package/templates/skills/business-analyse-handoff/references/agent-handoff-transform-prompt.md +211 -0
  84. package/templates/skills/business-analyse-handoff/references/context-isolation-pattern.md +47 -0
  85. package/templates/skills/business-analyse-handoff/references/handoff-file-inventory.md +49 -0
  86. package/templates/skills/business-analyse-handoff/references/handoff-global-validation.md +142 -0
  87. package/templates/skills/business-analyse-handoff/references/prd-validation-checks.md +125 -0
  88. package/templates/skills/business-analyse-handoff/references/project-index-update.md +98 -0
  89. package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +9 -160
  90. package/templates/skills/business-analyse-handoff/steps/step-02-export.md +10 -99
  91. package/templates/skills/business-analyse-html/SKILL.md +10 -0
  92. package/templates/skills/business-analyse-html/html/ba-interactive.html +504 -97
  93. package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +79 -2
  94. package/templates/skills/business-analyse-html/html/src/scripts/02-navigation.js +6 -46
  95. package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +80 -11
  96. package/templates/skills/business-analyse-html/html/src/scripts/06-render-consolidation.js +2 -2
  97. package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +94 -36
  98. package/templates/skills/business-analyse-html/html/src/scripts/12-render-diagrams.js +162 -0
  99. package/templates/skills/business-analyse-html/html/src/styles/10-diagrams.css +73 -0
  100. package/templates/skills/business-analyse-html/html/src/template.html +2 -0
  101. package/templates/skills/business-analyse-html/references/02-embedded-artifacts-building.md +144 -0
  102. package/templates/skills/business-analyse-html/references/02-feature-data-building.md +143 -0
  103. package/templates/skills/business-analyse-html/references/02-mapping-tables.md +442 -0
  104. package/templates/skills/business-analyse-html/references/02-normalization-helpers.md +139 -0
  105. package/templates/skills/business-analyse-html/references/02-screen-format-detection.md +283 -0
  106. package/templates/skills/business-analyse-html/references/02-self-check-validation.md +199 -0
  107. package/templates/skills/business-analyse-html/references/data-build.md +24 -1
  108. package/templates/skills/business-analyse-html/references/data-mapping.md +119 -17
  109. package/templates/skills/business-analyse-html/steps/step-02-build-data.md +18 -555
  110. package/templates/skills/business-analyse-html/steps/step-04-verify.md +92 -3
  111. package/templates/skills/business-analyse-quick/SKILL.md +807 -0
  112. package/templates/skills/{sketch → business-analyse-quick}/references/domain-heuristics.md +59 -3
  113. package/templates/skills/business-analyse-quick/references/prd-schema.md +268 -0
  114. package/templates/skills/business-analyse-review/SKILL.md +10 -0
  115. package/templates/skills/business-analyse-review/references/review-data-mapping.md +6 -0
  116. package/templates/skills/business-analyse-status/SKILL.md +8 -0
  117. package/templates/skills/dev-start/SKILL.md +143 -307
  118. package/templates/skills/efcore/SKILL.md +13 -0
  119. package/templates/skills/sketch/SKILL.md +15 -153
  120. package/templates/skills/ui-components/SKILL.md +1 -1
  121. package/templates/skills/ui-components/patterns/data-table.md +1 -1
@@ -0,0 +1,149 @@
1
+ # Multi-App Detection Algorithm
2
+
3
+ > **Purpose:** Detect and extract multiple applications from user prompts using a two-tier approach.
4
+ > Executed early in initialization to determine `workflow_mode` ("application" vs "project").
5
+
6
+ ## Overview
7
+
8
+ When the user's prompt describes multiple applications or spans multiple business domains, we must recognize this immediately and set `workflow.mode = "project"` to avoid doing cadrage for a single app.
9
+
10
+ ## Tier 1 — Explicit Patterns (ANY match = multi-app detected)
11
+
12
+ ### French patterns:
13
+ - "une application X ... une application Y" (two occurrences of "une application")
14
+ - "application 1: X ... application 2: Y" (numbered applications)
15
+ - "première application ... deuxième application"
16
+ - "app 1: ... app 2: ..."
17
+
18
+ ### English patterns:
19
+ - "an application (for) X ... an application (for) Y" (two occurrences)
20
+ - "application #1: ... application #2: ..." (numbered)
21
+ - "first app ... second app"
22
+
23
+ ### Decision:
24
+
25
+ If ANY of these patterns is found in `{feature_description}`:
26
+ → `isMultiApp = true`, `detectionTier = "explicit"`
27
+
28
+ ## Tier 2 — Domain Diversity Analysis (when Tier 1 does not match)
29
+
30
+ ### Definition
31
+
32
+ A "domain" is an autonomous business perimeter with its own entities and processes (e.g., HR, CRM, Finance, Projects, Sales, Inventory).
33
+
34
+ ### Algorithm
35
+
36
+ ULTRATHINK: Analyze `{feature_description}` to extract distinct business domains.
37
+
38
+ 1. List all business domains mentioned or implied in the description
39
+ 2. Classify each domain:
40
+ - **DISTINCT** — has its own entities, processes, and lifecycle (e.g., HR vs CRM)
41
+ - **RELATED** — is a sub-domain of another (e.g., Payroll is a sub-domain of HR)
42
+ 3. Count DISTINCT domains only
43
+
44
+ ### Threshold
45
+
46
+ 2+ DISTINCT domains → `isMultiApp = true`, `detectionTier = "domain-diversity"`
47
+
48
+ ### False Positive Protection
49
+
50
+ - "RH complet avec employés, congés, paie, pointage" = 1 domain (HR) with 4 modules, NOT 4 domains
51
+ - "HR and Payroll management" = 1 domain (HR) with 2 modules — Payroll is RELATED to HR
52
+ - "gestion commerciale avec devis, commandes et facturation" = 1 domain (Sales) with 3 modules
53
+ - Only count as DISTINCT when domains have genuinely independent entity models and processes
54
+
55
+ ## Extraction Algorithm (depends on detection tier)
56
+
57
+ ### IF Tier 1 (explicit):
58
+
59
+ 1. **Identify boundaries:** Split the prompt at each "une application" / "an application" occurrence. Each block = one candidate.
60
+ 2. **Extract per candidate:** For each block, derive `name` (application name), `description` (summary of purpose), and `modules[]` (listed modules/features).
61
+ - Example: `[{ name: "RH", description: "gestion des employés, congés, temps", modules: ["Employés", "Congés", "Temps"] }, ...]`
62
+ 3. **Detect shared modules:** Collect all module names across all candidates. Any module appearing in more than one candidate is a shared module.
63
+ - Example: `sharedModules = ["Temps"]` (appears in both RH and Projet)
64
+
65
+ ### IF Tier 2 (domain-diversity):
66
+
67
+ 1. Each DISTINCT domain = 1 candidate application:
68
+ - `name` = short domain label (e.g., "RH", "CRM", "Finance")
69
+ - `description` = user's expressed need for that domain
70
+ - `modules[]` = sub-functionalities mentioned (can be empty → "(à définir au cadrage)")
71
+ 2. Group RELATED sub-domains under their parent DISTINCT domain as modules
72
+ 3. **Detect shared modules:** Same logic as Tier 1 — modules appearing in multiple candidates
73
+
74
+ ## Confirmation Dialogue
75
+
76
+ Display detection result:
77
+
78
+ ```
79
+ {detectionTier == "explicit"
80
+ ? (language == "fr"
81
+ ? "### Détection multi-application\n\nJ'ai détecté **{candidates.length} applications** dans votre description :"
82
+ : "### Multi-application detection\n\nI detected **{candidates.length} applications** in your description:")
83
+ : (language == "fr"
84
+ ? "### Détection multi-application\n\nVotre description couvre **{candidates.length} domaines métier distincts**. Chaque domaine pourrait constituer une application séparée :"
85
+ : "### Multi-application detection\n\nYour description covers **{candidates.length} distinct business domains**. Each domain could be a separate application:")}
86
+
87
+ | # | Application | Modules identifiés |
88
+ |---|-------------|-------------------|
89
+ {for each candidate: index | name | modules.join(", ") || "(à définir au cadrage)"}
90
+
91
+ {sharedModules.length > 0
92
+ ? "⚠️ **Modules partagés détectés :** {sharedModules.join(', ')} — ces modules apparaissent dans plusieurs applications. Ils pourraient constituer une application transversale dédiée."
93
+ : ""}
94
+ ```
95
+
96
+ ### AskUserQuestion Options
97
+
98
+ ```
99
+ question: "{language == 'fr' ? 'Confirmez-vous cette structure multi-application ?' : 'Do you confirm this multi-application structure?'}"
100
+ header: "Architecture"
101
+ options:
102
+ - label: "{language == 'fr' ? 'Oui, {candidates.length} applications' : 'Yes, {candidates.length} applications'}"
103
+ description: "{language == 'fr' ? 'Créer un projet avec les applications identifiées' : 'Create a project with the identified applications'}"
104
+ - label: "{language == 'fr' ? 'Extraire les modules partagés' : 'Extract shared modules'}" (only if sharedModules.length > 0)
105
+ 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)'}"
106
+ - label: "{language == 'fr' ? 'Regrouper certains domaines' : 'Regroup some domains'}" (only if detectionTier == "domain-diversity")
107
+ description: "{language == 'fr' ? 'Fusionner des domaines en moins d\\'applications' : 'Merge domains into fewer applications'}"
108
+ - label: "{language == 'fr' ? 'Application unique' : 'Single application'}"
109
+ description: "{language == 'fr' ? 'Tout regrouper en une seule application avec plusieurs modules' : 'Group everything into one application with multiple modules'}"
110
+ ```
111
+
112
+ ## Handling User Responses
113
+
114
+ ### IF "Oui, N applications" or "Extraire les modules partagés":
115
+
116
+ ```yaml
117
+ workflow_mode: "project"
118
+ project_name: derived from feature_description
119
+ candidate_applications: [{ name, description, modules, context }]
120
+ shared_modules_extracted: boolean # true if user chose extraction
121
+ ```
122
+
123
+ → Skip step 4 (application name) — applications will be confirmed in step-01-cadrage
124
+ → Continue to step 5 (language selection)
125
+
126
+ ### IF "Regrouper certains domaines" (Tier 2 only):
127
+
128
+ Ask via AskUserQuestion:
129
+ ```
130
+ 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\")'}"
131
+ header: "Regroupement"
132
+ ```
133
+
134
+ Process user response:
135
+ 1. Parse the grouping instructions (natural language)
136
+ 2. Rebuild `candidate_applications` based on the specified groups
137
+ 3. Re-display the confirmation dialogue with the updated candidates
138
+
139
+ ### IF "Application unique":
140
+
141
+ ```yaml
142
+ workflow_mode: "application"
143
+ ```
144
+
145
+ → Continue to step 4 normally
146
+
147
+ ### IF no multi-app detected (neither Tier 1 nor Tier 2):
148
+
149
+ → Continue to step 4 normally
@@ -0,0 +1,52 @@
1
+ # Portal Classification
2
+
3
+ > **Note :** La detection initiale des utilisateurs externes a lieu dans le batch 1 (4a).
4
+ > Ce bloc RESOUT la detection en classifiant les stakeholders et configurant le portail.
5
+
6
+ ## External Signals Detection
7
+
8
+ ```
9
+ EXTERNAL_SIGNALS = ["client", "customer", "fournisseur", "supplier", "partenaire",
10
+ "partner", "portail", "portal", "externe", "external", "tiers", "third-party",
11
+ "organisation cliente"]
12
+ ```
13
+
14
+ ## SmartStack Native Support
15
+
16
+ > **SmartStack gère nativement les utilisateurs externes :**
17
+ > - **Person Extension Pattern** : User → Employee, Contact, Customer via `UserId` FK
18
+ > - **Organisation Extension** : Organisation → Client, Supplier via `OrganisationId` FK
19
+ > - **Multi-tenant** : portail et interne déployés sur des tenants séparés automatiquement
20
+
21
+ ## Classification and Portal Mode Resolution
22
+
23
+ SI `_portalDetected` (from batch 1) OU un profil stakeholder (batch 2) match EXTERNAL_SIGNALS :
24
+ → **Auto-classifier** chaque stakeholder : `audience: "internal" | "external" | "shared"`
25
+ → **Auto-déduire** `_portalMode` :
26
+
27
+ | Stakeholders détectés | `_portalMode` |
28
+ |----------------------|---------------|
29
+ | Internes + Externes | `"dual"` |
30
+ | Uniquement externes | `"portal-only"` |
31
+ | Uniquement internes | `"internal-only"` |
32
+
33
+ ## Portal Module Rule (SCOPE LOCK)
34
+
35
+ SI `_portalMode = "dual"` ou `"portal-only"`:
36
+ Un portail = UN module "Portal" avec des sections view par entite.
37
+ INTERDICTION de creer des modules separes MyAccount, MyProjects, MyInvoices.
38
+ Le module Portal aura des sections (view/inherit) pour chaque zone accessible.
39
+
40
+ ## Client Notification
41
+
42
+ → **Informer le client** (statement, PAS de question) :
43
+
44
+ ```
45
+ "{language == 'fr'
46
+ ? 'J\'ai détecté des utilisateurs externes ({profiles}). SmartStack déploiera automatiquement un portail dédié ({_portalMode}) avec isolation multi-tenant. Les extensions Person/Organisation gèrent nativement la séparation des profils internes et externes.'
47
+ : 'I detected external users ({profiles}). SmartStack will automatically deploy a dedicated portal ({_portalMode}) with multi-tenant isolation. Person/Organisation extensions natively handle the separation of internal and external profiles.'}"
48
+ ```
49
+
50
+ ## Default Case
51
+
52
+ SI aucun profil ne match EXTERNAL_SIGNALS → `_portalMode = "internal-only"` (défaut silencieux, rien à informer).
@@ -61,7 +61,7 @@ Ensures each module has ALL required components before being marked as "specifie
61
61
  | 5.1 | Sections count | ≥2 | YES | Modules need list + form minimum |
62
62
  | 5.2 | Wireframes count | 1 per section | YES | EVERY section MUST have wireframe |
63
63
  | 5.3 | Navigation entries | ≥1 | YES | Module must be accessible in menu |
64
- | 5.4 | Navigation route patterns | No `/list` or `/detail/:id` suffixes | YES | list route = module route (index), detail route = module + /:id. FORBIDDEN: `/module/list`, `/module/detail/:id` |
64
+ | 5.4 | Navigation route patterns | No `/detail/:id` suffix | YES | ALL sections use uniform route: module route + /{section-code}. list route MUST end with `/list`. FORBIDDEN: `/module/detail/:id` (detail is implicit) |
65
65
 
66
66
  #### SECTION 6: I18N & Messages (3 checks)
67
67
 
@@ -169,20 +169,20 @@ const checklist = {
169
169
  },
170
170
 
171
171
  navigationRoutePatterns: {
172
- check: "Navigation routes do NOT contain CRUD suffixes (/list, /detail/:id)",
172
+ check: "Navigation routes do NOT contain forbidden patterns (/detail/:id)",
173
173
  status: (() => {
174
174
  const allRoutes = [
175
175
  ...(specification.seedDataCore?.navigationSections || []).map(s => s.route),
176
176
  ...(specification.sections || []).map(s => s.route),
177
177
  ...(specification.navigation?.entries || []).map(e => e.route)
178
178
  ].filter(Boolean);
179
- const forbidden = allRoutes.filter(r => r.match(/\/list$/) || r.match(/\/detail\/:id$/));
179
+ const forbidden = allRoutes.filter(r => r.match(/\/detail\/:id$/));
180
180
  return forbidden.length === 0 ? "PASS" : "FAIL";
181
181
  })(),
182
182
  blocking: true,
183
- details: "FORBIDDEN: /module/list (use /module), /module/detail/:id (use /module/:id). " +
184
- "list route = module route (React Router index route). " +
185
- "detail route = module route + /:id (React Router :id child). " +
183
+ details: "FORBIDDEN: /module/detail/:id (detail is implicit, not a section). " +
184
+ "ALL sections use uniform route: module route + /{section-code}. " +
185
+ "list route = module route + /list. " +
186
186
  "Other sections (dashboard, approve) add /{section} normally."
187
187
  },
188
188
 
@@ -262,7 +262,36 @@ const checklist = {
262
262
  details: "Modules need field validation rules"
263
263
  },
264
264
 
265
- // SECTION 10: GHERKIN SCENARIOS (BLOCKING for format, WARNING for count)
265
+ // SECTION 10: ANALYSIS DEPTH (BLOCKING)
266
+ analysisDepthRules: {
267
+ check: "Business rules include domain-specific rules (not just generic CRUD)",
268
+ status: countDomainSpecificRules(analysis.businessRules) >= 2 ? "PASS" : "FAIL",
269
+ blocking: true,
270
+ details: "Module must have at least 2 domain-specific rules beyond basic validation. " +
271
+ "Generic rules: date coherence, required fields, unique constraints, basic workflow transitions. " +
272
+ "Domain-specific: half-day absences, team capacity limits, carry-over expiry, " +
273
+ "invoice sequential numbering, credit note linking, opportunity probability rules, etc. " +
274
+ "If C-pre (Business Rules Domain Research) was executed, these should come from web research."
275
+ },
276
+
277
+ sectionCompleteness: {
278
+ check: "Workflow modules have contextual filtered views",
279
+ status: (moduleFeatureType === "workflow" && hasContextualViews(analysis.anticipatedSections)) ? "PASS" : "FAIL",
280
+ blocking: true,
281
+ details: "Workflow modules must have at least 1 contextual filtered view " +
282
+ "(e.g., open-requests, rejected, my-X, history) beyond the base CRUD sections. " +
283
+ "A workflow module with only list/detail/approve is incomplete."
284
+ },
285
+
286
+ webResearchPerformed: {
287
+ check: "Web research was performed for this module",
288
+ status: module.domainResearchSource !== "built-in-only" ? "PASS" : "WARNING",
289
+ blocking: false,
290
+ details: "Modules without web research have lower completeness confidence. " +
291
+ "Domain-specific rules and sections may be missing."
292
+ },
293
+
294
+ // SECTION 11: GHERKIN SCENARIOS (BLOCKING for format, WARNING for count)
266
295
  gherkinFormat: {
267
296
  check: "gherkinScenarios is ARRAY (not single object)",
268
297
  status: Array.isArray(specification.gherkinScenarios) ? "PASS" : "FAIL",
@@ -24,23 +24,67 @@
24
24
  "type": "object",
25
25
  "required": ["id", "name", "category", "statement"],
26
26
  "properties": {
27
- "id": { "type": "string", "pattern": "^BR-(VAL|CALC|WF|SEC|DATA)-[A-Z]{2,4}-\\d{3}$", "description": "Module-prefixed BR ID (e.g., BR-VAL-RM-001)" },
27
+ "id": { "type": "string", "pattern": "^BR-(VAL|CALC|WF|SEC|DATA|NOTIF)-[A-Z]{2,4}-\\d{3}$", "description": "Module-prefixed BR ID (e.g., BR-VAL-RM-001)" },
28
28
  "name": { "type": "string" },
29
- "category": { "type": "string", "enum": ["validation", "calculation", "workflow", "security", "data"] },
29
+ "category": { "type": "string", "enum": ["validation", "calculation", "workflow", "security", "data", "notification"] },
30
30
  "statement": { "type": "string", "description": "IF ... THEN ... ELSE ..." },
31
31
  "priority": { "type": "string", "enum": ["must", "should", "could"] },
32
- "conditions": { "type": "array", "items": { "type": "string" } },
32
+ "conditions": {
33
+ "type": "array",
34
+ "items": {
35
+ "oneOf": [
36
+ { "type": "string" },
37
+ {
38
+ "type": "object",
39
+ "properties": {
40
+ "entity": { "type": "string" },
41
+ "field": { "type": "string" },
42
+ "operator": { "type": "string", "enum": ["==", "!=", ">", "<", ">=", "<=", "in", "not-in", "is-null", "is-not-null"] },
43
+ "value": {}
44
+ }
45
+ }
46
+ ]
47
+ }
48
+ },
33
49
  "examples": {
34
50
  "type": "array",
51
+ "description": "Test-ready examples: each example = a test case with concrete values. Minimum 2 per rule (happy_path + error). These feed Gherkin generation and automated tests.",
35
52
  "items": {
36
53
  "type": "object",
54
+ "required": ["input", "expected"],
37
55
  "properties": {
38
- "input": { "type": "string" },
39
- "expected": { "type": "string" }
56
+ "input": { "type": "string", "description": "LEGACY fallback. Prefer given/when/then format." },
57
+ "expected": { "type": "string", "description": "LEGACY fallback. Prefer given/when/then format." },
58
+ "scenario": { "type": "string", "enum": ["happy_path", "error", "boundary", "calculation", "security"], "description": "Test scenario type" },
59
+ "description": { "type": "string", "description": "Human-readable test case description" },
60
+ "given": { "type": "object", "description": "Initial state: Entity.field → concrete value. Ex: {\"Employee.code\": \"EMP-001\", \"existingCodes\": [\"EMP-001\"]}", "additionalProperties": true },
61
+ "when": { "type": "string", "description": "Triggering action. Ex: 'create', 'update', 'submit', 'calculate_remaining'" },
62
+ "then": { "type": "object", "description": "Expected outcome: {result: 'success'|'error', Entity.field: value, message: '...', field: '...'}", "additionalProperties": true }
63
+ }
64
+ }
65
+ },
66
+ "entities": {
67
+ "type": "array",
68
+ "items": { "type": "string" },
69
+ "description": "Entity names this rule applies to"
70
+ },
71
+ "testability": { "type": "string" },
72
+ "formula": { "type": "string", "description": "BR-CALC calculation formulas" },
73
+ "sectionCode": { "type": "string", "description": "Section code the rule applies to" },
74
+ "severity": { "type": "string", "enum": ["blocking", "warning", "info"] },
75
+ "consequences": {
76
+ "type": "array",
77
+ "items": {
78
+ "type": "object",
79
+ "required": ["type", "target"],
80
+ "properties": {
81
+ "type": { "type": "string", "enum": ["notification", "field-update", "status-change", "block-action", "recalculate"] },
82
+ "target": { "type": "string" },
83
+ "description": { "type": "string" }
40
84
  }
41
85
  }
42
86
  },
43
- "testability": { "type": "string" }
87
+ "domainSpecific": { "type": "boolean", "default": false, "description": "True if from domain research" }
44
88
  }
45
89
  }
46
90
  },
@@ -121,138 +121,9 @@ existing_projects: array of { projectName, projectId, applications[], version }
121
121
 
122
122
  ## Step 3b: Early Multi-Application Detection from Prompt (NEW)
123
123
 
124
- > **Detect multi-app structure BEFORE asking for a single application name.**
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.
124
+ > **Load** `references/multi-app-detection.md` for the multi-app detection algorithm (Tier 1 patterns, Tier 2 domain diversity scoring, extraction, confirmation).
127
125
 
128
- ### Tier 1 Explicit patterns (ANY match = multi-app detected)
129
-
130
- French patterns:
131
- - "une application X ... une application Y" (two occurrences of "une application")
132
- - "application 1: X ... application 2: Y" (numbered applications)
133
- - "première application ... deuxième application"
134
- - "app 1: ... app 2: ..."
135
-
136
- English patterns:
137
- - "an application (for) X ... an application (for) Y" (two occurrences)
138
- - "application #1: ... application #2: ..." (numbered)
139
- - "first app ... second app"
140
-
141
- If ANY of these patterns is found in `{feature_description}`:
142
- → `isMultiApp = true`, `detectionTier = "explicit"`
143
-
144
- ### Tier 2 — Domain diversity analysis (when Tier 1 does not match)
145
-
146
- ULTRATHINK: Analyze `{feature_description}` to extract distinct business domains.
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):**
168
-
169
- 1. **Identify boundaries:** Split the prompt at each "une application" / "an application" occurrence. Each block = one candidate.
170
- 2. **Extract per candidate:** For each block, derive `name` (application name), `description` (summary of purpose), and `modules[]` (listed modules/features).
171
- - Example: `[{ name: "RH", description: "gestion des employés, congés, temps", modules: ["Employés", "Congés", "Temps"] }, ...]`
172
- 3. **Detect shared modules:** Collect all module names across all candidates. Any module appearing in more than one candidate is a shared module.
173
- - Example: `sharedModules = ["Temps"]` (appears in both RH and Projet)
174
-
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:
187
-
188
- ```
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:")}
196
-
197
- | # | Application | Modules identifiés |
198
- |---|-------------|-------------------|
199
- {for each candidate: index | name | modules.join(", ") || "(à définir au cadrage)"}
200
-
201
- {sharedModules.length > 0
202
- ? "⚠️ **Modules partagés détectés :** {sharedModules.join(', ')} — ces modules apparaissent dans plusieurs applications. Ils pourraient constituer une application transversale dédiée."
203
- : ""}
204
- ```
205
-
206
- Ask via AskUserQuestion:
207
- ```
208
- question: "{language == 'fr' ? 'Confirmez-vous cette structure multi-application ?' : 'Do you confirm this multi-application structure?'}"
209
- header: "Architecture"
210
- options:
211
- - label: "{language == 'fr' ? 'Oui, {candidates.length} applications' : 'Yes, {candidates.length} applications'}"
212
- description: "{language == 'fr' ? 'Créer un projet avec les applications identifiées' : 'Create a project with the identified applications'}"
213
- - label: "{language == 'fr' ? 'Extraire les modules partagés' : 'Extract shared modules'}" (only if sharedModules.length > 0)
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'}"
217
- - label: "{language == 'fr' ? 'Application unique' : 'Single application'}"
218
- description: "{language == 'fr' ? 'Tout regrouper en une seule application avec plusieurs modules' : 'Group everything into one application with multiple modules'}"
219
- ```
220
-
221
- **IF "Oui, N applications" or "Extraire les modules partagés":**
222
-
223
- ```yaml
224
- workflow_mode: "project"
225
- project_name: derived from feature_description
226
- candidate_applications: [{ name, description, modules, context }]
227
- shared_modules_extracted: boolean # true if user chose extraction
228
- ```
229
-
230
- → Skip step 4 (application name) — applications will be confirmed in step-01-cadrage
231
- → Continue to step 5 (language selection)
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
-
246
- **IF "Application unique":**
247
-
248
- ```yaml
249
- workflow_mode: "application"
250
- ```
251
-
252
- → Continue to step 4 normally
253
-
254
- **IF no multi-app detected (neither Tier 1 nor Tier 2):**
255
- → Continue to step 4 normally
126
+ Execute the multi-app detection. IF multi-app detected set `workflow_mode = "project"` and skip step 4 (application name). ELSE continue to step 4 normally.
256
127
 
257
128
  ## Step 4: Determine Project Name & Application Name
258
129
 
@@ -365,20 +236,27 @@ ELSE:
365
236
  feature_id: string
366
237
  ```
367
238
 
368
- ## Step 7: Create Output Directory Structure
239
+ ## Step 7: Create Output Directory Structure (EXECUTABLE)
369
240
 
370
241
  ```
371
242
  projectDir = "docs/" + projectSlug + "/v" + version
243
+ docs_dir = projectDir
244
+ ```
372
245
 
373
- IF workflow_type = "new":
374
- mkdir -p {projectDir}
375
- docs_dir = projectDir
246
+ **MANDATORY Execute via Bash tool (NOT just pseudocode):**
376
247
 
377
- ELSE:
378
- // Directory already exists from previous session
379
- docs_dir = projectDir
248
+ ```bash
249
+ mkdir -p "{projectDir}"
250
+ ```
251
+
252
+ **POST-CHECK (BLOCKING):**
253
+
254
+ ```bash
255
+ ls -d "{projectDir}" 2>/dev/null || echo "DIRECTORY_MISSING"
380
256
  ```
381
257
 
258
+ If output contains `DIRECTORY_MISSING` → **BLOCKING ERROR: directory creation failed. Check permissions.**
259
+
382
260
  > **Key change (ba-006):** All project data lives under `docs/{projectSlug}/v{X.Y}/`.
383
261
  > No more `business-analyse/` intermediate directory. Applications and modules are
384
262
  > direct subdirectories: `docs/{projectSlug}/v{X.Y}/{appKebab}/{moduleKebab}/`.
@@ -575,57 +453,11 @@ analysisMode: "interactive"
575
453
  version: string
576
454
  ```
577
455
 
578
- ## Error Handling
579
-
580
- | Error | Action |
581
- |-------|--------|
582
- | Config missing | Create fresh with defaults, continue |
583
- | Directory creation fails | Check permissions, display error, EXIT |
584
- | index.json creation fails | Validate ba-writer, retry or fallback |
585
- | Feature ID not unique | Generate new ID, retry |
586
-
587
- ### Resume After Interruption
588
-
589
- If initialization was interrupted:
590
-
591
- 1. Check `.business-analyse/config.json` for currentFeature or currentProject
592
- 2. If project ID exists, search for project index.json in `docs/*/v*/` (or legacy `docs/business-analyse/`)
593
- - If found with scope = "project": resume project mode (see Project Resume below)
594
- 3. If feature ID exists, search for index.json in `docs/`
595
- 4. If found, check status and `metadata.workflow.lastCompletedStep`:
596
-
597
- **Status-based resume routing (check in this order):**
598
-
599
- - If status = `"handed-off"` or `"consolidated"`:
600
- → Display: "BA workflow complete. Use /business-analyse-html to generate HTML, /business-analyse-review for corrections."
601
- → STOP
602
-
603
- - If status = `"specified"` AND `metadata.workflow.allModulesSpecified === true`:
604
- → Resume at `step-04-consolidate.md`
605
- → Display: "All modules specified — resuming at consolidation..."
606
-
607
- - If status = `"specified"` AND `metadata.workflow.completedModules.length > 0` AND `metadata.workflow.completedModules.length < metadata.workflow.moduleOrder.length`:
608
- → Resume at `step-03-specify.md` (continue specifying remaining modules)
609
- → Display: "Resuming module specification ({completedCount}/{totalCount})..."
610
-
611
- - Otherwise: offer to resume from last completed step
612
-
613
- 5. If not found, create fresh index.json
614
-
615
- **Project Resume (project mode):**
616
-
617
- If a project-level index.json is found (scope = "project"):
618
-
619
- - If status = `"draft"` or `"framed"`:
620
- → Resume at `step-01-cadrage.md`
621
-
622
- - If status = `"decomposed"`:
623
- → Check `metadata.workflow.currentApplicationIndex` and `completedApplications[]`
624
- → Resume module specification for current application (step-02 or step-03)
456
+ ## Error Handling & Resume Logic
625
457
 
626
- - If status = `"specified"`:
627
- → All applications specified → Resume at `step-04-consolidate.md`
458
+ > → **Load** `references/init-resume-logic.md` for error handling matrix, resume detection, and status-based routing (draft → framed → decomposed → specified → consolidated → handed-off).
628
459
 
629
- - If status = `"consolidated"`:
630
- → Display: "BA workflow complete. Use /business-analyse-html to generate HTML."
631
- STOP
460
+ When re-running initialization, check for interrupted workflows:
461
+ 1. Read `.business-analyse/config.json` for currentFeature or currentProject
462
+ 2. Search for existing index.json files in `docs/` hierarchy
463
+ 3. Check status and route appropriately (see reference for status-based routing matrix)