@atlashub/smartstack-cli 2.7.1 → 2.7.2

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.
@@ -79,6 +79,44 @@ ba-reader.readApplicationContext({feature_id})
79
79
 
80
80
  Update module status in master: "pending" → "in-progress"
81
81
 
82
+ ### 2-ter. Derive Module Discovery Section (MANDATORY)
83
+
84
+ > **The module feature.json MUST have a `discovery` section.** In multi-module mode, derive it from the parent application's `cadrage`. In single-module mode, it should already exist from step-01.
85
+
86
+ ```
87
+ ba-reader.readApplicationContext({feature_id})
88
+ → Read cadrage: problem, asIs, toBe, trigger, stakeholders, risks, acceptanceCriteria
89
+
90
+ // Filter to this module's scope
91
+ moduleScope = cadrage.coverageMatrix.filter(cm => cm.module === currentModule.code)
92
+ moduleStakeholders = cadrage.stakeholders.filter(s => s.tasks relevant to this module)
93
+ moduleRisks = cadrage.risks.filter(r => r related to this module)
94
+
95
+ ba-writer.enrichSection({
96
+ featureId: {module_feature_id},
97
+ section: "discovery",
98
+ data: {
99
+ problem: cadrage.problem,
100
+ asIs: cadrage.asIs,
101
+ toBe: cadrage.toBe,
102
+ trigger: cadrage.trigger,
103
+ stakeholders: moduleStakeholders,
104
+ scope: {
105
+ mustHave: moduleScope.filter(s => s.category === "mustHave").map(s => s.item),
106
+ shouldHave: moduleScope.filter(s => s.category === "shouldHave").map(s => s.item),
107
+ couldHave: moduleScope.filter(s => s.category === "couldHave").map(s => s.item),
108
+ outOfScope: []
109
+ },
110
+ risks: moduleRisks,
111
+ acceptanceCriteria: cadrage.acceptanceCriteria.filter(ac => relevant to module),
112
+ codebaseContext: cadrage.codebaseContext
113
+ }
114
+ })
115
+ ```
116
+
117
+ > **STRUCTURE CARD: discovery** — Same format as cadrage but module-scoped.
118
+ > Fields: `problem`, `asIs`, `toBe`, `trigger`, `stakeholders[]`, `scope{}`, `risks[]`, `acceptanceCriteria[]`, `codebaseContext`, `openQuestions[]`
119
+
82
120
  ### 2-bis. Coverage Verification (MANDATORY)
83
121
 
84
122
  > **Before specifying any module, verify that the coverageMatrix from cadrage covers this module.**
@@ -149,8 +187,173 @@ options:
149
187
  description: "Tableau de bord avec KPIs, graphiques (Recharts) et métriques clés"
