@atlashub/smartstack-cli 2.7.0 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlashub/smartstack-cli",
3
- "version": "2.7.0",
3
+ "version": "2.7.2",
4
4
  "description": "SmartStack Claude Code automation toolkit - GitFlow, APEX, EF Core migrations, prompts and more",
5
5
  "author": {
6
6
  "name": "SmartStack",
@@ -83,7 +83,7 @@
83
83
  "cli-table3": "^0.6.3",
84
84
  "commander": "^12.0.0",
85
85
  "fs-extra": "^11.2.0",
86
- "glob": "^11.0.0",
86
+ "glob": "^13.0.1",
87
87
  "handlebars": "^4.7.8",
88
88
  "inquirer": "^9.2.12",
89
89
  "jsonwebtoken": "^9.0.3",
@@ -34,6 +34,7 @@ Create an initial feature.json with metadata and draft status.
34
34
  - If scope = "application": `docs/business/{app}/business-analyse/v1.0/`
35
35
  - If scope = "module": `docs/business/{app}/{module}/business-analyse/v1.0/`
36
36
  4. Generate initial feature.json with:
37
+ - **`$schema`**: relative path to the deployed schema file (MANDATORY — see $schema rules below)
37
38
  - id: FEAT-NNN (from config)
38
39
  - version: "1.0"
39
40
  - status: "draft"
@@ -221,6 +222,143 @@ Perform these structural checks before every write:
221
222
  - `metadata.workflow` must exist with mode, moduleOrder, currentModuleIndex
222
223
  - Each module in `modules[]` must have: code, description, status
223
224
 
225
+ ## Structural Schema Enforcement (MANDATORY)
226
+
227
+ > **Before EVERY write**, validate field names against the expected schema structure below. REJECT writes containing FORBIDDEN fields. AUTO-MAP known mismatches when possible.
228
+
229
+ ### Module-Level Sections
230
+
231
+ **analysis.entities[]** — REQUIRED fields: `name`, `description`, `attributes[]`, `relationships[]`
232
+ - attributes[]: REQUIRED `name`, `description`, `required` | OPTIONAL `unique`, `validation`
233
+ - relationships[]: REQUIRED `target`, `type`, `description`
234
+ - FORBIDDEN: `type` in attributes (use `description`), `values` (use `validation`), `rules` (use `validation`)
235
+
236
+ **analysis.businessRules[]** — REQUIRED: `id`, `name`, `category`, `statement`, `priority`
237
+ - OPTIONAL: `conditions[]`, `examples[]`, `testability`
238
+ - category values: `validation`, `calculation`, `workflow`, `security`, `data` (lowercase only)
239
+ - FORBIDDEN: `rule` (use `name`+`statement`), `condition` singular (use `conditions[]`), `action` (use `statement` with IF/THEN/ELSE)
240
+ - AUTO-MAP: `rule` → split into `name` (short) + `statement` (IF/THEN)
241
+
242
+ **analysis.objectives[]** — REQUIRED: `id`, `description`, `measurable`
243
+
244
+ **analysis.processFlow** — REQUIRED: `entryPoints[]`, `mainFlow[]`, `decisionPoints[]`
245
+ - FORBIDDEN: `lifecycle` (that goes in specification.lifeCycles), flat step arrays
246
+
247
+ **analysis.dataLifecycle** — REQUIRED: `retention`, `archival`, `deletion`, `gdprRelevant`
248
+
249
+ **specification.useCases[]** — REQUIRED: `id`, `name`, `primaryActor`, `permission`, `preconditions[]`, `postconditions[]`, `mainScenario[]`
250
+ - OPTIONAL: `alternativeScenarios[]`, `errorScenarios[]`, `linkedRules[]`
251
+ - mainScenario[]: array of strings "1. Step description"
252
+ - FORBIDDEN: `actor` (use `primaryActor`), `linkedBRs` (use `linkedRules`), `linkedFRs` (remove), `scenario` (use `mainScenario`)
253
+ - AUTO-MAP: `actor` → `primaryActor`, `linkedBRs` → `linkedRules`
254
+
255
+ **specification.functionalRequirements[]** — REQUIRED: `id`, `statement`, `priority`, `linkedUseCases[]`
256
+ - OPTIONAL: `linkedRules[]`, `acceptanceCriteria[]`
257
+ - priority values: `must`, `should`, `could`
258
+ - FORBIDDEN: `name` (use `statement`), `description` (use `statement`), `linkedUCs` (use `linkedUseCases`), `linkedBRs` (use `linkedRules`)
259
+ - AUTO-MAP: `name`/`description` → `statement`, `linkedUCs` → `linkedUseCases`, `linkedBRs` → `linkedRules`
260
+
261
+ **specification.permissionMatrix** — REQUIRED shape: `{permissions[], roleAssignments[]}`
262
+ - permissions[]: `{path, action, description}`
263
+ - roleAssignments[]: `{role, permissions[]}`
264
+ - FORBIDDEN: flat array with `resource`/`roles` fields, top-level `roles` key
265
+
266
+ **specification.sections[]** — REQUIRED: `code`, `title`, `type`, `resources[]`, `wireframe`
267
+ - resources[]: REQUIRED `code`, `type`, `entity`, `permission` | OPTIONAL `columnDefs[]`, `rowActions[]`, `defaultSort`, `defaultPageSize`, `emptyState`, `fields[]`, `formLayout`
268
+
269
+ **specification.uiWireframes[]** — REQUIRED: `screen`, `section`, `mockup`, `componentMapping[]`, `layout`
270
+ - componentMapping[]: `{wireframeElement, reactComponent}`
271
+ - layout: `{type, regions[]}` where regions[]: `{id, position, span?, components[]}`
272
+ - FORBIDDEN: wireframes without `layout` object
273
+
274
+ **specification.lifeCycles[]** — REQUIRED: `entity`, `field`, `initialState`, `states[]`, `transitions[]`
275
+ - states[]: REQUIRED `{id, displayName, color, allowedTransitions[], isTerminal}`
276
+ - transitions[]: REQUIRED `{from, to, action, label, permission}` | OPTIONAL `guards[]`, `effects[]`, `confirm`
277
+ - FORBIDDEN: flat string arrays for states (e.g., `["Active", "Inactive"]`), `terminalStates` as separate array
278
+
279
+ **specification.seedDataCore** — REQUIRED 5 arrays: `navigationModules[]`, `navigationTranslations[]`, `permissions[]`, `rolePermissions[]`, `permissionConstants[]`
280
+ - navigationModules[]: `{code, label, icon, route, parentCode, sort}`
281
+ - navigationTranslations[]: `{moduleCode, language, label}` (4 languages: fr, en, nl, de)
282
+ - permissions[]: `{path, action, description}`
283
+ - rolePermissions[]: `{role, permissionPath}`
284
+ - permissionConstants[]: `{constantName, path}`
285
+ - FORBIDDEN: flat object, comma-separated strings, singular constants
286
+
287
+ **specification.gherkinScenarios** — REQUIRED shape: `{feature, scenarios[]}`
288
+ - scenarios[]: `{name, tags[], given[], when[], then[]}`
289
+ - FORBIDDEN: flat array of scenario objects without wrapping `feature`
290
+
291
+ **specification.validations[]** — REQUIRED: `entity`, `field`, `rule`, `errorMessageKey`
292
+ - FORBIDDEN: missing `entity`, missing `errorMessageKey`
293
+
294
+ **specification.messages[]** — REQUIRED: `code`, `type`, `title`, `i18nKey`
295
+ - type values: `success`, `error`, `warning`, `info`
296
+ - FORBIDDEN: missing `title`, missing `i18nKey`
297
+
298
+ **specification.apiEndpoints[]** — REQUIRED: `method`, `path`, `description`, `permission`, `request`, `response`
299
+
300
+ **specification.navigation** — REQUIRED: `entries[]` where each: `{code, label, icon, route, parentCode, sort}`
301
+
302
+ **specification.i18nKeys[]** — REQUIRED: `key`, `fr`, `en`, `nl`, `de`
303
+
304
+ **validation** — REQUIRED: `completenessChecks[]`, `consistencyChecks[]`, `semanticChecks[]`, `decision`
305
+ - decision: `{approved, reason, checkedAt}`
306
+ - semanticChecks[]: `{check, module?, status, details, autoFixed}`
307
+ - status values: `PASS`, `WARNING`, `ERROR`
308
+
309
+ **handoff** — REQUIRED: `complexity`, `filesToCreate`, `brToCodeMapping[]`, `apiEndpointSummary[]`, `prdFile`, `totalFiles`, `totalTasks`, `handedOffAt`
310
+ - filesToCreate: REQUIRED 7 categories: `domain[]`, `application[]`, `infrastructure[]`, `api[]`, `frontend[]`, `seedData[]`, `tests[]`
311
+ - brToCodeMapping[]: `{ruleId, files[], implementation}`
312
+ - apiEndpointSummary[]: `{method, path, permission, linkedUC}`
313
+
314
+ ### Application-Level Sections
315
+
316
+ **cadrage.stakeholders[]** — REQUIRED: `role`, `function`, `involvement`, `tasks[]`
317
+ - OPTIONAL: `frequency`, `painPoints[]`
318
+ - involvement values: `approver`, `decision-maker`, `consulted`, `informed`, `end-user`
319
+ - FORBIDDEN: `expertise`, `systemRole`, `description` (use `function`)
320
+
321
+ **cadrage.applicationRoles[]** — REQUIRED: `role`, `level`, `permissionPattern`
322
+ - OPTIONAL: `description`
323
+ - level values: `admin`, `manager`, `contributor`, `viewer`
324
+ - FORBIDDEN: `permissions` array (use `permissionPattern` string), `isDefault`
325
+
326
+ **cadrage.risks[]** — REQUIRED: `id`, `type`, `description`, `mitigation`
327
+ - OPTIONAL: `probability`, `impact`, `priority`
328
+ - id pattern: `RISK-NNN`
329
+ - type values: `business`, `technical`, `organizational`
330
+ - FORBIDDEN: `risk` as field name (use `description`), `severity` (use `priority`)
331
+
332
+ **cadrage.acceptanceCriteria[]** — REQUIRED: `id`, `criterion`, `validated`
333
+ - id pattern: `AC-NNN`
334
+
335
+ **cadrage.coverageMatrix[]** — REQUIRED: `item`, `category`, `module`
336
+ - OPTIONAL: `ucRef`, `notes`
337
+ - category values: `mustHave`, `shouldHave`, `couldHave`, `outOfScope`, `implicit` (camelCase)
338
+ - FORBIDDEN: `id` (no ID field), `feature` (use `item`), `priority` (use `category`)
339
+
340
+ **cadrage.codebaseContext** — MUST be a string, NOT an object
341
+
342
+ **modules[]** — REQUIRED: `code`, `description`, `featureType`, `dependencies[]`, `dependents[]`, `status`, `priority`, `sortOrder`, `entities[]`, `estimatedComplexity`
343
+ - OPTIONAL: `featureJsonPath`
344
+ - FORBIDDEN: missing `dependencies`/`dependents`/`sortOrder`
345
+
346
+ **consolidation** — REQUIRED: `crossModuleInteractions[]`, `sharedEntities[]`, `permissionCoherence`, `e2eFlows[]`, `globalRiskAssessment[]`, `semanticChecks[]`, `decision`
347
+ - crossModuleInteractions[]: `{fromModule, toModule, interactionType, description, entities[]}`
348
+ - sharedEntities[]: `{entity, ownerModule, referencedBy[], sharedFields[]}`
349
+ - decision: `{approved, reason, approvedBy, approvedAt}`
350
+ - FORBIDDEN: nested `{fkReferences, sharedEntities, events}` in crossModuleInteractions, `clientApproval` string
351
+
352
+ ### Enforcement Process
353
+
354
+ On EVERY `enrichSection()` call:
355
+ 1. **BEFORE WRITE:** Scan incoming data keys against the schema above
356
+ 2. **DETECT FORBIDDEN:** If any FORBIDDEN field found → attempt AUTO-MAP first
357
+ 3. **AUTO-MAP:** Rename known mismatches (e.g., `actor` → `primaryActor`, `rule` → `name`+`statement`)
358
+ 4. **REJECT:** If FORBIDDEN field found with no AUTO-MAP rule → BLOCK write, return error listing violations
359
+ 5. **VALIDATE REQUIRED:** If REQUIRED fields missing → BLOCK write, return error listing missing fields
360
+ 6. **LOG:** Record all auto-mappings and rejections in changelog[]
361
+
224
362
  ## Directory Structure
225
363
 
226
364
  ```
@@ -305,10 +443,31 @@ Before EVERY enrichSection() call for specification or handoff sections, validat
305
443
  - Block transitions that violate status workflow
306
444
  - Report missing featureId clearly
307
445
 
446
+ ## $schema Reference Rules (MANDATORY)
447
+
448
+ > **Every feature.json MUST include a `$schema` field** pointing to the deployed schema file via relative path.
449
+ > Schemas are deployed by step-00-init to: `docs/business/{app}/business-analyse/schemas/`
450
+
451
+ **$schema paths by scope:**
452
+
453
+ | Scope | Feature.json location | $schema value |
454
+ |-------|----------------------|---------------|
455
+ | application | `docs/business/{app}/business-analyse/v1.0/feature.json` | `"../schemas/application-schema.json"` |
456
+ | module | `docs/business/{app}/{module}/business-analyse/v1.0/feature.json` | `"../../../business-analyse/schemas/feature-schema.json"` |
457
+
458
+ **Rules:**
459
+ - `$schema` is ALWAYS the FIRST field in feature.json (before `id`)
460
+ - Path is RELATIVE from the feature.json file to the schemas directory
461
+ - For application scope: go up 1 level (v1.0/) → into schemas/
462
+ - For module scope: go up 3 levels (v1.0/ → business-analyse/ → {module}/) → into business-analyse/schemas/
463
+ - If schemas directory not found → WARNING (schemas may not have been deployed by step-00)
464
+
308
465
  ## Example Feature.json Structure
309
466
 
467
+ **Module-level:**
310
468
  ```json
311
469
  {
470
+ "$schema": "../../../business-analyse/schemas/feature-schema.json",
312
471
  "id": "FEAT-001",
313
472
  "version": "1.0",
314
473
  "status": "draft",
@@ -333,18 +492,28 @@ Before EVERY enrichSection() call for specification or handoff sections, validat
333
492
  }
334
493
  },
