# JSON Schemas (step-03-specify)

## Entity Schema Format

```json
{
  "name": "Employee",
  "description": "Représente un employé de l'entreprise",
  "personRoleConfig": { "variant": "mandatory", "userFields": ["firstName", "lastName", "email"] },
  "attributes": [
    { "name": "code", "type": "string", "required": true, "unique": true, "searchable": true, "description": "Identifiant unique auto-généré" },
    { "name": "userId", "type": "string", "required": true, "unique": true, "description": "FK vers auth_Users (ASP.NET Identity — type string, NOT guid)" },
    { "name": "departmentId", "type": "guid", "required": true, "description": "Département d'affectation" },
    { "name": "hireDate", "type": "date", "required": true, "searchable": true, "description": "Date d'embauche" },
    { "name": "position", "type": "string", "searchable": true, "description": "Poste occupé" },
    { "name": "status", "type": "enum", "options": ["Active", "Inactive", "OnLeave", "Terminated"], "defaultValue": "Active", "searchable": true, "description": "Statut de l'employé" }
  ],
  "versionedAttributes": [
    { "entity": "Salary", "attributes": ["grossAmount", "netAmount", "effectiveDate", "currency"], "reason": "Historique salarial versionné" }
  ],
  "estimatedVolume": { "monthly": 50, "total2y": 1200 },
  "searchableFields": ["code", "position", "status"],
  "defaultFilters": ["status"],
  "relationships": [
    { "target": "Department", "type": "ManyToOne", "description": "Appartient à un département" },
    { "target": "Contract", "type": "OneToMany", "description": "Possède plusieurs contrats" },
    { "target": "Salary", "type": "OneToMany", "description": "Historique de salaires versionnés" }
  ]
}
```

**Attribute flags (OPTIONAL, default: false):**
- `unique: true` — attribute has uniqueness constraint (e.g., `code`, `userId`)
- `searchable: true` — attribute appears in search/filter results (e.g., `code`, `status`, `position`)
- `computed: true` — attribute value is calculated (e.g., `subtotal`, `total`). **MUST** have a corresponding `BR-CALC` rule with `formula` field

Omit flags when `false` (default). Include explicitly when `true`.

## Business Rules Schema Format

> **Source of truth:** `schemas/sections/analysis-schema.json` property `businessRules`.

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

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

**Mandatory requirements:**
- Each enum attribute MUST have a `defaultValue`
- Each bounded numeric attribute MUST have `validation.min/max`
- FK attributes to Identity (userId) MUST use type `string` (ASP.NET Identity convention)
- Each attribute marked "computed" in entities.json MUST have a rule with `category: "calculation"` and `formula` field

**Calculation rule example:**
```json
{
  "id": "BR-CALC-INV-003",
  "name": "Calcul reste à payer",
  "category": "calculation",
  "sectionCode": "detail",
  "statement": "Le reste à payer = total - montant payé",
  "severity": "blocking",
  "formula": "remainingAmount = total - paidAmount",
  "entities": ["Invoice"],
  "examples": [{ "input": "total=1000, paidAmount=300", "expected": "remainingAmount = 700" }],
  "domainSpecific": false
}
```

**MANDATORY enrichment fields (added in v2):**
- `severity` : `"blocking"` | `"warning"` | `"info"` — impact level of the rule
- `sectionCode` : section where this rule applies (e.g., `"list"`, `"approve"`)
- `examples[]` : structured as `{input: string, expected: string}` — at least 1 per rule
  ```json
  "examples": [{ "input": "debut=15/03 fin=12/03", "expected": "Erreur : date de fin avant date de debut" }]
  ```

**RECOMMENDED enrichment fields:**
- `conditions[]` : structured IF conditions — `{entity, field, operator, value}`
  ```json
  "conditions": [{ "entity": "Absence", "field": "duration", "operator": ">", "value": 3 }]
  ```
- `consequences[]` : side effects when rule fires — `{type, target, description}`
  ```json
  "consequences": [{ "type": "notification", "target": "RH Manager", "description": "Certificat medical requis" }]
  ```
- `formula` : for BR-CALC rules (e.g., `"remaining = entitled + carried - taken"`)
- `domainSpecific` : `true` if from domain research, `false` if generic CRUD validation

## Use Cases Schema Format