150
188
  ```
151
189
 
190
+ #### 3a-depth. Determine Specification Depth
191
+
192
+ > **Based on module complexity and type, determine how deeply to specify sections and resources.**
193
+ > **This avoids over-specifying simple modules and under-specifying complex ones.**
194
+
195
+ Read from application master:
196
+ ```
197
+ ba-reader.readApplicationContext({feature_id})
198
+ → module = modules.find(m => m.code === currentModule)
199
+ → complexity = module.estimatedComplexity // simple | medium | complex
200
+ → featureType = module.featureType // data-centric | workflow | integration | reporting | full-module
201
+ ```
202
+
203
+ **Depth decision matrix:**
204
+
205
+ | Complexity | featureType | Depth | Behavior |
206
+ |---|---|---|---|
207
+ | simple | data-centric | **convention** | Auto-generate sections + resources from entities. Quick client validation. |
208
+ | simple | reporting | **convention** | Standard dashboard template. Quick validation. |
209
+ | simple | * | **convention** | Standard sections for featureType. Quick validation. |
210
+ | medium | data-centric | **override** | Auto-generate then ask client which sections to customize. |
211
+ | medium | workflow | **full** | State machine required → always full. |
212
+ | medium | * | **override** | Auto-generate then ask client to customize. |
213
+ | complex | * | **full** | Full specification: state machine, typed columns, conditional actions. |
214
+ | * | workflow | **full** | Always full for workflow modules (state machine is mandatory). |
215
+
216
+ Display to client:
217
+ ```
218
+ "Module {currentModule}: complexité {complexity}, type {featureType} → profondeur: {depth}"
219
+ ```
220
+
221
+ **IF depth = convention:**
222
+ - Execute 3a-infer (auto-inference) → generates sections + resources
223
+ - Execute 3b (wireframes) for each section
224
+ - Skip 3a-bis detailed walkthrough → present auto-generated spec for quick validation
225
+ - Ask client: "La spécification auto-générée convient-elle, ou souhaitez-vous personnaliser certaines sections ?"
226
+ - If client says OK → proceed to step 4 (questionnaires)
227
+ - If client wants changes → switch to **override** for specified sections
228
+
229
+ **IF depth = override:**
230
+ - Execute 3a-infer (auto-inference) → generates base sections + resources
231
+ - Ask client: "Quelles sections souhaitez-vous personnaliser ?"
232
+ - For selected sections → execute full 3a-bis + 3b + 3b-ter
233
+ - For other sections → keep auto-generated spec
234
+
235
+ **IF depth = full:**
236
+ - Execute standard flow: 3a-bis → 3b → 3b-bis → 3b-ter → 3c → 3d (as currently defined below)
237
+ - PLUS: 3a-state (state machine definition) for entities with status fields
238
+
239
+ #### 3a-infer. Auto-Infer Resources from Entities (Convention/Override)
240
+
241
+ > **For convention and override depths, auto-generate resource details from entity definitions.**
242
+ > **The goal: produce a complete spec without manual input, that the client only validates.**
243
+
244
+ **Prerequisites:** Entity attributes must be defined (from step 6) OR anticipated from decomposition.
245
+
246
+ **Inference rules - Entity attribute → SmartTable column:**
247
+
248
+ | Attribute Type | Column Format | Sortable | Filterable | Notes |
249
+ |---|---|---|---|---|
250
+ | string + unique | text | yes | yes | clickAction: navigate:detail |
251
+ | string | text | yes | yes | — |
252
+ | enum / status | badge | yes | yes (multi-select) | colorMap from lifeCycles if exists |
253
+ | FK:Entity | text (join .name) | yes | yes (entity-select) | Display related entity name |
254
+ | decimal | currency | yes | no | — |
255
+ | int | number | yes | no | — |
256
+ | datetime | date-relative | yes | yes (date-range) | — |
257
+ | bool | boolean | yes | yes (toggle) | — |
258
+ | text (long) | — | no | no | Hidden in table, visible in detail |
259
+
260
+ **Inference rules - Entity attribute → SmartForm field:**
261
+
262
+ | Attribute Type | Component | Required from | Notes |
263
+ |---|---|---|---|
264
+ | string | Input | entity.required | — |
265
+ | string (multiline) | TextArea | entity.required | rows: 4 |
266
+ | enum | Select | entity.required | source: enum name |
267
+ | FK:Entity | EntitySelect | entity.required | source: target entity, searchable |
268
+ | decimal | NumberInput | entity.required | — |
269
+ | int | NumberInput | entity.required | — |
270
+ | datetime | DatePicker | entity.required | — |
271
+ | bool | Toggle | — | default: false |
272
+
273
+ **Auto-generated sections per featureType:**
274
+
275
+ | featureType | Sections generated |
276
+ |---|---|
277
+ | data-centric | list, create, detail |
278
+ | workflow | list, create, detail, edit |
279
+ | integration | list, detail, config |
280
+ | reporting | dashboard |
281
+ | full-module | list, create, detail, edit, dashboard |
282
+
283
+ **For each auto-generated section:**
284
+
285
+ 1. **list section:** SmartTable with all non-long-text attributes as columns (convention or columnDefs based on depth), actions = [view, edit, delete], defaultSort = { createdAt, desc }
286
+ 2. **create section:** SmartForm with all writable attributes as fields, component inferred from type
287
+ 3. **detail section:** DetailCard with all attributes + child SmartTable for each 1:N relationship
288
+ 4. **edit section:** Same as create but pre-filled (mode: edit)
289
+ 5. **dashboard section:** Trigger 3d (dashboard specification)
290
+
291
+ **If entity has a status/enum field AND lifeCycles exists:**
292
+ - list section: status column gets `format: badge`, `colorMap: stateMachine:{Entity}`
293
+ - list section: rowActions get `showWhen` conditions based on state machine transitions
294
+ - detail section: add StatusBadge resource + transition action buttons
295
+
296
+ Write auto-generated sections to `specification.sections[]` via ba-writer.enrichSection()
297
+
298
+ #### 3a-state. Define Entity State Machine (Full Depth)
299
+
300
+ > **For full depth modules with entities that have a status/enum field, define the complete state machine.**
301
+ > **This drives conditional actions, badges, and transition effects throughout the UI.**
302
+
303
+ For each entity with a status-like attribute:
304
+
305
+ 1. **Identify states** from the enum values or business rules:
306
+ ```
307
+ Ask client: "Quels sont les états possibles pour {Entity}.{statusField} ?"
308
+ ```
309
+
310
+ 2. **Define transitions** - for each state, ask:
311
+ ```
312
+ Ask client: "Depuis l'état {state}, quelles transitions sont possibles ?"
313
+ ```
314
+
315
+ 3. **For each transition**, capture:
316
+ - `action`: verb label (submit, approve, reject, cancel, archive)
317
+ - `permission`: which permission is required
318
+ - `guards`: which BR must pass (reference existing BR-XXX from analysis)
319
+ - `effects`: what happens after (notification, email, field update)
320
+ - `confirm`: does the user need to confirm?
321
+
322
+ 4. **Assign colors** to states for badge rendering:
323
+ - Draft/New → gray
324
+ - In Progress/Submitted → blue
325
+ - Approved/Active → green
326
+ - Warning/Pending → yellow
327
+ - Error/Rejected → red
328
+ - Archived/Cancelled → purple
329
+
330
+ 5. **Store** in `specification.lifeCycles[]`:
331
+ ```json
332
+ {
333
+ "entity": "{Entity}",
334
+ "field": "status",
335
+ "initialState": "{firstState}",
336
+ "states": [
337
+ { "id": "draft", "displayName": "Brouillon", "color": "gray", "allowedTransitions": ["submitted"], "isTerminal": false }
338
+ ],
339
+ "transitions": [
340
+ {
341
+ "from": "draft", "to": "submitted", "action": "submit",
342
+ "permission": "business.{app}.{module}.submit",
343
+ "guards": ["BR-VAL-{PREFIX}-001"],
344
+ "effects": [{ "type": "notification", "target": "role:manager", "template": "{module}-submitted" }],
345
+ "confirm": true
346
+ }
347
+ ]
348
+ }
349
+ ```
350
+
351
+ 6. **Cross-validate:** Every `allowedTransitions` entry must have a matching `transitions[]` entry.
352
+
152
353
  #### 3a-bis. Structure Sections with Resources (Levels 4 & 5)
153
354
 
355
+ > **DEPTH GATE:** Execute this section for **full** depth, or for individual sections flagged for customization in **override** depth. For **convention** depth, sections are auto-generated by 3a-infer — skip to 3b.
356
+
154
357
  For EACH section confirmed in 3a, build the `specification.sections[]` structure:
155
358
 
156
359
  1. For each resource in the section, determine:
@@ -169,29 +372,73 @@ For EACH section confirmed in 3a, build the `specification.sections[]` structure
169
372
  - Map BR based on where it's enforced (validation BR → create/edit section, calc BR → detail section)
170
373
 
171
374
  4. Build the section object:
172
- ```json
173
- {
174
- "code": "list",
175
- "labels": { "fr": "Liste", "en": "List", "it": "Elenco", "de": "Liste" },
176
- "route": "/business/{app}/{module}/list",
177
- "icon": "list",
178
- "permission": "business.{app}.{module}.read",
179
- "wireframe": "{module}-list",
180
- "useCases": ["UC-{PREFIX}-001", "UC-{PREFIX}-002"],
181
- "businessRules": ["BR-VAL-{PREFIX}-001"],
182
- "resources": [
183
- {
184
- "code": "{module}-grid",
185
- "type": "SmartTable",
186
- "entity": "{MainEntity}",
187
- "permission": "business.{app}.{module}.read",
188
- "columns": ["name", "status", "createdAt"],
189
- "actions": ["view", "edit", "delete"],
190
- "filters": ["status", "dateRange"]
191
- }
192
- ]
193
- }
194
- ```
375
+
376
+ > **STRUCTURE CARD: specification.sections[]** — Resources MUST include full depth definitions.
377
+ > ```json
378
+ > {
379
+ > "code": "list",
380
+ > "labels": { "fr": "Liste", "en": "List", "it": "Elenco", "de": "Liste" },
381
+ > "route": "/business/{app}/{module}/list",
382
+ > "icon": "list",
383
+ > "permission": "business.{app}.{module}.read",
384
+ > "wireframe": "{module}-list",
385
+ > "useCases": ["UC-{PREFIX}-001", "UC-{PREFIX}-002"],
386
+ > "businessRules": ["BR-VAL-{PREFIX}-001"],
387
+ > "resources": [
388
+ > {
389
+ > "code": "{module}-grid",
390
+ > "type": "SmartTable",
391
+ > "entity": "{MainEntity}",
392
+ > "permission": "business.{app}.{module}.read",
393
+ > "columns": ["name", "status", "createdAt"],
394
+ > "columnDefs": [
395
+ > { "field": "code", "label": {"fr": "Code", "en": "Code"}, "format": "text", "sortable": true, "filterable": true, "clickAction": "navigate:detail" },
396
+ > { "field": "name", "label": {"fr": "Nom", "en": "Name"}, "format": "text", "sortable": true, "filterable": true },
397
+ > { "field": "status", "label": {"fr": "Statut", "en": "Status"}, "format": "badge", "sortable": true, "filterable": true, "colorMap": "stateMachine:{Entity}" },
398
+ > { "field": "createdAt", "label": {"fr": "Créé le", "en": "Created"}, "format": "date-relative", "sortable": true }
399
+ > ],
400
+ > "actions": ["view", "edit", "delete"],
401
+ > "rowActions": [
402
+ > { "action": "view", "icon": "eye", "permission": "business.{app}.{module}.read" },
403
+ > { "action": "edit", "icon": "edit", "permission": "business.{app}.{module}.update", "showWhen": {"status": ["draft"]} },
404
+ > { "action": "delete", "icon": "trash", "permission": "business.{app}.{module}.delete", "confirm": true }
405
+ > ],
406
+ > "filters": ["status", "dateRange"],
407
+ > "defaultSort": { "field": "createdAt", "direction": "desc" },
408
+ > "defaultPageSize": 20,
409
+ > "emptyState": { "icon": "inbox", "message": {"fr": "Aucun enregistrement", "en": "No records"}, "createAction": true }
410
+ > }
411
+ > ]
412
+ > }
413
+ > ```
414
+ >
415
+ > **SmartForm resource example (for create/edit sections):**
416
+ > ```json
417
+ > {
418
+ > "code": "{module}-form",
419
+ > "type": "SmartForm",
420
+ > "entity": "{MainEntity}",
421
+ > "permission": "business.{app}.{module}.create",
422
+ > "fields": [
423
+ > { "name": "code", "component": "Input", "required": true, "validation": "Unique, auto-generated" },
424
+ > { "name": "name", "component": "Input", "required": true },
425
+ > { "name": "type", "component": "Select", "required": true, "source": "EntityTypeEnum" },
426
+ > { "name": "description", "component": "TextArea", "required": false },
427
+ > { "name": "parentId", "component": "EntitySelect", "source": "ParentEntity", "required": true },
428
+ > { "name": "startDate", "component": "DatePicker", "required": true },
429
+ > { "name": "isActive", "component": "Toggle", "default": true }
430
+ > ],
431
+ > "formLayout": {
432
+ > "type": "tabs",
433
+ > "tabs": [
434
+ > { "code": "general", "label": {"fr": "Général", "en": "General"}, "fields": ["code", "name", "type", "description"] },
435
+ > { "code": "details", "label": {"fr": "Détails", "en": "Details"}, "fields": ["parentId", "startDate", "isActive"] }
436
+ > ]
437
+ > }
438
+ > }
439
+ > ```
440
+ > **MANDATORY for SmartTable:** `columnDefs`, `rowActions`, `defaultSort`, `emptyState`
441
+ > **MANDATORY for SmartForm:** `fields` with `component` type, `formLayout`
195
442
 
196
443
  5. Write `specification.sections[]` via ba-writer.enrichSection()
197
444
 
@@ -221,20 +468,39 @@ Example for a list section:
221
468
 
222
469
  Store in specification.uiWireframes[] (**MANDATORY** for every section):
223
470
 
224
- ```json
225
- {
226
- "screen": "{module}-{section}",
227
- "section": "{section}",
228
- "description": "Description of the screen",
229
- "mockupFormat": "ascii",
230
- "mockup": "╔═══...",
231
- "elements": ["DataGrid", "FilterBar", "Pagination", "CreateButton"],
232
- "actions": ["filter", "sort", "create", "view-detail"],
233
- "permissionsRequired": ["business.{app}.{module}.read"]
234
- }
235
- ```
236
-
237
- > **REQUIRED fields:** `screen`, `mockup`, `elements`, `section` are all mandatory. A wireframe without these fields will FAIL validation in step 9.
471
+ > **STRUCTURE CARD: specification.uiWireframes[]** — ALL fields below are MANDATORY.
472
+ > ```json
473
+ > {
474
+ > "screen": "{module}-{section}",
475
+ > "section": "{section}",
476
+ > "description": "Description of the screen",
477
+ > "mockupFormat": "ascii",
478
+ > "mockup": "╔═══...",
479
+ > "elements": ["DataGrid", "FilterBar", "Pagination", "CreateButton"],
480
+ > "actions": ["filter", "sort", "create", "view-detail"],
481
+ > "permissionsRequired": ["business.{app}.{module}.read"],
482
+ > "componentMapping": [
483
+ > { "wireframeElement": "DataGrid", "reactComponent": "SmartTable" },
484
+ > { "wireframeElement": "FilterBar", "reactComponent": "SmartFilter" },
485
+ > { "wireframeElement": "CreateButton", "reactComponent": "Button" }
486
+ > ],
487
+ > "layout": {
488
+ > "type": "page",
489
+ > "regions": [
490
+ > { "id": "toolbar", "position": "top", "components": [
491
+ > { "type": "FilterBar", "resourceRef": "{module}-filters" },
492
+ > { "type": "ActionMenu", "resourceRef": "{module}-actions", "permission": "business.{app}.{module}.create" }
493
+ > ]},
494
+ > { "id": "content", "position": "main", "span": 12, "components": [
495
+ > { "type": "SmartTable", "resourceRef": "{module}-grid" }
496
+ > ]}
497
+ > ]
498
+ > }
499
+ > }
500
+ > ```
501
+ > **REQUIRED fields:** `screen`, `mockup`, `elements`, `section`, `componentMapping`, `layout` are ALL mandatory.
502
+ > A wireframe without `componentMapping` or `layout` will FAIL validation in step 9.
503
+ > **layout.regions[].components[].resourceRef** MUST match a `sections[].resources[].code`.
238
504
 
239
505
  Ask client to validate each mockup via AskUserQuestion (batch 2-3 mockups at once if possible).
240
506
 
@@ -332,7 +598,8 @@ When a "dashboard" section is selected, capture structured KPI and chart data **
332
598
  "metric": "COUNT(entity)",
333
599
  "format": "number",
334
600
  "visualization": "kpi-card",
335
- "dataSource": "Entity"
601
+ "dataSource": "Entity",
602
+ "thresholds": { "warning": 100, "critical": 50 }
336
603
  },
337
604
  {
338
605
  "code": "items-by-status",
@@ -435,101 +702,374 @@ options:
435
702
  description: "Pas de référence à {completedModule}"
436
703
  ```