335
494
  "discovery": {},
336
- "analysis": {
337
- "businessRules": []
338
- },
339
- "specification": {
340
- "useCases": [],
341
- "functionalRequirements": [],
342
- "entities": []
343
- },
344
- "validation": {
345
- "testCases": []
346
- },
495
+ "analysis": {},
496
+ "specification": {},
497
+ "validation": {},
347
498
  "handoff": {},
348
499
  "suggestions": []
349
500
  }
350
501
  ```
502
+
503
+ **Application-level:**
504
+ ```json
505
+ {
506
+ "$schema": "../schemas/application-schema.json",
507
+ "id": "FEAT-001",
508
+ "version": "1.0",
509
+ "status": "draft",
510
+ "scope": "application",
511
+ "metadata": { "..." },
512
+ "cadrage": {},
513
+ "modules": [],
514
+ "dependencyGraph": {},
515
+ "consolidation": {},
516
+ "suggestions": [],
517
+ "changelog": []
518
+ }
519
+ ```
@@ -37,7 +37,8 @@ All BA outputs are stored in **two levels** of feature.json, enriched progressiv
37
37
 
38
38
  ### Application-Level (Master)
39
39
  **Path:** `docs/business/{app}/business-analyse/v{X.Y}/feature.json`
40
- **Schema:** `schemas/application-schema.json`
40
+ **Schema:** `docs/business/{app}/business-analyse/schemas/application-schema.json` (deployed to project by step-00)
41
+ **$schema:** `"../schemas/application-schema.json"` (relative in feature.json)
41
42
 
42
43
  | Step | Section enriched | Status after |
43
44
  |------|-----------------|--------------|
@@ -50,7 +51,8 @@ All BA outputs are stored in **two levels** of feature.json, enriched progressiv
50
51
 
51
52
  ### Module-Level (Per Module)
52
53
  **Path:** `docs/business/{app}/{module}/business-analyse/v{X.Y}/feature.json`
53
- **Schema:** `schemas/feature-schema.json`
54
+ **Schema:** `docs/business/{app}/business-analyse/schemas/feature-schema.json` (deployed to project by step-00)
55
+ **$schema:** `"../../../business-analyse/schemas/feature-schema.json"` (relative in feature.json)
54
56
 
55
57
  | Step | Section enriched | Status after |
56
58
  |------|-----------------|--------------|
@@ -64,7 +66,7 @@ All BA outputs are stored in **two levels** of feature.json, enriched progressiv
64
66
  - **ba-writer**: Writes/updates feature.json (create, enrichSection, updateStatus, createVersion, createApplicationFeature, advanceModuleLoop)
65
67
  - **ba-reader**: Reads feature.json (findFeature, readSection, answerQuestion, getSummaryForSkill, readApplicationContext, getCompletedModulesSummary)
66
68
 
67
- **Schemas:** `schemas/application-schema.json` (master) + `schemas/feature-schema.json` (module)
69
+ **Schemas:** Deployed to project at `docs/business/{app}/business-analyse/schemas/` (9 files). Source: `schemas/` in skill directory. Every feature.json includes `$schema` relative reference.
68
70
 
69
71
  ---
70
72
 
@@ -324,12 +326,24 @@ docs/
324
326
  ├── business/
325
327
  │ └── {application}/
326
328
  │ ├── business-analyse/
329
+ │ │ ├── schemas/ ← JSON SCHEMAS (deployed by step-00)
330
+ │ │ │ ├── feature-schema.json
331
+ │ │ │ ├── application-schema.json
332
+ │ │ │ ├── sections/
333
+ │ │ │ │ ├── analysis-schema.json
334
+ │ │ │ │ ├── discovery-schema.json
335
+ │ │ │ │ ├── handoff-schema.json
336
+ │ │ │ │ ├── metadata-schema.json
337
+ │ │ │ │ ├── specification-schema.json
338
+ │ │ │ │ └── validation-schema.json
339
+ │ │ │ └── shared/
340
+ │ │ │ └── common-defs.json
327
341
  │ │ └── v1.0/
328
- │ │ └── feature.json ← APPLICATION master
342
+ │ │ └── feature.json ← APPLICATION master ($schema: ../schemas/application-schema.json)
329
343
  │ ├── {module1}/
330
344
  │ │ └── business-analyse/
331
345
  │ │ └── v1.0/
332
- │ │ └── feature.json ← MODULE detail
346
+ │ │ └── feature.json ← MODULE detail ($schema: ../../../business-analyse/schemas/feature-schema.json)
333
347
  │ └── {module2}/
334
348
  │ └── business-analyse/
335
349
  │ └── v1.0/
@@ -315,12 +315,14 @@
315
315
  },
316
316
  "lifeCycles": {
317
317
  "type": "array",
318
- "description": "Per-entity state machines for entities with Status fields",
318
+ "description": "Per-entity state machines for entities with Status fields. Convention depth: states + allowedTransitions only. Full depth: + transitions with guards, permissions, effects.",
319
319
  "items": {
320
320
  "type": "object",
321
321
  "required": ["entity", "states"],
322
322
  "properties": {
323
323
  "entity": { "type": "string" },
324
+ "field": { "type": "string", "default": "status", "description": "Entity field that holds the state" },
325
+ "initialState": { "type": "string", "description": "State assigned on entity creation" },
324
326
  "states": {
325
327
  "type": "array",
326
328
  "items": {
@@ -330,10 +332,50 @@
330
332
  "id": { "type": "string" },
331
333
  "displayName": { "type": "string" },
332
334
  "description": { "type": "string" },
335
+ "color": { "type": "string", "enum": ["gray", "blue", "green", "yellow", "orange", "red", "purple"], "description": "Badge color for UI rendering" },
333
336
  "allowedTransitions": { "type": "array", "items": { "type": "string" } },
334
337
  "isTerminal": { "type": "boolean", "default": false }
335
338
  }
336
339
  }
340
+ },
341
+ "transitions": {
342
+ "type": "array",
343
+ "description": "Detailed transition definitions (full depth). Links actions to permissions, guards (BR), and side effects.",
344
+ "items": {
345
+ "type": "object",
346
+ "required": ["from", "to", "action"],
347
+ "properties": {
348
+ "from": { "type": "string", "description": "Source state id" },
349
+ "to": { "type": "string", "description": "Target state id" },
350
+ "action": { "type": "string", "description": "Action verb (submit, approve, reject, cancel, archive)" },
351
+ "label": {
352
+ "type": "object",
353
+ "description": "i18n action label for UI button",
354
+ "properties": {
355
+ "fr": { "type": "string" },
356
+ "en": { "type": "string" },
357
+ "it": { "type": "string" },
358
+ "de": { "type": "string" }
359
+ }
360
+ },
361
+ "permission": { "type": "string", "description": "Required permission path for this transition" },
362
+ "guards": { "type": "array", "items": { "type": "string" }, "description": "BR-XXX references that must pass before transition" },
363
+ "effects": {
364
+ "type": "array",
365
+ "description": "Side effects triggered on successful transition",
366
+ "items": {
367
+ "type": "object",
368
+ "required": ["type"],
369
+ "properties": {
370
+ "type": { "type": "string", "enum": ["notification", "email", "webhook", "field-update"], "description": "Effect type" },
371
+ "target": { "type": "string", "description": "Target role, user field, or endpoint" },
372
+ "template": { "type": "string", "description": "Notification/email template code" }
373
+ }
374
+ }
375
+ },
376
+ "confirm": { "type": "boolean", "default": false, "description": "Require user confirmation dialog before transition" }
377
+ }
378
+ }
337
379
  }
338
380
  }
339
381
  }
@@ -69,7 +69,31 @@
69
69
  "entity": { "type": "string", "description": "Primary entity this resource displays/edits" },
70
70
  "parentEntity": { "type": "string", "description": "Parent entity for child tables (e.g., RepairPart parent=Repair)" },
71
71
  "permission": { "type": "string", "description": "Permission required for this resource" },
72
- "columns": { "type": "array", "items": { "type": "string" }, "description": "For SmartTable: visible columns" },
72
+ "columns": { "type": "array", "items": { "type": "string" }, "description": "For SmartTable: visible column names (convention depth). Use columnDefs for full depth." },
73
+ "columnDefs": {
74
+ "type": "array",
75
+ "description": "For SmartTable: typed column definitions (full depth). Overrides columns[] when present.",
76
+ "items": {
77
+ "type": "object",
78
+ "required": ["field"],
79
+ "properties": {
80
+ "field": { "type": "string", "description": "Entity attribute path (e.g., code, customer.name)" },
81
+ "label": {
82
+ "type": "object",
83
+ "description": "i18n column header (auto-inferred from entity attribute if omitted)",
84
+ "properties": { "fr": { "type": "string" }, "en": { "type": "string" }, "it": { "type": "string" }, "de": { "type": "string" } }
85
+ },
86
+ "format": { "type": "string", "enum": ["text", "number", "currency", "percent", "date", "date-relative", "badge", "boolean", "link"], "description": "Display format" },
87
+ "sortable": { "type": "boolean", "default": true },
88
+ "filterable": { "type": "boolean", "default": false },
89
+ "width": { "type": "integer", "description": "Column width in pixels (hint)" },
90
+ "clickAction": { "type": "string", "description": "Action on cell click (e.g., navigate:detail)" },
91
+ "colorMap": { "type": "string", "description": "For badge format: reference to lifeCycles (e.g., stateMachine:Repair) or inline object" },
92
+ "aggregation": { "type": "string", "enum": ["sum", "avg", "count", "min", "max"], "description": "Footer aggregation" },
93
+ "hidden": { "type": "boolean", "default": false, "description": "Hidden by default (user can show via column picker)" }
94
+ }
95
+ }
96
+ },
73
97
  "fields": {
74
98
  "type": "array",
75
99
  "description": "For SmartForm: form fields",
@@ -81,12 +105,81 @@
81
105
  "component": { "type": "string", "enum": ["Input", "TextArea", "Select", "MultiSelect", "DatePicker", "DateRangePicker", "NumberInput", "Toggle", "EntitySelect", "FileUpload", "RichText", "ColorPicker"] },
82
106
  "source": { "type": "string", "description": "Lookup table entity for Select/MultiSelect" },
83
107
  "required": { "type": "boolean" },
84
- "validation": { "type": "string" }
108
+ "validation": { "type": "string" },
109
+ "default": { "type": ["string", "number", "boolean", "null"], "description": "Default value" },
110
+ "visibleWhen": { "type": "object", "description": "Conditional visibility: { field: value } or { field: [values] }", "additionalProperties": true },
111
+ "computedValue": { "type": "string", "description": "Formula for auto-calculated fields (e.g., SUM(parts.unitCost * parts.quantity))" },
112
+ "readOnly": { "type": "boolean", "default": false, "description": "Read-only computed field" },
113
+ "helpText": { "type": "string", "description": "Tooltip/help text for the field" }
114
+ }
115
+ }
116
+ },
117
+ "actions": { "type": "array", "items": { "type": "string" }, "description": "Row/item actions - simple list (convention depth). Use rowActions for full depth." },
118
+ "rowActions": {
119
+ "type": "array",
120
+ "description": "Conditional row actions (full depth). Overrides actions[] when present.",
121
+ "items": {
122
+ "type": "object",
123
+ "required": ["action"],
124
+ "properties": {
125
+ "action": { "type": "string", "description": "Action code (view, edit, delete, submit, approve)" },
126
+ "icon": { "type": "string", "description": "Lucide icon name" },
127
+ "permission": { "type": "string", "description": "Required permission (relative: read, update, delete)" },
128
+ "showWhen": { "type": "object", "description": "Show only when entity field matches value(s): { status: [\"draft\"] }", "additionalProperties": true },
129
+ "confirm": {
130
+ "oneOf": [
131
+ { "type": "boolean" },
132
+ { "type": "object", "properties": { "fr": { "type": "string" }, "en": { "type": "string" }, "it": { "type": "string" }, "de": { "type": "string" } }, "description": "i18n confirmation message" }
133
+ ],
134
+ "description": "Require confirmation dialog (true for default message, or i18n object)"
135
+ }
85
136
  }
86
137
  }
87
138
  },
88
- "actions": { "type": "array", "items": { "type": "string" }, "description": "Row/item actions (view, edit, delete, etc.)" },
89
139
  "filters": { "type": "array", "items": { "type": "string" }, "description": "Available filter fields" },
140
+ "defaultSort": {
141
+ "type": "object",
142
+ "description": "Default sort configuration",
143
+ "properties": {
144
+ "field": { "type": "string" },
145
+ "direction": { "type": "string", "enum": ["asc", "desc"], "default": "desc" }
146
+ }
147
+ },
148
+ "defaultPageSize": { "type": "integer", "default": 20, "description": "Default rows per page" },
149
+ "emptyState": {
150
+ "type": "object",
151
+ "description": "Empty state display when no data",
152
+ "properties": {
153
+ "icon": { "type": "string", "description": "Lucide icon name" },
154
+ "message": {
155
+ "type": "object",
156
+ "properties": { "fr": { "type": "string" }, "en": { "type": "string" }, "it": { "type": "string" }, "de": { "type": "string" } }
157
+ },
158
+ "createAction": { "type": "boolean", "default": false, "description": "Show a create button in empty state" }
159
+ }
160
+ },
161
+ "formLayout": {
162
+ "type": "object",
163
+ "description": "For SmartForm: form layout structure (tabs or sections)",
164
+ "properties": {
165
+ "type": { "type": "string", "enum": ["flat", "tabs", "sections"], "default": "flat" },
166
+ "tabs": {
167
+ "type": "array",
168
+ "items": {
169
+ "type": "object",
170
+ "required": ["code", "label", "fields"],
171
+ "properties": {
172
+ "code": { "type": "string" },
173
+ "label": {
174
+ "type": "object",
175
+ "properties": { "fr": { "type": "string" }, "en": { "type": "string" }, "it": { "type": "string" }, "de": { "type": "string" } }
176
+ },
177
+ "fields": { "type": "array", "items": { "type": "string" }, "description": "Field names in this tab" }
178
+ }
179
+ }
180
+ }
181
+ }
182
+ },
90
183
  "kpis": { "type": "array", "items": { "type": "string" }, "description": "For KpiPanel: entity fields to display as KPIs" },
91
184
  "chartType": { "type": "string", "enum": ["bar", "line", "pie", "area", "donut", "stacked-bar"], "description": "For Chart resource" },
92
185
  "dataSource": { "type": "string", "description": "API endpoint or entity for data" }
@@ -349,6 +349,53 @@ docs_dir: "docs/business/{app}/{module}/business-analyse/v{version}"
349
349
  output_dir: same as docs_dir
350
350
  ```