**CANONICAL FORMAT (MANDATORY):** The usecases.json file MUST use these exact keys:
- Root key: `"useCases"` (camelCase, NOT "usecases")
- Actor field: `"primaryActor"` (NOT "actor")
- Steps field: `"mainScenario"` (string[], NOT "steps" with objects)
- Alternatives: `"alternativeScenarios"` (object[] with `{name, steps}`, NOT "alternative" as flat string)
- This matches specification-schema.json. Deviation causes normalization overhead in 4+ downstream skills.

```json
{
  "useCases": [
    {
      "id": "UC-EMPLOYEES-001",
      "name": "Créer un employé",
      "sectionCode": "list",
      "primaryActor": "Responsable RH",
      "preconditions": ["L'utilisateur a la permission HumanResources.Employees.Create"],
      "mainScenario": [
        "L'utilisateur ouvre la page de création",
        "Il remplit les champs obligatoires (nom, département, date embauche)",
        "Il valide le formulaire",
        "Le système vérifie les règles métier (BR-VAL-EMPLOYEES-001)",
        "Le système crée l'employé et affiche la fiche"
      ],
      "alternativeScenarios": [
        {
          "name": "Données invalides",
          "steps": ["Le système affiche les erreurs de validation", "L'utilisateur corrige et re-soumet"]
        }
      ],
      "businessRules": ["BR-VAL-EMPLOYEES-001"],
      "result": "L'employé est créé avec le statut 'Actif'"
    }
  ]
}
```

**MANDATORY enrichment fields (activated in v2):**
- `postconditions[]` : effects AFTER the UC completes (schema field exists, now mandatory)
  ```json
  "postconditions": ["Absence.status = Approved", "AbsenceBalance.taken += duration", "Notification envoyee"]
  ```
- `errorScenarios[]` : error paths — MANDATORY for workflow UCs (schema field exists, now mandatory)
  ```json
  "errorScenarios": [{ "name": "Solde insuffisant", "steps": ["Systeme affiche le solde restant", "Soumission bloquee"] }]
  ```

**Minimum requirements:**
- Workflow UCs: `mainScenario[]` >= 5 steps, `errorScenarios[]` >= 1, `postconditions[]` required
- CRUD UCs: `mainScenario[]` >= 3 steps, `postconditions[]` required

## Permissions Schema Format

```json
{
  "roles": ["RH Admin", "Manager", "Employee"],
  "matrix": [
    { "role": "RH Admin", "permissions": ["Read", "Create", "Update", "Delete", "Export"] },
    { "role": "Manager", "permissions": ["Read", "Export"] },
    { "role": "Employee", "permissions": ["Read"] }
  ],
  "permissionPaths": [
    "HumanResources.Employees.Read",
    "HumanResources.Employees.Create",
    "HumanResources.Employees.Update",
    "HumanResources.Employees.Delete",
    "HumanResources.Employees.Export"
  ]
}
```

**Auto-detection rules:**
- If the cadrage mentions "export", "Excel", "CSV", or "télécharger" → automatically add `.export` permission and an export use case (UC-{PREFIX}-EXPORT)
- If the cadrage mentions "import", "importer", "upload" → automatically add `.import` permission and an import use case (UC-{PREFIX}-IMPORT)

## LifeCycle Schema Format

> Source: `specification-schema.json` `lifeCycles[]`
> **MANDATORY** for each entity with a status enum attribute.
> Generated in step-03 section F-bis. Consumed by Mermaid diagram generation (step-04) and code generation (handoff/develop).

```json
{
  "entity": "EntityName",
  "field": "status",
  "initialState": "Draft",
  "states": [
    {
      "id": "Draft",
      "displayName": "Brouillon",
      "color": "gray",
      "allowedTransitions": ["Submitted"],
      "isTerminal": false
    }
  ],
  "transitions": [
    {
      "from": "Draft",
      "to": "Submitted",
      "action": "submit",
      "permission": "App.Module.Action",
      "guards": ["BR-VAL-XXX"],
      "effects": [
        { "type": "notification", "target": "Manager", "template": "entity-submitted" },
        { "type": "field-update", "target": "Entity.field", "template": "= value" }
      ],
      "confirm": false
    }
  ]
}
```

**Generation rules:**
- Extract states from entity's status enum `options[]`
- Extract transitions from BR-WF-* rules
- Link `guards[]` to BR-VAL-* rules that must pass before transition
- Link `effects[]` to BR-NOTIF-* and BR-CALC-* triggered by the transition
- Link `permission` from permissions.json for each transition action
- Set `color` based on state semantic: gray=draft, blue=active, green=success, red=error, yellow=warning
- Set `isTerminal: true` for states with no allowed transitions