437
704
 
438
- ### 6. Entity Definition
705
+ ### 6. Analysis Section
439
706
 
440
- Define entities for this module (business attributes, not technical):
707
+ #### 6a. Objectives
441
708
 
442
- For each entity:
709
+ Define measurable business objectives for this module:
443
710
 
444
- ```json
445
- {
446
- "name": "PascalCase",
447
- "description": "1-2 sentences",
448
- "attributes": [
449
- { "name": "attributeName", "type": "string|int|decimal|datetime|enum|FK", "required": true/false, "rules": "validation description" }
450
- ],
451
- "relationships": [
452
- { "target": "OtherEntity", "type": "1:N", "description": "description" }
453
- ]
454
- }
455
- ```
711
+ > **STRUCTURE CARD: analysis.objectives[]**
712
+ > ```json
713
+ > { "id": "OBJ-{PREFIX}-001", "objective": "Reduce order processing time", "metric": "Average time to fulfillment", "target": "< 4 hours" }
714
+ > ```
715
+
716
+ #### 6b. Entity Definition
717
+
718
+ Define entities for this module (business attributes, not technical):
719
+
720
+ > **STRUCTURE CARD: analysis.entities[]** — Field names are EXACT. Do NOT deviate.
721
+ > ```json
722
+ > {
723
+ > "name": "PascalCase",
724
+ > "description": "1-2 sentences describing the entity purpose",
725
+ > "attributes": [
726
+ > {
727
+ > "name": "attributeName",
728
+ > "description": "What this attribute represents",
729
+ > "required": true,
730
+ > "unique": false,
731
+ > "validation": "Format: XXX-NNNNN, max 100 chars, etc."
732
+ > }
733
+ > ],
734
+ > "relationships": [
735
+ > { "target": "OtherEntity", "type": "1:1|1:N|N:1|N:M", "description": "description" }
736
+ > ]
737
+ > }
738
+ > ```
739
+ > **FORBIDDEN fields in attributes:** Do NOT use `type`, `values`, `rules`.
740
+ > Use `description` to explain what the attribute is, `validation` for format/constraint rules, `unique` as boolean.
741
+
742
+ #### 6c. Process Flow
743
+
744
+ Define the main business process flow for this module (not lifecycle — that's in 8j):
745
+
746
+ > **STRUCTURE CARD: analysis.processFlow**
747
+ > ```json
748
+ > {
749
+ > "entryPoints": ["User navigates to module", "System event triggers action"],
750
+ > "mainFlow": [
751
+ > { "step": 1, "actor": "Manager", "action": "Opens the list", "system": "Displays filtered records" },
752
+ > { "step": 2, "actor": "Manager", "action": "Creates a record", "system": "Validates BR-VAL-{PREFIX}-001" },
753
+ > { "step": 3, "actor": "System", "action": "Saves record", "system": "Sends notification" }
754
+ > ],
755
+ > "decisionPoints": [
756
+ > { "condition": "Is amount > threshold?", "ifTrue": "Route to approver", "ifFalse": "Auto-approve", "rule": "BR-WF-{PREFIX}-001" }
757
+ > ],
758
+ > "alternativeFlows": ["Bulk import via CSV", "Automatic sync from SFTP"]
759
+ > }
760
+ > ```
761
+ > **FORBIDDEN:** Do NOT put lifecycle/state machine data here. Use `specification.lifeCycles[]` for that.
762
+
763
+ #### 6d. Data Lifecycle
764
+
765
+ Define data retention and lifecycle policies:
766
+
767
+ > **STRUCTURE CARD: analysis.dataLifecycle**
768
+ > ```json
769
+ > {
770
+ > "retentionPeriod": "7 years",
771
+ > "archiveStrategy": "Move to cold storage after 2 years",
772
+ > "gdprCompliance": "PII anonymized on request, data export available",
773
+ > "states": [
774
+ > { "name": "active", "transitions": ["archived", "deleted"] },
775
+ > { "name": "archived", "transitions": ["active"] },
776
+ > { "name": "deleted", "transitions": [] }
777
+ > ]
778
+ > }
779
+ > ```
456
780
 
457
781
  ### 7. Business Rules Extraction
458
782
 
459
783
  Extract business rules specific to this module:
460
784
 
461
- Format: BR-{CATEGORY}-NNN where CATEGORY is VAL/CALC/WF/SEC/DATA
462
-
463
- ```json
464
- {
465
- "id": "BR-VAL-001",
466
- "rule": "Description of the rule",
467
- "category": "Validation",
468
- "priority": "Must",
469
- "condition": "When X happens",
470
- "action": "Then Y must be true",
471
- "examples": [{ "input": "...", "expected": "..." }],
472
- "linkedRules": ["BR-WF-002"]
473
- }
474
- ```
785
+ > **STRUCTURE CARD: analysis.businessRules[]** Field names are EXACT. Do NOT deviate.
786
+ > ```json
787
+ > {
788
+ > "id": "BR-VAL-{PREFIX}-001",
789
+ > "name": "Short rule name",
790
+ > "category": "validation|calculation|workflow|security|data",
791
+ > "statement": "IF {condition} THEN {consequence} ELSE {alternative}",
792
+ > "priority": "must|should|could",
793
+ > "conditions": ["Condition 1", "Condition 2"],
794
+ > "examples": [{ "input": "Order total $5000, budget $2000", "expected": "Order rejected" }],
795
+ > "testability": "Via unit test with mock data / integration test"
796
+ > }
797
+ > ```
798
+ > **MANDATORY fields:** `id`, `name`, `category`, `statement`, `priority`
799
+ > **FORBIDDEN fields:** Do NOT use `rule`, `condition` (singular), `action`. Use `name` + `statement` (IF/THEN/ELSE format) + `conditions` (array).
800
+ > **ID PATTERN:** `BR-{CAT}-{PREFIX}-{NNN}` where CAT = VAL|CALC|WF|SEC|DATA, PREFIX = module initials (2-4 chars)
801
+ > **category values:** lowercase only: `validation`, `calculation`, `workflow`, `security`, `data`
475
802
 
476
803
  ### 8. Full Specification
477
804
 
478
- Generate the complete specification for this module:
805
+ Generate the complete specification for this module. **Each subsection below includes a STRUCTURE CARD showing the EXACT JSON format. Follow them precisely.**
479
806
 
480
807
  #### 8a. Actors
481
808
 
482
- Inherited from application roles → mapped to module permissions
483
-
484
- #### 8b. Use Cases (UC-NNN)
809
+ Inherited from application roles → mapped to module permissions.
810
+
811
+ > **STRUCTURE CARD: specification.actors[]**
812
+ > ```json
813
+ > {
814
+ > "role": "Sales Manager",
815
+ > "description": "Creates and approves orders",
816
+ > "permissions": [
817
+ > "business.{app}.{module}.read",
818
+ > "business.{app}.{module}.create",
819
+ > "business.{app}.{module}.update"
820
+ > ]
821
+ > }
822
+ > ```
823
+ > **MANDATORY fields:** `role`, `permissions` (array of permission paths)
824
+ > **FORBIDDEN fields:** Do NOT use `systemRole`. Use `permissions` array.
825
+
826
+ #### 8b. Use Cases (UC-{PREFIX}-NNN)
485
827
 
486
828
  Per section: list, create, read, update, delete, approve, etc.
487
829
 
488
- #### 8c. Functional Requirements (FR-NNN)
489
-
490
- Linked to BRs and UCs
830
+ > **STRUCTURE CARD: specification.useCases[]**
831
+ > ```json
832
+ > {
833
+ > "id": "UC-{PREFIX}-001",
834
+ > "name": "Create Order",
835
+ > "primaryActor": "Sales Representative",
836
+ > "permission": "business.{app}.{module}.create",
837
+ > "preconditions": ["Customer exists", "Products in stock"],
838
+ > "postconditions": ["Order created with Draft status"],
839
+ > "mainScenario": [
840
+ > "1. User navigates to creation form",
841
+ > "2. User fills in required fields",
842
+ > "3. System validates data (BR-VAL-{PREFIX}-001)",
843
+ > "4. System creates the record",
844
+ > "5. System displays confirmation"
845
+ > ],
846
+ > "alternativeScenarios": [
847
+ > { "name": "Validation failure", "steps": ["1. System detects invalid data", "2. System highlights errors"] }
848
+ > ],
849
+ > "errorScenarios": [
850
+ > { "name": "Server error", "steps": ["1. System shows error message", "2. Data preserved for retry"] }
851
+ > ],
852
+ > "linkedRules": ["BR-VAL-{PREFIX}-001", "BR-WF-{PREFIX}-002"]
853
+ > }
854
+ > ```
855
+ > **MANDATORY fields:** `id`, `name`, `primaryActor`, `permission`, `mainScenario`, `linkedRules`
856
+ > **FORBIDDEN fields:** Do NOT use `actor` (use `primaryActor`), `linkedBRs` (use `linkedRules`), `linkedFRs` (not in UC, FRs link to UCs instead)
857
+
858
+ #### 8c. Functional Requirements (FR-{PREFIX}-NNN)
859
+
860
+ Linked to BRs and UCs.
861
+
862
+ > **STRUCTURE CARD: specification.functionalRequirements[]**
863
+ > ```json
864
+ > {
865
+ > "id": "FR-{PREFIX}-001",
866
+ > "statement": "System MUST validate customer budget before order creation",
867
+ > "priority": "must|should|could",
868
+ > "linkedRules": ["BR-VAL-{PREFIX}-001"],
869
+ > "linkedUseCases": ["UC-{PREFIX}-001"],
870
+ > "acceptanceCriteria": [
871
+ > "Order rejected if total > budget",
872
+ > "Error message displayed with remaining budget"
873
+ > ]
874
+ > }
875
+ > ```
876
+ > **MANDATORY fields:** `id`, `statement`, `priority`, `linkedUseCases`
877
+ > **FORBIDDEN fields:** Do NOT use `name`/`description` (use `statement` with System MUST/SHOULD/COULD format), `linkedUCs` (use `linkedUseCases`), `linkedBRs` (use `linkedRules`)
491
878
 
492
879
  #### 8d. Permission Matrix
493
880
 
494
- Roles × resources × operations with full paths: `business.{app}.{module}.{resource}.{action}`
881
+ Roles × resources × operations with full paths.
882
+
883
+ > **STRUCTURE CARD: specification.permissionMatrix**
884
+ > ```json
885
+ > {
886
+ > "permissions": [
887
+ > { "path": "business.{app}.{module}.read", "action": "read", "description": "View records" },
888
+ > { "path": "business.{app}.{module}.create", "action": "create", "description": "Create new records" },
889
+ > { "path": "business.{app}.{module}.update", "action": "update", "description": "Update existing records" },
890
+ > { "path": "business.{app}.{module}.delete", "action": "delete", "description": "Delete records" },
891
+ > { "path": "business.{app}.{module}.export", "action": "export", "description": "Export data" }
892
+ > ],
893
+ > "roleAssignments": [
894
+ > { "role": "{App} Admin", "permissions": ["business.{app}.{module}.read", "business.{app}.{module}.create", "business.{app}.{module}.update", "business.{app}.{module}.delete", "business.{app}.{module}.export"] },
895
+ > { "role": "{App} Manager", "permissions": ["business.{app}.{module}.read", "business.{app}.{module}.create", "business.{app}.{module}.update"] },
896
+ > { "role": "{App} Viewer", "permissions": ["business.{app}.{module}.read"] }
897
+ > ]
898
+ > }
899
+ > ```
900
+ > **STRUCTURE:** Object with 2 arrays: `permissions[]` and `roleAssignments[]`
901
+ > **FORBIDDEN:** Do NOT use a flat array with `resource`/`roles` fields. Always use the nested structure above.
495
902
 
496
903
  #### 8e. Navigation
497
904
 
498
- Module → Sections → Resources (levels 3-4-5 of the hierarchy)
905
+ Module → Sections → Resources (levels 3-4-5 of the hierarchy).
499
906
 
500
- #### 8f. SeedData Core
907
+ > **STRUCTURE CARD: specification.navigation**
908
+ > ```json
909
+ > {
910
+ > "entries": [
911
+ > { "level": "module", "code": "{module}", "labels": {"fr": "...", "en": "..."}, "route": "/business/{app}/{module}", "icon": "list" },
912
+ > { "level": "section", "code": "list", "labels": {"fr": "Liste", "en": "List", "it": "Elenco", "de": "Liste"}, "route": "/business/{app}/{module}/list", "icon": "list" },
913
+ > { "level": "section", "code": "dashboard", "labels": {"fr": "Dashboard", "en": "Dashboard"}, "route": "/business/{app}/{module}/dashboard", "icon": "chart-bar", "isNew": true }
914
+ > ]
915
+ > }
916
+ > ```
501
917
 
502
- 5 mandatory files:
918
+ #### 8f. SeedData Core
503
919
 
504
- 1. NavigationModuleConfiguration (from navigation entries)
505
- 2. NavigationTranslationConfiguration (4 languages)
506
- 3. PermissionConfiguration (full path format)
507
- 4. RolePermissionConfiguration (role → permission mapping)
508
- 5. Permissions.cs constants (PascalCase)
920
+ 5 MANDATORY typed arrays — each with structured objects, NOT flat strings or objects.
921
+
922
+ > **STRUCTURE CARD: specification.seedDataCore**
923
+ > ```json
924
+ > {
925
+ > "navigationModules": [
926
+ > { "code": "{module}", "label": "{Module Name}", "icon": "list", "route": "/business/{app}/{module}", "parentCode": "{app}", "sort": 1 }
927
+ > ],
928
+ > "navigationTranslations": [
929
+ > { "moduleCode": "{module}", "language": "fr", "label": "..." },
930
+ > { "moduleCode": "{module}", "language": "en", "label": "..." },
931
+ > { "moduleCode": "{module}", "language": "it", "label": "..." },
932
+ > { "moduleCode": "{module}", "language": "de", "label": "..." }
933
+ > ],
934
+ > "permissions": [
935
+ > { "path": "business.{app}.{module}.read", "action": "read", "description": "View {module}" },
936
+ > { "path": "business.{app}.{module}.create", "action": "create", "description": "Create {module}" }
937
+ > ],
938
+ > "rolePermissions": [
939
+ > { "role": "{App} Admin", "permissionPath": "business.{app}.{module}.*" },
940
+ > { "role": "{App} Manager", "permissionPath": "business.{app}.{module}.read" }
941
+ > ],
942
+ > "permissionConstants": [
943
+ > { "constantName": "{Module}Read", "path": "business.{app}.{module}.read" },
944
+ > { "constantName": "{Module}Create", "path": "business.{app}.{module}.create" }
945
+ > ]
946
+ > }
947
+ > ```
948
+ > **MANDATORY:** All 5 arrays must be present. Each element must be an object, NOT a string.
949
+ > **FORBIDDEN:** Do NOT use `navigationModule` (singular string), `permissions` as flat string array, `rolePermissions` as flat object, `permissionsConstants` as comma-separated string.
509
950
 
510
951
  #### 8g. Gherkin Scenarios
511
952
 
512
- BDD acceptance tests per UC
953
+ BDD acceptance tests per UC.
954
+
955
+ > **STRUCTURE CARD: specification.gherkinScenarios[]**
956
+ > ```json
957
+ > {
958
+ > "feature": "{Module} Management",
959
+ > "scenarios": [
960
+ > {
961
+ > "name": "Create a new record with valid data",
962
+ > "tags": ["@{module}", "@create", "@smoke"],
963
+ > "given": ["An authenticated user with role Manager", "No existing record with code 'TEST-001'"],
964
+ > "when": ["The user fills the creation form", "The user submits the form"],
965
+ > "then": ["The record is created with Draft status", "A success message is displayed"]
966
+ > }
967
+ > ]
968
+ > }
969
+ > ```
970
+ > **STRUCTURE:** Object with `feature` string + `scenarios[]` array. Each scenario has `given`, `when`, `then` as ARRAYS of strings.
971
+ > **FORBIDDEN:** Do NOT use flat arrays of `{uc, scenario, given, when, then}` where given/when/then are single strings.
513
972
 
514
973
  #### 8h. Validations
515
974
 
516
- Field validation rules
975
+ Field validation rules per entity.
976
+
977
+ > **STRUCTURE CARD: specification.validations[]**
978
+ > ```json
979
+ > {
980
+ > "entity": "Order",
981
+ > "field": "amount",
982
+ > "rules": ["required", "decimal", "min:0.01", "max:999999.99"],
983
+ > "errorMessageKey": "validation.{module}.amount.invalid"
984
+ > }
985
+ > ```
986
+ > **MANDATORY fields:** `entity`, `field`, `rules` (array), `errorMessageKey`
987
+ > **FORBIDDEN fields:** Do NOT use `rule` (singular string) or `message` (use `errorMessageKey`).
517
988
 
518
989
  #### 8i. Business Messages
519
990
 
520
- Minimum 4: success, error CRUD, error validation, error permission
991
+ Minimum 4: success, error CRUD, error validation, error permission.
992
+
993
+ > **STRUCTURE CARD: specification.messages[]**
994
+ > ```json
995
+ > {
996
+ > "code": "{MODULE}-SUCCESS-CREATE",
997
+ > "type": "success|error|warning|info",
998
+ > "title": "Record Created",
999
+ > "message": "The record {code} has been created successfully.",
1000
+ > "i18nKey": "message.{module}.created"
1001
+ > }
1002
+ > ```
1003
+ > **MANDATORY fields:** `code`, `type`, `message`, `i18nKey`
1004
+ > **FORBIDDEN:** Do NOT omit `title` or `i18nKey`. Every message MUST have an i18n key.
521
1005
 
522
1006
  #### 8j. Entity Lifecycle
523
1007
 
524
- State machines for entities with status/state
1008
+ State machines for entities with status/state.
1009
+ **Note:** If depth = full and 3a-state was executed, lifeCycles are already defined. Verify completeness and add any missing states/transitions.
1010
+
1011
+ > **STRUCTURE CARD: specification.lifeCycles[]**
1012
+ > ```json
1013
+ > {
1014
+ > "entity": "Order",
1015
+ > "field": "status",
1016
+ > "initialState": "draft",
1017
+ > "states": [
1018
+ > { "id": "draft", "displayName": "Brouillon", "color": "gray", "allowedTransitions": ["submitted"], "isTerminal": false },
1019
+ > { "id": "submitted", "displayName": "Soumis", "color": "blue", "allowedTransitions": ["approved", "rejected"], "isTerminal": false },
1020
+ > { "id": "approved", "displayName": "Approuvé", "color": "green", "allowedTransitions": ["archived"], "isTerminal": false },
1021
+ > { "id": "rejected", "displayName": "Rejeté", "color": "red", "allowedTransitions": [], "isTerminal": true },
1022
+ > { "id": "archived", "displayName": "Archivé", "color": "purple", "allowedTransitions": [], "isTerminal": true }
1023
+ > ],
1024
+ > "transitions": [
1025
+ > {
1026
+ > "from": "draft", "to": "submitted", "action": "submit",
1027
+ > "label": { "fr": "Soumettre", "en": "Submit" },
1028
+ > "permission": "business.{app}.{module}.update",
1029
+ > "guards": ["BR-VAL-{PREFIX}-001"],
1030
+ > "effects": [{ "type": "notification", "target": "role:manager", "template": "{module}-submitted" }],
1031
+ > "confirm": true
1032
+ > }
1033
+ > ]
1034
+ > }
1035
+ > ```
1036
+ > **MANDATORY:** `states` MUST be an array of OBJECTS with `id`, `displayName`, `color`, `allowedTransitions`, `isTerminal`. NEVER use flat string arrays.
1037
+ > **Colors:** gray (draft/new), blue (in-progress), green (active/approved), yellow (warning/pending), orange (review), red (error/rejected), purple (archived/terminal)
1038
+ > **FORBIDDEN:** Do NOT use `states: ["Active", "Inactive"]` (flat strings), `terminalStates` (use `isTerminal: true` on each state).
525
1039
 
526
1040
  #### 8k. API Endpoints
527
1041
 
528
- RESTful routes following SmartStack patterns
1042
+ RESTful routes following SmartStack patterns.
1043
+
1044
+ > **STRUCTURE CARD: specification.apiEndpoints[]**
1045
+ > ```json
1046
+ > {
1047
+ > "method": "GET|POST|PUT|PATCH|DELETE",
1048
+ > "path": "/api/business/{app}/{module}",
1049
+ > "permission": "business.{app}.{module}.read",
1050
+ > "requestDto": "Get{Module}Query",
1051
+ > "responseDto": "{Module}Dto[]",
1052
+ > "description": "List all records with pagination and filters"
1053
+ > }
1054
+ > ```
1055
+ > **MANDATORY fields:** `method`, `path`, `permission`, `description`
1056
+ > **Recommended:** Include `requestDto` and `responseDto` for implementation clarity.
529
1057
 
530
1058
  #### 8l. i18n Keys
531
1059
 
532
- Translation keys for all UI text (4 languages: fr, en, it, de)
1060
+ Translation keys for all UI text (4 languages: fr, en, it, de).
1061
+
1062
+ > **STRUCTURE CARD: specification.i18nKeys**
1063
+ > ```json
1064
+ > {
1065
+ > "title": { "fr": "{Module}", "en": "{Module}", "it": "{Module}", "de": "{Module}" },
1066
+ > "list": { "title": { "fr": "Liste", "en": "List" }, "empty": { "fr": "Aucun enregistrement", "en": "No records" } },
1067
+ > "create": { "title": { "fr": "Nouveau", "en": "New" } },
1068
+ > "detail": { "title": { "fr": "Détail", "en": "Detail" } },
1069
+ > "buttons": { "create": { "fr": "Créer", "en": "Create" }, "edit": { "fr": "Modifier", "en": "Edit" }, "delete": { "fr": "Supprimer", "en": "Delete" } },
1070
+ > "validation": { "required": { "fr": "Ce champ est requis", "en": "This field is required" } }
1071
+ > }
1072
+ > ```
533
1073
 
534
1074
  ### 9. Per-Module Validation
535
1075
 
@@ -587,6 +1127,48 @@ IF validation FAIL:
587
1127
  description: "Accepter malgré les erreurs (risqué)"
588
1128
  ```
589
1129
 
1130
+ #### 9e. Write Module Validation Section (MANDATORY)
1131
+
1132
+ > **The module feature.json MUST have a `validation` section recording the results of steps 9a-9d.**
1133
+
1134
+ ```
1135
+ ba-writer.enrichSection({
1136
+ featureId: {module_feature_id},
1137
+ section: "validation",
1138
+ data: {
1139
+ validatedAt: "{ISO timestamp}",
1140
+ completenessChecks: [
1141
+ { "section": "useCases", "count": {count}, "minimum": 2, "status": "PASS|FAIL" },
1142
+ { "section": "functionalRequirements", "count": {count}, "minimum": 4, "status": "PASS|FAIL" },
1143
+ { "section": "wireframes", "count": {count}, "minimum": {section_count}, "status": "PASS|FAIL" },
1144
+ { "section": "seedDataCore", "count": 5, "minimum": 5, "status": "PASS|FAIL" }
1145
+ ],
1146
+ consistencyChecks: [
1147
+ { "check": "UC-FR linkage", "passed": {n}, "warnings": {n}, "errors": {n}, "status": "PASS|FAIL" },
1148
+ { "check": "BR references valid", "passed": {n}, "warnings": {n}, "errors": {n}, "status": "PASS|FAIL" },
1149
+ { "check": "Permission path format", "passed": {n}, "warnings": {n}, "errors": {n}, "status": "PASS|FAIL" }
1150
+ ],
1151
+ conventionChecks: [
1152
+ { "check": "ID naming with module prefix", "status": "PASS|FAIL", "details": "..." },
1153
+ { "check": "Entity names PascalCase", "status": "PASS|FAIL", "details": "..." }
1154
+ ],
1155
+ semanticChecks: [
1156
+ { "check": "orphan-permissions", "module": "{currentModule}", "status": "PASS|WARNING|ERROR", "details": "...", "autoFixed": false },
1157
+ { "check": "uc-sans-fr", "module": "{currentModule}", "status": "PASS|WARNING|ERROR", "details": "...", "autoFixed": false },
1158
+ { "check": "missing-wireframes", "module": "{currentModule}", "status": "PASS|WARNING|ERROR", "details": "...", "autoFixed": false }
1159
+ ],
1160
+ warnings: ["List of non-blocking warnings"],
1161
+ decision: {
1162
+ "approved": true,
1163
+ "reason": "All checks passed",
1164
+ "approvalMode": "standard",
1165
+ "approvedBy": "Client",
1166
+ "approvedAt": "{ISO timestamp}"
1167
+ }
1168
+ }
1169
+ })
1170
+ ```
1171
+
590
1172
  ### 10. Module Summary with Roles & Permissions
591
1173
 
592
1174
  Display comprehensive summary:
@@ -635,18 +1217,45 @@ options:
635
1217
  ### 11. Write Module Feature.json
636
1218
 
637
1219
  ```
1220
+ // Write analysis section with ALL subsections
638
1221
  ba-writer.enrichSection({
639
1222
  featureId: {module_feature_id},
640
- section: "specification",
641
- data: { ...all specification sections... }
1223
+ section: "analysis",
1224
+ data: {
1225
+ objectives: [{id, objective, metric, target}], // from 6a
1226
+ entities: [{name, description, attributes, relationships}], // from 6b — SCHEMA FORMAT
1227
+ businessRules: [{id, name, category, statement, priority, conditions, examples, testability}], // from 7 — SCHEMA FORMAT
1228
+ processFlow: {entryPoints, mainFlow, decisionPoints, alternativeFlows}, // from 6c
1229
+ dataLifecycle: {retentionPeriod, archiveStrategy, gdprCompliance, states} // from 6d
1230
+ }
642
1231
  })
643
1232
 
1233
+ // Write specification section with ALL subsections
644
1234
  ba-writer.enrichSection({
645
1235
  featureId: {module_feature_id},
646
- section: "analysis",
647
- data: { entities, businessRules, processFlow }
1236
+ section: "specification",
1237
+ data: {
1238
+ actors: [{role, description, permissions}], // 8a
1239
+ useCases: [{id, name, primaryActor, permission, mainScenario, linkedRules}], // 8b
1240
+ functionalRequirements: [{id, statement, priority, linkedRules, linkedUseCases, acceptanceCriteria}], // 8c
1241
+ permissionMatrix: {permissions: [], roleAssignments: []}, // 8d
1242
+ navigation: {entries: []}, // 8e
1243
+ seedDataCore: {navigationModules, navigationTranslations, permissions, rolePermissions, permissionConstants}, // 8f
1244
+ gherkinScenarios: [{feature, scenarios: [{name, tags, given, when, then}]}], // 8g
1245
+ validations: [{entity, field, rules, errorMessageKey}], // 8h
1246
+ messages: [{code, type, title, message, i18nKey}], // 8i
1247
+ lifeCycles: [{entity, field, initialState, states: [{id, displayName, color, allowedTransitions, isTerminal}], transitions}], // 8j
1248
+ apiEndpoints: [{method, path, permission, requestDto, responseDto, description}], // 8k
1249
+ i18nKeys: {...}, // 8l
1250
+ sections: [{code, labels, route, icon, permission, wireframe, useCases, businessRules, resources}], // from 3a-bis
1251
+ dashboards: [{code, title, kpis, filters, refreshMode}], // from 3d
1252
+ uiWireframes: [{screen, section, mockup, elements, actions, componentMapping, layout}] // from 3b
1253
+ }
648
1254
  })
649
1255
 
1256
+ // Write validation results from step 9
1257
+ // (Already written in step 9e above)
1258
+
650
1259
  ba-writer.updateStatus({module_feature_id}, "specified")
651
1260
 
652
1261
  // Update master