351
351
 
352
+ ## Step 9-bis: Deploy JSON Schemas to Project (MANDATORY)
353
+
354
+ > **The JSON Schemas MUST be present in the project alongside the generated feature.json files.**
355
+ > Without schemas, feature.json files cannot be validated and have no structural reference.
356
+
357
+ **Check if schemas already deployed:**
358
+ ```
359
+ IF EXISTS docs/business/{app}/business-analyse/schemas/feature-schema.json:
360
+ Skip deployment (schemas already present)
361
+ ELSE:
362
+ Deploy schemas
363
+ ```
364
+
365
+ **Deploy all schema files from skill directory to project:**
366
+
367
+ Source: `schemas/` (relative to skill root = `~/.claude/skills/business-analyse/schemas/`)
368
+ Destination: `docs/business/{app}/business-analyse/schemas/`
369
+
370
+ ```
371
+ Read and Write each file (preserving directory structure):
372
+
373
+ docs/business/{app}/business-analyse/schemas/
374
+ ├── feature-schema.json ← from schemas/feature-schema.json
375
+ ├── application-schema.json ← from schemas/application-schema.json
376
+ ├── sections/
377
+ │ ├── metadata-schema.json ← from schemas/sections/metadata-schema.json
378
+ │ ├── discovery-schema.json ← from schemas/sections/discovery-schema.json
379
+ │ ├── analysis-schema.json ← from schemas/sections/analysis-schema.json
380
+ │ ├── specification-schema.json ← from schemas/sections/specification-schema.json
381
+ │ ├── validation-schema.json ← from schemas/sections/validation-schema.json
382
+ │ └── handoff-schema.json ← from schemas/sections/handoff-schema.json
383
+ └── shared/
384
+ └── common-defs.json ← from schemas/shared/common-defs.json
385
+ ```
386
+
387
+ **Total: 9 files to deploy.**
388
+
389
+ **Implementation:**
390
+ 1. Use Glob to find all `.json` files in `schemas/` directory (skill-relative)
391
+ 2. For each file, Read from skill directory and Write to project directory
392
+ 3. Preserve the subdirectory structure (sections/, shared/)
393
+
394
+ **Store:**
395
+ ```yaml
396
+ schemas_dir: "docs/business/{app}/business-analyse/schemas"
397
+ ```
398
+
352
399
  ## Step 10: Create Master feature.json
