# Canonical JSON Formats Reference

> **Purpose:** Single source of truth for all JSON file formats produced by the BA pipeline.
> **Used by:** `step-03`, `/business-analyse-design` (step-01), `/business-analyse-html`, `/business-analyse-handoff`, `/business-analyse-develop`
> **Rule:** All producers MUST write canonical format. All consumers MUST accept canonical + deprecated fallbacks.

---

## entities.json

```json
{
  "entities": [
    {
      "name": "Employee",
      "description": "...",
      "personRoleConfig": { "variant": "mandatory", "userFields": ["firstName", "lastName", "email"] },
      "attributes": [
        { "name": "code", "type": "string", "required": true, "description": "..." },
        { "name": "userId", "type": "string", "required": true, "description": "FK auth_Users (ASP.NET Identity)" }
      ],
      "versionedAttributes": [
        { "entity": "Salary", "attributes": ["grossAmount", "effectiveDate"], "reason": "..." }
      ],
      "relationships": [
        { "target": "Department", "type": "ManyToOne", "description": "..." }
      ]
    }
  ]
}
```

**Convention guards:**
- Person entities → `personRoleConfig` + `userId` (string), NO firstName/lastName/email
- Versioned data → `versionedAttributes[]`, NOT inline fields
- FK naming → always `{entity}Id` suffix
- FK to auth_Users → type `string` (ASP.NET Identity), NOT `guid`

---

## usecases.json

```json
{
  "useCases": [
    {
      "id": "UC-MODULE-001",
      "name": "Créer un employé",
      "sectionCode": "list",
      "primaryActor": "Responsable RH",
      "preconditions": ["..."],
      "mainScenario": [
        "L'utilisateur ouvre la page de création",
        "Il remplit les champs obligatoires"
      ],
      "alternativeScenarios": [
        { "name": "Données invalides", "steps": ["Le système affiche les erreurs"] }
      ],
      "businessRules": ["BR-VAL-MODULE-001"],
      "result": "L'entité est créée"
    }
  ]
}
```

| Canonical key | Deprecated alternatives | Notes |
|---------------|------------------------|-------|
| `useCases` (root) | `usecases` | camelCase is canonical |
| `primaryActor` | `actor` | |
| `mainScenario` (string[]) | `steps` (object[] or string[]) | MUST be strings, never `{step, action}` objects |
| `alternativeScenarios` (object[]) | `alternativeFlows`, `alternative` (string) | Must be `[{name, steps}]` |

---

## rules.json

```json
{
  "rules": [
    {
      "id": "BR-VAL-MODULE-001",
      "name": "Validation date",
      "category": "validation",
      "sectionCode": "list",
      "statement": "La date ne peut pas être dans le futur",
      "severity": "blocking",
      "entities": ["Employee"],
      "examples": [{ "input": "date = 2027-01-01", "expected": "Erreur : date dans le futur" }],
      "domainSpecific": false
    }
  ]
}
```

| Canonical key | Deprecated alternatives |
|---------------|------------------------|
| `rules` (root) | `businessRules` |
| `statement` | `description` |
| `id` | `name` (as identifier), `code` |
| `examples` (array of `{input, expected}`) | `example` (singular string) |
| `category` | `type` |
| `name` | `label` |

Categories: `validation`, `calculation`, `workflow`, `security`, `data`, `notification`

---

## permissions.json

```json
{
  "roles": [
    { "role": "RH Admin", "description": "..." }
  ],
  "permissionPaths": [
    "HumanResources.Employees.Read",
    "HumanResources.Employees.Create"
  ],
  "matrix": {
    "roleAssignments": [
      { "role": "RH Admin", "permissions": ["HumanResources.Employees.*"] }
    ]
  }
}
```

---

## screens.json

```json
{
  "sections": [
    {
      "sectionCode": "list",
      "sectionLabel": "Liste des employés",
      "resources": [
        {
          "code": "employees-grid",
          "type": "SmartTable",
          "label": "Grille des employés",
          "columns": [
            { "field": "code", "label": "Code", "type": "text", "sortable": true }
          ],
          "filters": [
            { "field": "status", "type": "select", "label": "Statut" }
          ],
          "actions": ["create", "export"],
          "permission": "HumanResources.Employees.Read"
        }
      ]
    }
  ]
}
```

| Canonical key | Deprecated alternatives | Notes |
|---------------|------------------------|-------|
| `sections` (root) | `screens` (flat array) | `sections[]` with `resources[]` is canonical |
| `sectionCode` | `id`, `code` | |
| `sectionLabel` | `displayName`, `label` | |
| resource `type` | `layout`, `componentType` | Must be: SmartTable, SmartForm, SmartDashboard, SmartKanban, SmartCard, SmartFilter |
| column `field` | `code`, `name`, `id`, `fieldCode` | |
| column `label` | `displayName` | |

**DEPRECATED format (do NOT produce):**
```json
{
  "screens": [
    { "screen": "employees-list", "section": "list", "componentType": "SmartTable", "columns": [...] }
  ]
}
```

---

## Consumer normalization pattern

All downstream consumers should normalize input using this priority chain:

```javascript
// usecases
const rawUCs = data.useCases || data.usecases || [];
const uc = {
  name: raw.name || raw.title || raw.id,
  actor: raw.primaryActor || raw.actor,
  steps: (raw.mainScenario || raw.steps || []).map(s =>
    typeof s === 'string' ? s : (s.action || s.description || "")
  ),
  alternatives: raw.alternativeScenarios || raw.alternativeFlows || []
};

// screens
const sections = data.sections || [];
const flatScreens = data.screens || [];
// If flat format: wrap each screen as a section with 1 resource

// columns
const col = {
  field: raw.field || raw.code || raw.name || raw.id,
  label: raw.label || raw.displayName || raw.code,
  type: raw.renderAs === "badge" ? "badge" : (raw.type || raw.dataType || "text")
};
```