353
400
 
354
401
  Create the master feature document using ba-writer agent.
@@ -389,6 +436,7 @@ ba-writer.createApplicationFeature({
389
436
  **Result structure:**
390
437
  ```json
391
438
  {
439
+ "$schema": "../schemas/application-schema.json",
392
440
  "id": "{feature_id}",
393
441
  "version": "1.0",
394
442
  "status": "draft",
@@ -222,7 +222,75 @@ If a feature is in mustHave → it MUST have at least one UC in the correspondin
222
222
 
223
223
  ### 10. Write Cadrage to Feature.json
224
224
 
225
- Use ba-writer to enrich master feature.json:
225
+ Use ba-writer to enrich master feature.json. **Follow the STRUCTURE CARDS below exactly.**
226
+
227
+ > **STRUCTURE CARD: cadrage.stakeholders[]**
228
+ > ```json
229
+ > {
230
+ > "role": "Fleet Manager",
231
+ > "function": "Manages daily fleet operations",
232
+ > "involvement": "decision-maker",
233
+ > "tasks": ["Monitor vehicles", "Approve repairs", "Export reports"],
234
+ > "frequency": "Daily",
235
+ > "painPoints": ["Manual tracking in spreadsheets", "No real-time visibility"]
236
+ > }
237
+ > ```
238
+ > **MANDATORY fields:** `role`, `function`, `involvement`, `tasks`
239
+ > **involvement values:** `approver`, `decision-maker`, `consulted`, `informed`, `end-user`
240
+ > **FORBIDDEN fields:** Do NOT use `expertise`, `systemRole`, `description` (use `function` instead).
241
+
242
+ > **STRUCTURE CARD: cadrage.applicationRoles[]**
243
+ > ```json
244
+ > {
245
+ > "role": "{App} Admin",
246
+ > "description": "Full access to all modules",
247
+ > "level": "admin",
248
+ > "permissionPattern": "business.{app}.*"
249
+ > }
250
+ > ```
251
+ > **MANDATORY fields:** `role`, `level`, `permissionPattern`
252
+ > **level values:** `admin`, `manager`, `contributor`, `viewer`
253
+ > **FORBIDDEN fields:** Do NOT use `permissions` (use `permissionPattern`), `isDefault`.
254
+
255
+ > **STRUCTURE CARD: cadrage.risks[]**
256
+ > ```json
257
+ > {
258
+ > "id": "RISK-001",
259
+ > "type": "business|technical|organizational",
260
+ > "description": "CSV data may contain duplicates and errors",
261
+ > "probability": "high|medium|low",
262
+ > "impact": "high|medium|low",
263
+ > "priority": "critical|medium|low",
264
+ > "mitigation": "Data cleaning phase before import, detailed error reports"
265
+ > }
266
+ > ```
267
+ > **MANDATORY fields:** `id` (pattern: RISK-NNN), `type`, `description`, `mitigation`
268
+ > **FORBIDDEN fields:** Do NOT use `risk` (name), `severity`. Use `id` + `description` + `priority`.
269
+
270
+ > **STRUCTURE CARD: cadrage.acceptanceCriteria[]**
271
+ > ```json
272
+ > { "id": "AC-001", "criterion": "All must-have features delivered and tested", "validated": false }
273
+ > ```
274
+ > **MANDATORY:** This section must NOT be omitted.
275
+
276
+ > **STRUCTURE CARD: cadrage.coverageMatrix[]**
277
+ > ```json
278
+ > {
279
+ > "item": "User management with CRUD",
280
+ > "category": "mustHave|shouldHave|couldHave|outOfScope|implicit",
281
+ > "module": "Users",
282
+ > "ucRef": "UC-UM-001",
283
+ > "notes": "Foundation module, must be implemented first"
284
+ > }
285
+ > ```
286
+ > **MANDATORY fields:** `item`, `category`, `module`
287
+ > **category values:** `mustHave`, `shouldHave`, `couldHave`, `outOfScope`, `implicit` (camelCase)
288
+ > **FORBIDDEN fields:** Do NOT use `id`, `feature`, `priority`. Use `item` + `category`.
289
+
290
+ > **STRUCTURE CARD: cadrage.codebaseContext** — Must be a string, NOT an object.
291
+ > ```json
292
+ > "codebaseContext": "Greenfield project, no existing entities. SmartStack 2.1.0 with Extensions DbContext."
293
+ > ```
226
294
 
227
295
  ```
228
296
  ba-writer.enrichSection({
@@ -233,18 +301,18 @@ ba-writer.enrichSection({
233
301
  asIs: {Q1.2 answer},
234
302
  toBe: {Q1.3 answer},
235
303
  trigger: {Q1.4 answer},
236
- stakeholders: [{mapped from Q2.x answers}],
304
+ stakeholders: [{mapped from Q2.x — use STRUCTURE CARD format}],
237
305
  globalScope: {
238
306
  mustHave: [{from Q3.x}],
239
307
  shouldHave: [{from Q3.x}],
240
308
  couldHave: [{from Q3.x}],
241
309
  outOfScope: [{from Q3.x}]
242
310
  },
243
- applicationRoles: [{from section 6}],
244
- risks: [{from section 8}],
245
- acceptanceCriteria: [{derived from scope}],
246
- coverageMatrix: [{from section 9}],
247
- codebaseContext: {codebase_context}
311
+ applicationRoles: [{from section 6 — use STRUCTURE CARD format}],
312
+ risks: [{from section 8 — use STRUCTURE CARD format}],
313
+ acceptanceCriteria: [{derived from scope — use STRUCTURE CARD format}],
314
+ coverageMatrix: [{from section 9 — use STRUCTURE CARD format}],
315
+ codebaseContext: "{string summary of codebase findings}"
248
316
  }
249
317
  })
250
318