{
  "openapi": "3.1.0",
  "info": {
    "title": "API BioTrace",
    "version": "1.40.0",
    "description": "Traçabilité biologique, de la parcelle au conteneur. Document produit depuis les schémas TypeBox de packages/schemas."
  },
  "paths": {
    "/sante": {
      "get": {
        "operationId": "lireSante",
        "summary": "Vivacité du service",
        "tags": [
          "Service"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Le service répond.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "statut"
                  ],
                  "properties": {
                    "statut": {
                      "const": "ok",
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/openapi.json": {
      "get": {
        "operationId": "lireOpenApi",
        "summary": "Document OpenAPI de l'API",
        "tags": [
          "Service"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Document OpenAPI 3.1.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "properties": {}
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/jwks.json": {
      "get": {
        "operationId": "lireJwks",
        "summary": "Clé publique du jeton PowerSync",
        "tags": [
          "Synchronisation"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Jeu de clés JWKS lu par le service PowerSync.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "keys"
                  ],
                  "properties": {
                    "keys": {
                      "type": "array",
                      "items": {
                        "additionalProperties": true,
                        "type": "object",
                        "properties": {}
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/sync/commandes": {
      "post": {
        "operationId": "envoyerCommandes",
        "summary": "Envoyer un lot de 1 à 50 commandes",
        "tags": [
          "Synchronisation"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "commandes"
                ],
                "properties": {
                  "commandes": {
                    "minItems": 1,
                    "maxItems": 50,
                    "type": "array",
                    "items": {}
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Résultat de chaque commande, dans l'ordre d'envoi.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "resultats",
                    "derniere_sequence",
                    "heure_serveur",
                    "arret"
                  ],
                  "properties": {
                    "resultats": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "commande_id",
                          "issue",
                          "motifs",
                          "alertes",
                          "numero_officiel",
                          "entites",
                          "date_operation"
                        ],
                        "properties": {
                          "commande_id": {
                            "type": "string"
                          },
                          "issue": {
                            "anyOf": [
                              {
                                "const": "acceptee",
                                "type": "string"
                              },
                              {
                                "const": "acceptee_controle",
                                "type": "string"
                              },
                              {
                                "const": "rejetee",
                                "type": "string"
                              }
                            ]
                          },
                          "motifs": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "alertes": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "numero_officiel": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "entites": {
                            "additionalProperties": {
                              "type": "string"
                            },
                            "type": "object",
                            "properties": {}
                          },
                          "date_operation": {
                            "anyOf": [
                              {
                                "format": "date-time",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        }
                      }
                    },
                    "derniere_sequence": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "heure_serveur": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "arret": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "raison",
                            "attendue"
                          ],
                          "properties": {
                            "raison": {
                              "const": "sequence_attendue",
                              "type": "string"
                            },
                            "attendue": {
                              "minimum": 1,
                              "type": "integer"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Lot illisible (`lot_invalide`) ou enveloppe illisible (`enveloppe_illisible`) : rien n'est traité.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/sync/etat-appareil": {
      "get": {
        "operationId": "lireEtatAppareil",
        "summary": "État de synchronisation d'un appareil",
        "tags": [
          "Synchronisation"
        ],
        "parameters": [
          {
            "name": "appareil_id",
            "in": "query",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Dernière séquence, statut, versions minimales, heure serveur.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "appareil_id",
                    "statut",
                    "revoque_le",
                    "derniere_sequence",
                    "derniere_synchro",
                    "versions_minimales",
                    "heure_serveur"
                  ],
                  "properties": {
                    "appareil_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "revoque",
                          "type": "string"
                        },
                        {
                          "const": "remplace",
                          "type": "string"
                        }
                      ]
                    },
                    "revoque_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "derniere_sequence": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "derniere_synchro": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "versions_minimales": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "schemas"
                      ],
                      "properties": {
                        "schemas": {
                          "additionalProperties": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "courante",
                              "minimale"
                            ],
                            "properties": {
                              "courante": {
                                "minimum": 1,
                                "type": "integer"
                              },
                              "minimale": {
                                "minimum": 1,
                                "type": "integer"
                              }
                            }
                          },
                          "description": "Par type de commande.",
                          "type": "object",
                          "properties": {}
                        }
                      }
                    },
                    "heure_serveur": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Identifiant d'appareil invalide (`appareil_id_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Appareil inconnu de cet utilisateur (`appareil_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/sync/jeton": {
      "post": {
        "operationId": "emettreJetonPowerSync",
        "summary": "Jeton PowerSync de 5 minutes",
        "tags": [
          "Synchronisation"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "appareil_id"
                ],
                "properties": {
                  "appareil_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Jeton signé, limité à l'organisation de l'appareil.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "jeton",
                    "expire_le"
                  ],
                  "properties": {
                    "jeton": {
                      "type": "string"
                    },
                    "expire_le": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Identifiant d'appareil invalide (`appareil_id_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Appareil révoqué (`appareil_revoque`), ou refus d'organisation ou de droit.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Appareil inconnu de cet utilisateur (`appareil_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/permissions": {
      "get": {
        "operationId": "listerPermissions",
        "summary": "Catalogue des permissions (`permission_sets.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Permissions de commande et du back-office.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "permissions",
                    "par_module"
                  ],
                  "properties": {
                    "permissions": {
                      "description": "Permissions connues : commandes et back-office.",
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "par_module": {
                      "description": "Permissions rangées par module, avec l'état du module pour l'organisation active (AM-05). Un ensemble ne propose utilement que celles des modules actifs.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "module",
                          "actif",
                          "permissions"
                        ],
                        "properties": {
                          "module": {
                            "type": "string"
                          },
                          "actif": {
                            "type": "boolean"
                          },
                          "permissions": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/moi": {
      "get": {
        "operationId": "lireMoi",
        "summary": "Utilisateur courant, organisation active et permissions effectives",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Qui est connecté, dans quelle organisation, avec quels droits à cet instant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "utilisateur",
                    "organisation",
                    "permissions",
                    "modules",
                    "onboarding"
                  ],
                  "properties": {
                    "utilisateur": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "identifiant",
                        "nom_affiche",
                        "statut"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "identifiant": {
                          "type": "string"
                        },
                        "nom_affiche": {
                          "type": "string"
                        },
                        "statut": {
                          "type": "string"
                        }
                      }
                    },
                    "organisation": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom",
                        "langue",
                        "fuseau_horaire",
                        "devise_defaut"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom": {
                          "type": "string"
                        },
                        "langue": {
                          "type": "string"
                        },
                        "fuseau_horaire": {
                          "type": "string"
                        },
                        "devise_defaut": {
                          "type": "string"
                        }
                      }
                    },
                    "permissions": {
                      "description": "Permissions effectives à l'instant de la requête, triées, sans doublon (EC-038).",
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "modules": {
                      "description": "Modules actifs (noyau compris), et modules désactivés après avoir été actifs, en lecture seule (AM-05). Un module jamais activé est absent.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "etat"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "etat": {
                            "anyOf": [
                              {
                                "const": "actif",
                                "type": "string"
                              },
                              {
                                "const": "lecture_seule",
                                "type": "string"
                              }
                            ]
                          }
                        }
                      }
                    },
                    "onboarding": {
                      "description": "Parcours d'onboarding de la première connexion : `requis` tant que le compte n'est pas ouvert ou que le parcours est reporté ou rouvert.",
                      "type": "object",
                      "required": [
                        "requis",
                        "etat"
                      ],
                      "properties": {
                        "requis": {
                          "type": "boolean"
                        },
                        "etat": {
                          "anyOf": [
                            {
                              "const": "jamais",
                              "type": "string"
                            },
                            {
                              "const": "reporte",
                              "type": "string"
                            },
                            {
                              "const": "termine",
                              "type": "string"
                            },
                            {
                              "const": "rouvert",
                              "type": "string"
                            }
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/campagnes": {
      "get": {
        "operationId": "listerCampagnes",
        "summary": "Campagnes de l'organisation active",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "statut",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "const": "preparation",
                  "type": "string"
                },
                {
                  "const": "ouverte",
                  "type": "string"
                },
                {
                  "const": "cloturee",
                  "type": "string"
                }
              ]
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Campagnes, de l'année la plus récente à la plus ancienne, puis par code.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "campagnes"
                  ],
                  "properties": {
                    "campagnes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom",
                          "statut",
                          "annee",
                          "date_ouverture_prevue",
                          "date_cloture_prevue",
                          "date_ouverture",
                          "date_cloture",
                          "pack_version_id",
                          "modele_numerotation_version",
                          "cree_le",
                          "modifie_le",
                          "pack"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "minLength": 1,
                            "maxLength": 40,
                            "type": "string"
                          },
                          "nom": {
                            "minLength": 1,
                            "maxLength": 200,
                            "type": "string"
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "preparation",
                                "type": "string"
                              },
                              {
                                "const": "ouverte",
                                "type": "string"
                              },
                              {
                                "const": "cloturee",
                                "type": "string"
                              }
                            ]
                          },
                          "annee": {
                            "minimum": 2000,
                            "maximum": 2999,
                            "type": "integer"
                          },
                          "date_ouverture_prevue": {
                            "format": "date",
                            "type": "string"
                          },
                          "date_cloture_prevue": {
                            "format": "date",
                            "type": "string"
                          },
                          "date_ouverture": {
                            "anyOf": [
                              {
                                "format": "date",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "date_cloture": {
                            "anyOf": [
                              {
                                "format": "date",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "pack_version_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "modele_numerotation_version": {
                            "anyOf": [
                              {
                                "minimum": 1,
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "modifie_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "pack": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "code",
                              "libelle",
                              "version"
                            ],
                            "properties": {
                              "code": {
                                "type": "string"
                              },
                              "libelle": {
                                "type": "string"
                              },
                              "version": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Statut inconnu (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/produits": {
      "get": {
        "operationId": "listerProduits",
        "summary": "Produits de l'organisation active, avec leurs attributs typés",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Produits par code, attributs dans l'ordre du pack. Le schéma de chaque attribut alimente le formulaire généré.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "produits"
                  ],
                  "properties": {
                    "produits": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom_fr",
                          "nom_en",
                          "unite_code",
                          "est_matiere_premiere",
                          "matiere_premiere_liee_code",
                          "actif",
                          "pack",
                          "attributs"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom_fr": {
                            "type": "string"
                          },
                          "nom_en": {
                            "type": "string"
                          },
                          "unite_code": {
                            "type": "string"
                          },
                          "est_matiere_premiere": {
                            "type": "boolean"
                          },
                          "matiere_premiere_liee_code": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "actif": {
                            "type": "boolean"
                          },
                          "pack": {
                            "anyOf": [
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "code",
                                  "version"
                                ],
                                "properties": {
                                  "code": {
                                    "type": "string"
                                  },
                                  "version": {
                                    "type": "string"
                                  }
                                }
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "attributs": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "code",
                                "libelle_fr",
                                "libelle_en",
                                "schema",
                                "obligatoire",
                                "ordre"
                              ],
                              "properties": {
                                "code": {
                                  "type": "string"
                                },
                                "libelle_fr": {
                                  "type": "string"
                                },
                                "libelle_en": {
                                  "type": "string"
                                },
                                "schema": {
                                  "additionalProperties": true,
                                  "description": "JSON Schema de la valeur, tel que le pack le déclare.",
                                  "type": "object",
                                  "properties": {}
                                },
                                "obligatoire": {
                                  "type": "boolean"
                                },
                                "ordre": {
                                  "type": "integer"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/numerotation/apercu": {
      "get": {
        "operationId": "apercuNumero",
        "summary": "Aperçu du prochain numéro officiel, sans le réserver",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "campagne",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "produit",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "nature",
            "in": "query",
            "required": true,
            "schema": {
              "description": "Nature du numéro : matière première, réception, nettoyage, produit fini. « Vente » n'existe plus (avenant n°1). Codes à confirmer, EC-068.",
              "anyOf": [
                {
                  "const": "MP",
                  "type": "string"
                },
                {
                  "const": "REC",
                  "type": "string"
                },
                {
                  "const": "NET",
                  "type": "string"
                },
                {
                  "const": "PF",
                  "type": "string"
                }
              ]
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Le numéro que la prochaine attribution donnerait, et le modèle figé de la campagne.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "numero",
                    "rang",
                    "modele_version",
                    "segments"
                  ],
                  "properties": {
                    "numero": {
                      "description": "Prochain numéro officiel de (campagne, nature, produit). Indicatif : il n'est pas réservé.",
                      "type": "string"
                    },
                    "rang": {
                      "minimum": 1,
                      "type": "integer"
                    },
                    "modele_version": {
                      "minimum": 1,
                      "type": "integer"
                    },
                    "segments": {
                      "minItems": 1,
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "type"
                            ],
                            "properties": {
                              "type": {
                                "const": "annee_campagne",
                                "type": "string"
                              }
                            }
                          },
                          {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "type"
                            ],
                            "properties": {
                              "type": {
                                "const": "code_campagne",
                                "type": "string"
                              }
                            }
                          },
                          {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "type"
                            ],
                            "properties": {
                              "type": {
                                "const": "nature",
                                "type": "string"
                              }
                            }
                          },
                          {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "type"
                            ],
                            "properties": {
                              "type": {
                                "const": "produit",
                                "type": "string"
                              }
                            }
                          },
                          {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "type",
                              "actif"
                            ],
                            "properties": {
                              "type": {
                                "const": "prefixe_entreprise",
                                "type": "string"
                              },
                              "actif": {
                                "type": "boolean"
                              }
                            }
                          },
                          {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "type",
                              "valeur"
                            ],
                            "properties": {
                              "type": {
                                "const": "texte",
                                "type": "string"
                              },
                              "valeur": {
                                "type": "string"
                              }
                            }
                          },
                          {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "type",
                              "chiffres"
                            ],
                            "properties": {
                              "type": {
                                "const": "sequence",
                                "type": "string"
                              },
                              "chiffres": {
                                "minimum": 1,
                                "maximum": 15,
                                "type": "integer"
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre manquant ou invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Campagne ou produit inconnu (`campagne_introuvable`, `produit_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Campagne non ouverte, séquence pleine ou segment manquant (`campagne_non_ouverte`, `sequence_hors_capacite`, `segment_manquant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/groupements": {
      "get": {
        "operationId": "listerGroupements",
        "summary": "Groupements de l'organisation active, avec leur nombre de producteurs actifs",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Groupements par code.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "groupements"
                  ],
                  "properties": {
                    "groupements": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom",
                          "actif",
                          "producteurs_actifs",
                          "producteurs_incomplets"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom": {
                            "type": "string"
                          },
                          "actif": {
                            "type": "boolean"
                          },
                          "producteurs_actifs": {
                            "minimum": 0,
                            "type": "integer"
                          },
                          "producteurs_incomplets": {
                            "minimum": 0,
                            "description": "Producteurs actifs dont la fiche est incomplète (RG-012).",
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/producteurs": {
      "get": {
        "operationId": "listerProducteurs",
        "summary": "Producteurs de l'organisation active",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "groupement",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "statut",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "const": "actif",
                  "type": "string"
                },
                {
                  "const": "fusionnee",
                  "type": "string"
                }
              ]
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "incomplet",
            "in": "query",
            "required": false,
            "schema": {
              "const": "true",
              "type": "string"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "required": false,
            "schema": {
              "minimum": 1,
              "maximum": 500,
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Producteurs par code (200 au plus par défaut). `q` cherche dans le code et le nom.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "producteurs"
                  ],
                  "properties": {
                    "producteurs": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom_complet",
                          "groupement",
                          "village",
                          "statut",
                          "en_controle",
                          "actif",
                          "incomplete"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom_complet": {
                            "type": "string"
                          },
                          "groupement": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "code",
                              "nom"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "code": {
                                "type": "string"
                              },
                              "nom": {
                                "type": "string"
                              }
                            }
                          },
                          "village": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "actif",
                                "type": "string"
                              },
                              {
                                "const": "fusionnee",
                                "type": "string"
                              }
                            ]
                          },
                          "en_controle": {
                            "description": "Vrai tant qu'un contrôle de la fiche n'est pas levé (doublon de pièce d'identité, AV1-02).",
                            "type": "boolean"
                          },
                          "actif": {
                            "description": "Faux après désactivation (RG-011).",
                            "type": "boolean"
                          },
                          "incomplete": {
                            "description": "Fiche incomplète (RG-012) : aucune parcelle active, polygone manquant ou invalide, ou pièce absente.",
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "creerProducteur",
        "summary": "Créer un producteur (`producer.register`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "code",
                  "groupement_id",
                  "nom_complet"
                ],
                "properties": {
                  "code": {
                    "minLength": 1,
                    "maxLength": 40,
                    "description": "Unique dans l'organisation, définitif (RG-010).",
                    "type": "string"
                  },
                  "groupement_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "nom_complet": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  },
                  "telephone": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "village": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "canton": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "zone_production": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "date_inscription": {
                    "anyOf": [
                      {
                        "format": "date",
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "type_piece_identite": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "numero_piece_identite": {
                    "description": "Le numéro complet n'est jamais relu : seul le masque l'est.",
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "chiffre_affaires_valeur": {
                    "description": "Unités mineures de la devise.",
                    "anyOf": [
                      {
                        "minimum": 0,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "chiffre_affaires_devise": {
                    "anyOf": [
                      {
                        "pattern": "^[A-Z]{3}$",
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "La fiche créée. Un doublon de pièce d'identité n'empêche rien : il ouvre un contrôle, visible dans `doublons` et `controles_ouverts` (AV1-02). Sans parcelle, `manques` contient `aucune_parcelle` (RG-012).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "nom_complet",
                    "groupement",
                    "village",
                    "statut",
                    "en_controle",
                    "actif",
                    "incomplete",
                    "telephone",
                    "canton",
                    "zone_production",
                    "date_inscription",
                    "type_piece_identite",
                    "numero_piece_masque",
                    "fusionnee_dans",
                    "doublons",
                    "controles_ouverts",
                    "parcelles_actives",
                    "manques",
                    "rattachable_a_collecte"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "nom_complet": {
                      "type": "string"
                    },
                    "groupement": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom": {
                          "type": "string"
                        }
                      }
                    },
                    "village": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "fusionnee",
                          "type": "string"
                        }
                      ]
                    },
                    "en_controle": {
                      "description": "Vrai tant qu'un contrôle de la fiche n'est pas levé (doublon de pièce d'identité, AV1-02).",
                      "type": "boolean"
                    },
                    "actif": {
                      "type": "boolean"
                    },
                    "incomplete": {
                      "description": "Fiche incomplète (RG-012) : aucune parcelle active, polygone manquant ou invalide, ou pièce absente.",
                      "type": "boolean"
                    },
                    "telephone": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "canton": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "zone_production": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "date_inscription": {
                      "anyOf": [
                        {
                          "format": "date",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "type_piece_identite": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "numero_piece_masque": {
                      "description": "Numéro de pièce dont seuls les trois derniers caractères sont lisibles : le numéro complet ne quitte pas l'API.",
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "fusionnee_dans": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "id",
                            "code"
                          ],
                          "properties": {
                            "id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "code": {
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "doublons": {
                      "description": "Autres fiches actives portant la même pièce d'identité (comparaison normalisée).",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom_complet"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom_complet": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "controles_ouverts": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "motif"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "motif": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "parcelles_actives": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "manques": {
                      "description": "Fiche incomplète (RG-012), calculée : aucune parcelle, polygone manquant ou invalide, pièce d'identité absente.",
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "const": "aucune_parcelle",
                            "type": "string"
                          },
                          {
                            "const": "polygone_manquant",
                            "type": "string"
                          },
                          {
                            "const": "piece_manquante",
                            "type": "string"
                          }
                        ]
                      }
                    },
                    "rattachable_a_collecte": {
                      "description": "Actif et au moins une parcelle active (RG-011, RG-012).",
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps ou fiche invalide (`corps_invalide`, `fiche_invalide` avec `details.anomalies`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Groupement inconnu (`groupement_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Code déjà utilisé, `details.producteur` nomme la fiche existante (`code_producteur_deja_utilise`, RG-010) ; groupement inactif (`groupement_inactif`) ; module inactif (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/producteurs/import": {
      "post": {
        "operationId": "importerProducteurs",
        "summary": "Importer des producteurs et leurs parcelles depuis un CSV : contrôle à blanc, puis création tout ou rien (`producer.register`, et `plot.register` si le fichier porte des parcelles)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "mode",
                  "csv"
                ],
                "properties": {
                  "mode": {
                    "anyOf": [
                      {
                        "const": "a_blanc",
                        "type": "string"
                      },
                      {
                        "const": "valider",
                        "type": "string"
                      }
                    ]
                  },
                  "csv": {
                    "minLength": 1,
                    "maxLength": 5000000,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rapport ligne par ligne. En `a_blanc`, rien n'est écrit. En `valider` sans erreur, `crees` donne les totaux. Un doublon de pièce est un avertissement, jamais une erreur (AV1-02).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "mode",
                    "lignes_lues",
                    "producteurs_a_creer",
                    "parcelles_a_creer",
                    "erreurs",
                    "avertissements",
                    "crees"
                  ],
                  "properties": {
                    "mode": {
                      "anyOf": [
                        {
                          "const": "a_blanc",
                          "type": "string"
                        },
                        {
                          "const": "valider",
                          "type": "string"
                        }
                      ]
                    },
                    "lignes_lues": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "producteurs_a_creer": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "parcelles_a_creer": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "erreurs": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "ligne",
                          "colonne",
                          "code"
                        ],
                        "properties": {
                          "ligne": {
                            "minimum": 0,
                            "description": "Ligne du fichier, l'en-tête étant la ligne 1 ; 0 pour tout le fichier.",
                            "type": "integer"
                          },
                          "colonne": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "code": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "avertissements": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "ligne",
                          "code",
                          "autre"
                        ],
                        "properties": {
                          "ligne": {
                            "minimum": 1,
                            "type": "integer"
                          },
                          "code": {
                            "type": "string"
                          },
                          "autre": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        }
                      }
                    },
                    "crees": {
                      "description": "Renseigné seulement après une validation réussie.",
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "producteurs",
                            "parcelles"
                          ],
                          "properties": {
                            "producteurs": {
                              "minimum": 0,
                              "type": "integer"
                            },
                            "parcelles": {
                              "minimum": 0,
                              "type": "integer"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`) ; validation demandée alors que le fichier a des erreurs (`import_invalide`) : relancer le contrôle à blanc.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Un code est devenu indisponible pendant l'écriture, tout est annulé (`import_conflit`) ; module inactif (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/producteurs/verifier": {
      "post": {
        "operationId": "verifierProducteur",
        "summary": "Contrôle à blanc avant création : code libre, doublons de pièce (`producer.register`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "properties": {
                  "code": {
                    "minLength": 1,
                    "maxLength": 40,
                    "type": "string"
                  },
                  "type_piece_identite": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  },
                  "numero_piece_identite": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Informatif, rien n'est écrit.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "code_libre",
                    "code_pris_par",
                    "doublons"
                  ],
                  "properties": {
                    "code_libre": {
                      "type": "boolean"
                    },
                    "code_pris_par": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "id",
                            "code",
                            "nom_complet"
                          ],
                          "properties": {
                            "id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "code": {
                              "type": "string"
                            },
                            "nom_complet": {
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "doublons": {
                      "description": "Fiches actives portant la même pièce (comparaison normalisée). Informatif : un doublon n'empêche jamais l'enregistrement (AV1-02).",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom_complet"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom_complet": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`) ; type et numéro de pièce vont ensemble (`fiche_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/producteurs/{id}": {
      "patch": {
        "operationId": "modifierProducteur",
        "summary": "Modifier une fiche producteur ; le code est définitif (`producer.update`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "properties": {
                  "groupement_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "nom_complet": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  },
                  "telephone": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "village": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "canton": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "zone_production": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "date_inscription": {
                    "anyOf": [
                      {
                        "format": "date",
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "type_piece_identite": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "numero_piece_identite": {
                    "description": "Le numéro complet n'est jamais relu : seul le masque l'est.",
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "chiffre_affaires_valeur": {
                    "description": "Unités mineures de la devise.",
                    "anyOf": [
                      {
                        "minimum": 0,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "chiffre_affaires_devise": {
                    "anyOf": [
                      {
                        "pattern": "^[A-Z]{3}$",
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "minProperties": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "La fiche modifiée.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "nom_complet",
                    "groupement",
                    "village",
                    "statut",
                    "en_controle",
                    "actif",
                    "incomplete",
                    "telephone",
                    "canton",
                    "zone_production",
                    "date_inscription",
                    "type_piece_identite",
                    "numero_piece_masque",
                    "fusionnee_dans",
                    "doublons",
                    "controles_ouverts",
                    "parcelles_actives",
                    "manques",
                    "rattachable_a_collecte"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "nom_complet": {
                      "type": "string"
                    },
                    "groupement": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom": {
                          "type": "string"
                        }
                      }
                    },
                    "village": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "fusionnee",
                          "type": "string"
                        }
                      ]
                    },
                    "en_controle": {
                      "description": "Vrai tant qu'un contrôle de la fiche n'est pas levé (doublon de pièce d'identité, AV1-02).",
                      "type": "boolean"
                    },
                    "actif": {
                      "type": "boolean"
                    },
                    "incomplete": {
                      "description": "Fiche incomplète (RG-012) : aucune parcelle active, polygone manquant ou invalide, ou pièce absente.",
                      "type": "boolean"
                    },
                    "telephone": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "canton": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "zone_production": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "date_inscription": {
                      "anyOf": [
                        {
                          "format": "date",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "type_piece_identite": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "numero_piece_masque": {
                      "description": "Numéro de pièce dont seuls les trois derniers caractères sont lisibles : le numéro complet ne quitte pas l'API.",
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "fusionnee_dans": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "id",
                            "code"
                          ],
                          "properties": {
                            "id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "code": {
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "doublons": {
                      "description": "Autres fiches actives portant la même pièce d'identité (comparaison normalisée).",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom_complet"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom_complet": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "controles_ouverts": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "motif"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "motif": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "parcelles_actives": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "manques": {
                      "description": "Fiche incomplète (RG-012), calculée : aucune parcelle, polygone manquant ou invalide, pièce d'identité absente.",
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "const": "aucune_parcelle",
                            "type": "string"
                          },
                          {
                            "const": "polygone_manquant",
                            "type": "string"
                          },
                          {
                            "const": "piece_manquante",
                            "type": "string"
                          }
                        ]
                      }
                    },
                    "rattachable_a_collecte": {
                      "description": "Actif et au moins une parcelle active (RG-011, RG-012).",
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps ou fiche invalide (`corps_invalide`, `fiche_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Producteur ou groupement inconnu (`producteur_inconnu`, `groupement_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Fiche fusionnée (`producteur_fusionne`) ; groupement figé tant que le producteur a des parcelles (`groupement_verrouille`) ; groupement inactif ; module inactif.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "lireProducteur",
        "summary": "Fiche d'un producteur, avec ses doublons de pièce et ses contrôles ouverts",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "La fiche. Le numéro de pièce est masqué.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "nom_complet",
                    "groupement",
                    "village",
                    "statut",
                    "en_controle",
                    "actif",
                    "incomplete",
                    "telephone",
                    "canton",
                    "zone_production",
                    "date_inscription",
                    "type_piece_identite",
                    "numero_piece_masque",
                    "fusionnee_dans",
                    "doublons",
                    "controles_ouverts",
                    "parcelles_actives",
                    "manques",
                    "rattachable_a_collecte"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "nom_complet": {
                      "type": "string"
                    },
                    "groupement": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom": {
                          "type": "string"
                        }
                      }
                    },
                    "village": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "fusionnee",
                          "type": "string"
                        }
                      ]
                    },
                    "en_controle": {
                      "description": "Vrai tant qu'un contrôle de la fiche n'est pas levé (doublon de pièce d'identité, AV1-02).",
                      "type": "boolean"
                    },
                    "actif": {
                      "type": "boolean"
                    },
                    "incomplete": {
                      "description": "Fiche incomplète (RG-012) : aucune parcelle active, polygone manquant ou invalide, ou pièce absente.",
                      "type": "boolean"
                    },
                    "telephone": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "canton": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "zone_production": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "date_inscription": {
                      "anyOf": [
                        {
                          "format": "date",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "type_piece_identite": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "numero_piece_masque": {
                      "description": "Numéro de pièce dont seuls les trois derniers caractères sont lisibles : le numéro complet ne quitte pas l'API.",
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "fusionnee_dans": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "id",
                            "code"
                          ],
                          "properties": {
                            "id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "code": {
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "doublons": {
                      "description": "Autres fiches actives portant la même pièce d'identité (comparaison normalisée).",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom_complet"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom_complet": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "controles_ouverts": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "motif"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "motif": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "parcelles_actives": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "manques": {
                      "description": "Fiche incomplète (RG-012), calculée : aucune parcelle, polygone manquant ou invalide, pièce d'identité absente.",
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "const": "aucune_parcelle",
                            "type": "string"
                          },
                          {
                            "const": "polygone_manquant",
                            "type": "string"
                          },
                          {
                            "const": "piece_manquante",
                            "type": "string"
                          }
                        ]
                      }
                    },
                    "rattachable_a_collecte": {
                      "description": "Actif et au moins une parcelle active (RG-011, RG-012).",
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Producteur inconnu dans l'organisation active (`producteur_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/producteurs/{id}/desactiver": {
      "post": {
        "operationId": "desactiverProducteur",
        "summary": "Désactiver un producteur : il quitte les listes de saisie, l'historique reste (RG-011) (`producer.update`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "La fiche, `actif` à faux.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "nom_complet",
                    "groupement",
                    "village",
                    "statut",
                    "en_controle",
                    "actif",
                    "incomplete",
                    "telephone",
                    "canton",
                    "zone_production",
                    "date_inscription",
                    "type_piece_identite",
                    "numero_piece_masque",
                    "fusionnee_dans",
                    "doublons",
                    "controles_ouverts",
                    "parcelles_actives",
                    "manques",
                    "rattachable_a_collecte"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "nom_complet": {
                      "type": "string"
                    },
                    "groupement": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom": {
                          "type": "string"
                        }
                      }
                    },
                    "village": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "fusionnee",
                          "type": "string"
                        }
                      ]
                    },
                    "en_controle": {
                      "description": "Vrai tant qu'un contrôle de la fiche n'est pas levé (doublon de pièce d'identité, AV1-02).",
                      "type": "boolean"
                    },
                    "actif": {
                      "type": "boolean"
                    },
                    "incomplete": {
                      "description": "Fiche incomplète (RG-012) : aucune parcelle active, polygone manquant ou invalide, ou pièce absente.",
                      "type": "boolean"
                    },
                    "telephone": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "canton": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "zone_production": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "date_inscription": {
                      "anyOf": [
                        {
                          "format": "date",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "type_piece_identite": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "numero_piece_masque": {
                      "description": "Numéro de pièce dont seuls les trois derniers caractères sont lisibles : le numéro complet ne quitte pas l'API.",
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "fusionnee_dans": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "id",
                            "code"
                          ],
                          "properties": {
                            "id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "code": {
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "doublons": {
                      "description": "Autres fiches actives portant la même pièce d'identité (comparaison normalisée).",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom_complet"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom_complet": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "controles_ouverts": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "motif"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "motif": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "parcelles_actives": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "manques": {
                      "description": "Fiche incomplète (RG-012), calculée : aucune parcelle, polygone manquant ou invalide, pièce d'identité absente.",
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "const": "aucune_parcelle",
                            "type": "string"
                          },
                          {
                            "const": "polygone_manquant",
                            "type": "string"
                          },
                          {
                            "const": "piece_manquante",
                            "type": "string"
                          }
                        ]
                      }
                    },
                    "rattachable_a_collecte": {
                      "description": "Actif et au moins une parcelle active (RG-011, RG-012).",
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Producteur inconnu (`producteur_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Fiche fusionnée (`producteur_fusionne`) ; module inactif.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/producteurs/{id}/reactiver": {
      "post": {
        "operationId": "reactiverProducteur",
        "summary": "Réactiver un producteur désactivé (`producer.update`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "La fiche, `actif` à vrai.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "nom_complet",
                    "groupement",
                    "village",
                    "statut",
                    "en_controle",
                    "actif",
                    "incomplete",
                    "telephone",
                    "canton",
                    "zone_production",
                    "date_inscription",
                    "type_piece_identite",
                    "numero_piece_masque",
                    "fusionnee_dans",
                    "doublons",
                    "controles_ouverts",
                    "parcelles_actives",
                    "manques",
                    "rattachable_a_collecte"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "nom_complet": {
                      "type": "string"
                    },
                    "groupement": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom": {
                          "type": "string"
                        }
                      }
                    },
                    "village": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "fusionnee",
                          "type": "string"
                        }
                      ]
                    },
                    "en_controle": {
                      "description": "Vrai tant qu'un contrôle de la fiche n'est pas levé (doublon de pièce d'identité, AV1-02).",
                      "type": "boolean"
                    },
                    "actif": {
                      "type": "boolean"
                    },
                    "incomplete": {
                      "description": "Fiche incomplète (RG-012) : aucune parcelle active, polygone manquant ou invalide, ou pièce absente.",
                      "type": "boolean"
                    },
                    "telephone": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "canton": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "zone_production": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "date_inscription": {
                      "anyOf": [
                        {
                          "format": "date",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "type_piece_identite": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "numero_piece_masque": {
                      "description": "Numéro de pièce dont seuls les trois derniers caractères sont lisibles : le numéro complet ne quitte pas l'API.",
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "fusionnee_dans": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "id",
                            "code"
                          ],
                          "properties": {
                            "id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "code": {
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "doublons": {
                      "description": "Autres fiches actives portant la même pièce d'identité (comparaison normalisée).",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom_complet"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom_complet": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "controles_ouverts": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "motif"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "motif": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "parcelles_actives": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "manques": {
                      "description": "Fiche incomplète (RG-012), calculée : aucune parcelle, polygone manquant ou invalide, pièce d'identité absente.",
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "const": "aucune_parcelle",
                            "type": "string"
                          },
                          {
                            "const": "polygone_manquant",
                            "type": "string"
                          },
                          {
                            "const": "piece_manquante",
                            "type": "string"
                          }
                        ]
                      }
                    },
                    "rattachable_a_collecte": {
                      "description": "Actif et au moins une parcelle active (RG-011, RG-012).",
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Producteur inconnu (`producteur_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Fiche fusionnée (`producteur_fusionne`) ; module inactif.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/producteurs/{id}/fusionner": {
      "post": {
        "operationId": "fusionnerProducteur",
        "summary": "Fusionner cette fiche (absorbée) dans une autre (retenue) (`review.resolve`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "retenu_id",
                  "motif"
                ],
                "properties": {
                  "retenu_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Motif écrit : toute fusion en exige un (AV1-02).",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "La fiche retenue, après fusion. La fiche absorbée devient `fusionnee`, ses contrôles de doublon sont levés (décision `fusion`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "nom_complet",
                    "groupement",
                    "village",
                    "statut",
                    "en_controle",
                    "actif",
                    "incomplete",
                    "telephone",
                    "canton",
                    "zone_production",
                    "date_inscription",
                    "type_piece_identite",
                    "numero_piece_masque",
                    "fusionnee_dans",
                    "doublons",
                    "controles_ouverts",
                    "parcelles_actives",
                    "manques",
                    "rattachable_a_collecte"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "nom_complet": {
                      "type": "string"
                    },
                    "groupement": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom": {
                          "type": "string"
                        }
                      }
                    },
                    "village": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "fusionnee",
                          "type": "string"
                        }
                      ]
                    },
                    "en_controle": {
                      "description": "Vrai tant qu'un contrôle de la fiche n'est pas levé (doublon de pièce d'identité, AV1-02).",
                      "type": "boolean"
                    },
                    "actif": {
                      "type": "boolean"
                    },
                    "incomplete": {
                      "description": "Fiche incomplète (RG-012) : aucune parcelle active, polygone manquant ou invalide, ou pièce absente.",
                      "type": "boolean"
                    },
                    "telephone": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "canton": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "zone_production": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "date_inscription": {
                      "anyOf": [
                        {
                          "format": "date",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "type_piece_identite": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "numero_piece_masque": {
                      "description": "Numéro de pièce dont seuls les trois derniers caractères sont lisibles : le numéro complet ne quitte pas l'API.",
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "fusionnee_dans": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "id",
                            "code"
                          ],
                          "properties": {
                            "id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "code": {
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "doublons": {
                      "description": "Autres fiches actives portant la même pièce d'identité (comparaison normalisée).",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom_complet"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom_complet": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "controles_ouverts": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "motif"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "motif": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "parcelles_actives": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "manques": {
                      "description": "Fiche incomplète (RG-012), calculée : aucune parcelle, polygone manquant ou invalide, pièce d'identité absente.",
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "const": "aucune_parcelle",
                            "type": "string"
                          },
                          {
                            "const": "polygone_manquant",
                            "type": "string"
                          },
                          {
                            "const": "piece_manquante",
                            "type": "string"
                          }
                        ]
                      }
                    },
                    "rattachable_a_collecte": {
                      "description": "Actif et au moins une parcelle active (RG-011, RG-012).",
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide, ou fusion refusée (`fusion_refusee`) : motif vide, même fiche.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Fiche introuvable ou déjà fusionnée (`fiche_introuvable`, `producteur_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Module Membres et foncier inactif : lecture seule (`module_inactif`, `details.module`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/parcelles": {
      "get": {
        "operationId": "listerParcelles",
        "summary": "Parcelles de l'organisation active, avec la version de polygone en vigueur",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "producteur",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupement",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "required": false,
            "schema": {
              "minimum": 1,
              "maximum": 500,
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Parcelles par code (200 au plus par défaut). `q` cherche dans le code de la parcelle.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "parcelles"
                  ],
                  "properties": {
                    "parcelles": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "type_surface",
                          "actif",
                          "surface_declaree_m2",
                          "producteur",
                          "groupement_code",
                          "produit_code",
                          "version_en_vigueur",
                          "en_controle"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "type_surface": {
                            "type": "string"
                          },
                          "actif": {
                            "type": "boolean"
                          },
                          "surface_declaree_m2": {
                            "minimum": 1,
                            "type": "integer"
                          },
                          "producteur": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "code",
                              "nom_complet"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "code": {
                                "type": "string"
                              },
                              "nom_complet": {
                                "type": "string"
                              }
                            }
                          },
                          "groupement_code": {
                            "type": "string"
                          },
                          "produit_code": {
                            "type": "string"
                          },
                          "version_en_vigueur": {
                            "anyOf": [
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "version",
                                  "valide",
                                  "surface_mesuree_m2",
                                  "incertitude_m2"
                                ],
                                "properties": {
                                  "version": {
                                    "minimum": 1,
                                    "type": "integer"
                                  },
                                  "valide": {
                                    "type": "boolean"
                                  },
                                  "surface_mesuree_m2": {
                                    "anyOf": [
                                      {
                                        "type": "integer"
                                      },
                                      {
                                        "type": "null"
                                      }
                                    ]
                                  },
                                  "incertitude_m2": {
                                    "anyOf": [
                                      {
                                        "type": "integer"
                                      },
                                      {
                                        "type": "null"
                                      }
                                    ]
                                  }
                                }
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "en_controle": {
                            "description": "Vrai tant qu'un contrôle d'une version de polygone de la parcelle n'est pas levé.",
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/facteurs": {
      "get": {
        "operationId": "listerFacteurs",
        "summary": "Facteurs de la parcelle (région, mode de culture, type de sol) et leurs valeurs admises",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Catalogue en lecture seule ; les valeurs de région et de type de sol viennent du pack publié.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "facteurs"
                  ],
                  "properties": {
                    "facteurs": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle_fr",
                          "libelle_en",
                          "valeurs"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "valeurs": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "code",
                                "libelle_fr",
                                "libelle_en"
                              ],
                              "properties": {
                                "code": {
                                  "type": "string"
                                },
                                "libelle_fr": {
                                  "type": "string"
                                },
                                "libelle_en": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/producteurs/{id}/parcelles": {
      "post": {
        "operationId": "creerParcelle",
        "summary": "Créer une parcelle pour un producteur, sans polygone (`plot.register`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "code",
                  "produit_id",
                  "surface_declaree_m2"
                ],
                "properties": {
                  "code": {
                    "minLength": 1,
                    "maxLength": 40,
                    "description": "Unique dans l'organisation, définitif.",
                    "type": "string"
                  },
                  "produit_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "type_surface": {
                    "anyOf": [
                      {
                        "const": "cultures",
                        "type": "string"
                      },
                      {
                        "const": "serres",
                        "type": "string"
                      },
                      {
                        "const": "prairies",
                        "type": "string"
                      }
                    ]
                  },
                  "surface_declaree_m2": {
                    "minimum": 1,
                    "description": "En mètres carrés (EC-030).",
                    "type": "integer"
                  },
                  "region": {
                    "minLength": 1,
                    "maxLength": 60,
                    "type": "string"
                  },
                  "mode_culture": {
                    "minLength": 1,
                    "maxLength": 60,
                    "type": "string"
                  },
                  "type_sol": {
                    "minLength": 1,
                    "maxLength": 60,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "La parcelle créée, dans le groupement du producteur. Sans polygone, elle reste signalée ; le polygone arrive par l'import (`plot.survey`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "type_surface",
                    "actif",
                    "surface_declaree_m2",
                    "producteur",
                    "groupement_code",
                    "produit_code",
                    "version_en_vigueur",
                    "en_controle",
                    "region",
                    "mode_culture",
                    "type_sol",
                    "versions",
                    "ecart",
                    "controles_ouverts"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "type_surface": {
                      "type": "string"
                    },
                    "actif": {
                      "type": "boolean"
                    },
                    "surface_declaree_m2": {
                      "minimum": 1,
                      "type": "integer"
                    },
                    "producteur": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom_complet"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom_complet": {
                          "type": "string"
                        }
                      }
                    },
                    "groupement_code": {
                      "type": "string"
                    },
                    "produit_code": {
                      "type": "string"
                    },
                    "version_en_vigueur": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "version",
                            "valide",
                            "surface_mesuree_m2",
                            "incertitude_m2"
                          ],
                          "properties": {
                            "version": {
                              "minimum": 1,
                              "type": "integer"
                            },
                            "valide": {
                              "type": "boolean"
                            },
                            "surface_mesuree_m2": {
                              "anyOf": [
                                {
                                  "type": "integer"
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "incertitude_m2": {
                              "anyOf": [
                                {
                                  "type": "integer"
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "en_controle": {
                      "description": "Vrai tant qu'un contrôle d'une version de polygone de la parcelle n'est pas levé.",
                      "type": "boolean"
                    },
                    "region": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "mode_culture": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "type_sol": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "versions": {
                      "description": "Du plus récent au plus ancien ; la première est en vigueur.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "version",
                          "methode",
                          "valide",
                          "motif_invalidite",
                          "surface_mesuree_m2",
                          "perimetre_m",
                          "incertitude_m2",
                          "precision_mediane_cm",
                          "cree_le",
                          "geometrie"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "version": {
                            "minimum": 1,
                            "type": "integer"
                          },
                          "methode": {
                            "type": "string"
                          },
                          "valide": {
                            "type": "boolean"
                          },
                          "motif_invalidite": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "surface_mesuree_m2": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "perimetre_m": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "incertitude_m2": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "precision_mediane_cm": {
                            "minimum": 0,
                            "type": "integer"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "geometrie": {
                            "additionalProperties": true,
                            "description": "Polygone GeoJSON tel qu'enregistré, même invalide : il n'est jamais corrigé.",
                            "type": "object",
                            "properties": {}
                          }
                        }
                      }
                    },
                    "ecart": {
                      "description": "Absent quand la version en vigueur est invalide ou qu'il n'y en a pas.",
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "declaree_m2",
                            "mesuree_m2",
                            "incertitude_m2",
                            "ecart_m2",
                            "ecart_relatif_cp",
                            "anomalie"
                          ],
                          "properties": {
                            "declaree_m2": {
                              "type": "integer"
                            },
                            "mesuree_m2": {
                              "type": "integer"
                            },
                            "incertitude_m2": {
                              "type": "integer"
                            },
                            "ecart_m2": {
                              "type": "integer"
                            },
                            "ecart_relatif_cp": {
                              "description": "Écart relatif en centièmes de point (7 000 = 70 %).",
                              "type": "integer"
                            },
                            "anomalie": {
                              "description": "Vrai seulement si l'écart dépasse l'incertitude de la mesure (GPS-04).",
                              "type": "boolean"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "controles_ouverts": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "motif"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "motif": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`) ; produit ou facteur inconnu (`produit_inconnu`, `facteur_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Producteur ou produit inconnu (`producteur_inconnu`, `produit_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Code déjà utilisé, `details.parcelle` nomme la parcelle (`code_parcelle_deja_utilise`) ; producteur fusionné ou désactivé (`producteur_fusionne`, `producteur_inactif`) ; module inactif (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/parcelles/{id}": {
      "patch": {
        "operationId": "modifierParcelle",
        "summary": "Modifier une parcelle ou la désactiver ; le code est définitif (`plot.register`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "properties": {
                  "produit_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "type_surface": {
                    "anyOf": [
                      {
                        "const": "cultures",
                        "type": "string"
                      },
                      {
                        "const": "serres",
                        "type": "string"
                      },
                      {
                        "const": "prairies",
                        "type": "string"
                      }
                    ]
                  },
                  "surface_declaree_m2": {
                    "minimum": 1,
                    "type": "integer"
                  },
                  "region": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 60,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "mode_culture": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 60,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "type_sol": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "maxLength": 60,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "actif": {
                    "description": "Faux : la parcelle quitte les listes de saisie, son historique reste.",
                    "type": "boolean"
                  }
                },
                "minProperties": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "La parcelle modifiée.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "type_surface",
                    "actif",
                    "surface_declaree_m2",
                    "producteur",
                    "groupement_code",
                    "produit_code",
                    "version_en_vigueur",
                    "en_controle",
                    "region",
                    "mode_culture",
                    "type_sol",
                    "versions",
                    "ecart",
                    "controles_ouverts"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "type_surface": {
                      "type": "string"
                    },
                    "actif": {
                      "type": "boolean"
                    },
                    "surface_declaree_m2": {
                      "minimum": 1,
                      "type": "integer"
                    },
                    "producteur": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom_complet"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom_complet": {
                          "type": "string"
                        }
                      }
                    },
                    "groupement_code": {
                      "type": "string"
                    },
                    "produit_code": {
                      "type": "string"
                    },
                    "version_en_vigueur": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "version",
                            "valide",
                            "surface_mesuree_m2",
                            "incertitude_m2"
                          ],
                          "properties": {
                            "version": {
                              "minimum": 1,
                              "type": "integer"
                            },
                            "valide": {
                              "type": "boolean"
                            },
                            "surface_mesuree_m2": {
                              "anyOf": [
                                {
                                  "type": "integer"
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "incertitude_m2": {
                              "anyOf": [
                                {
                                  "type": "integer"
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "en_controle": {
                      "description": "Vrai tant qu'un contrôle d'une version de polygone de la parcelle n'est pas levé.",
                      "type": "boolean"
                    },
                    "region": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "mode_culture": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "type_sol": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "versions": {
                      "description": "Du plus récent au plus ancien ; la première est en vigueur.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "version",
                          "methode",
                          "valide",
                          "motif_invalidite",
                          "surface_mesuree_m2",
                          "perimetre_m",
                          "incertitude_m2",
                          "precision_mediane_cm",
                          "cree_le",
                          "geometrie"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "version": {
                            "minimum": 1,
                            "type": "integer"
                          },
                          "methode": {
                            "type": "string"
                          },
                          "valide": {
                            "type": "boolean"
                          },
                          "motif_invalidite": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "surface_mesuree_m2": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "perimetre_m": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "incertitude_m2": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "precision_mediane_cm": {
                            "minimum": 0,
                            "type": "integer"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "geometrie": {
                            "additionalProperties": true,
                            "description": "Polygone GeoJSON tel qu'enregistré, même invalide : il n'est jamais corrigé.",
                            "type": "object",
                            "properties": {}
                          }
                        }
                      }
                    },
                    "ecart": {
                      "description": "Absent quand la version en vigueur est invalide ou qu'il n'y en a pas.",
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "declaree_m2",
                            "mesuree_m2",
                            "incertitude_m2",
                            "ecart_m2",
                            "ecart_relatif_cp",
                            "anomalie"
                          ],
                          "properties": {
                            "declaree_m2": {
                              "type": "integer"
                            },
                            "mesuree_m2": {
                              "type": "integer"
                            },
                            "incertitude_m2": {
                              "type": "integer"
                            },
                            "ecart_m2": {
                              "type": "integer"
                            },
                            "ecart_relatif_cp": {
                              "description": "Écart relatif en centièmes de point (7 000 = 70 %).",
                              "type": "integer"
                            },
                            "anomalie": {
                              "description": "Vrai seulement si l'écart dépasse l'incertitude de la mesure (GPS-04).",
                              "type": "boolean"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "controles_ouverts": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "motif"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "motif": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`) ; produit ou facteur inconnu (`produit_inconnu`, `facteur_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Parcelle ou produit inconnu (`parcelle_inconnue`, `produit_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Module Membres et foncier inactif : lecture seule (`module_inactif`, `details.module`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "lireParcelle",
        "summary": "Fiche d'une parcelle : versions de polygone, écart de surface avec son incertitude, contrôles ouverts",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "La fiche. Les polygones invalides sont rendus tels qu'enregistrés.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "type_surface",
                    "actif",
                    "surface_declaree_m2",
                    "producteur",
                    "groupement_code",
                    "produit_code",
                    "version_en_vigueur",
                    "en_controle",
                    "region",
                    "mode_culture",
                    "type_sol",
                    "versions",
                    "ecart",
                    "controles_ouverts"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "type_surface": {
                      "type": "string"
                    },
                    "actif": {
                      "type": "boolean"
                    },
                    "surface_declaree_m2": {
                      "minimum": 1,
                      "type": "integer"
                    },
                    "producteur": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom_complet"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom_complet": {
                          "type": "string"
                        }
                      }
                    },
                    "groupement_code": {
                      "type": "string"
                    },
                    "produit_code": {
                      "type": "string"
                    },
                    "version_en_vigueur": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "version",
                            "valide",
                            "surface_mesuree_m2",
                            "incertitude_m2"
                          ],
                          "properties": {
                            "version": {
                              "minimum": 1,
                              "type": "integer"
                            },
                            "valide": {
                              "type": "boolean"
                            },
                            "surface_mesuree_m2": {
                              "anyOf": [
                                {
                                  "type": "integer"
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "incertitude_m2": {
                              "anyOf": [
                                {
                                  "type": "integer"
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "en_controle": {
                      "description": "Vrai tant qu'un contrôle d'une version de polygone de la parcelle n'est pas levé.",
                      "type": "boolean"
                    },
                    "region": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "mode_culture": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "type_sol": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "versions": {
                      "description": "Du plus récent au plus ancien ; la première est en vigueur.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "version",
                          "methode",
                          "valide",
                          "motif_invalidite",
                          "surface_mesuree_m2",
                          "perimetre_m",
                          "incertitude_m2",
                          "precision_mediane_cm",
                          "cree_le",
                          "geometrie"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "version": {
                            "minimum": 1,
                            "type": "integer"
                          },
                          "methode": {
                            "type": "string"
                          },
                          "valide": {
                            "type": "boolean"
                          },
                          "motif_invalidite": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "surface_mesuree_m2": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "perimetre_m": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "incertitude_m2": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "precision_mediane_cm": {
                            "minimum": 0,
                            "type": "integer"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "geometrie": {
                            "additionalProperties": true,
                            "description": "Polygone GeoJSON tel qu'enregistré, même invalide : il n'est jamais corrigé.",
                            "type": "object",
                            "properties": {}
                          }
                        }
                      }
                    },
                    "ecart": {
                      "description": "Absent quand la version en vigueur est invalide ou qu'il n'y en a pas.",
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "declaree_m2",
                            "mesuree_m2",
                            "incertitude_m2",
                            "ecart_m2",
                            "ecart_relatif_cp",
                            "anomalie"
                          ],
                          "properties": {
                            "declaree_m2": {
                              "type": "integer"
                            },
                            "mesuree_m2": {
                              "type": "integer"
                            },
                            "incertitude_m2": {
                              "type": "integer"
                            },
                            "ecart_m2": {
                              "type": "integer"
                            },
                            "ecart_relatif_cp": {
                              "description": "Écart relatif en centièmes de point (7 000 = 70 %).",
                              "type": "integer"
                            },
                            "anomalie": {
                              "description": "Vrai seulement si l'écart dépasse l'incertitude de la mesure (GPS-04).",
                              "type": "boolean"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "controles_ouverts": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "motif"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "motif": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Parcelle inconnue dans l'organisation active (`parcelle_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/parcelles/{id}/polygone": {
      "post": {
        "operationId": "importerPolygone",
        "summary": "Importer un polygone GeoJSON comme nouvelle version de la parcelle (`plot.survey`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "geometrie",
                  "precision_mediane_cm"
                ],
                "properties": {
                  "geometrie": {
                    "additionalProperties": false,
                    "type": "object",
                    "required": [
                      "type",
                      "coordinates"
                    ],
                    "properties": {
                      "type": {
                        "const": "Polygon",
                        "type": "string"
                      },
                      "coordinates": {
                        "minItems": 1,
                        "maxItems": 1,
                        "type": "array",
                        "items": {
                          "minItems": 4,
                          "type": "array",
                          "items": {
                            "description": "[longitude, latitude] en degrés décimaux, WGS 84.",
                            "type": "array",
                            "items": [
                              {
                                "minimum": -180,
                                "maximum": 180,
                                "type": "number"
                              },
                              {
                                "minimum": -90,
                                "maximum": 90,
                                "type": "number"
                              }
                            ],
                            "additionalItems": false,
                            "minItems": 2,
                            "maxItems": 2
                          }
                        }
                      }
                    }
                  },
                  "precision_mediane_cm": {
                    "minimum": 0,
                    "type": "integer"
                  },
                  "appareil": {
                    "minLength": 1,
                    "type": "string"
                  },
                  "trace_fichier_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "La nouvelle version. Un polygone invalide est conservé et signalé par un contrôle, jamais corrigé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "version_id",
                    "version",
                    "valide",
                    "motif_invalidite",
                    "surface_mesuree_m2",
                    "incertitude_m2",
                    "controles"
                  ],
                  "properties": {
                    "version_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "version": {
                      "minimum": 1,
                      "type": "integer"
                    },
                    "valide": {
                      "type": "boolean"
                    },
                    "motif_invalidite": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "surface_mesuree_m2": {
                      "anyOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "incertitude_m2": {
                      "anyOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "controles": {
                      "description": "Contrôles ouverts sur cette version : `polygone_invalide`, `chevauchement_parcelle`.",
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide ou polygone illisible (`corps_invalide`, `polygone_illisible`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Parcelle inconnue (`parcelle_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Module Membres et foncier inactif : lecture seule (`module_inactif`, `details.module`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/certificats": {
      "get": {
        "operationId": "listerCertificats",
        "summary": "Certificats de l'organisation active, avec leur état et leur alerte à une date",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "referentiel",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "date",
            "in": "query",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Certificats par date de fin croissante. « Expiré » est calculé à la date de référence (aujourd'hui par défaut), jamais stocké.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "date_reference",
                    "seuil_alerte_jours",
                    "certificats"
                  ],
                  "properties": {
                    "date_reference": {
                      "format": "date",
                      "type": "string"
                    },
                    "seuil_alerte_jours": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "certificats": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "referentiel",
                          "titulaire",
                          "organisme_nom",
                          "organisme_code",
                          "numero",
                          "date_debut",
                          "date_fin",
                          "statut",
                          "etat",
                          "alerte",
                          "a_pdf",
                          "portee"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "referentiel": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "code",
                              "libelle_fr",
                              "libelle_en"
                            ],
                            "properties": {
                              "code": {
                                "type": "string"
                              },
                              "libelle_fr": {
                                "type": "string"
                              },
                              "libelle_en": {
                                "type": "string"
                              }
                            }
                          },
                          "titulaire": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "type",
                              "code",
                              "nom"
                            ],
                            "properties": {
                              "type": {
                                "anyOf": [
                                  {
                                    "const": "operateur",
                                    "type": "string"
                                  },
                                  {
                                    "const": "groupement",
                                    "type": "string"
                                  },
                                  {
                                    "const": "fournisseur",
                                    "type": "string"
                                  }
                                ]
                              },
                              "code": {
                                "type": "string"
                              },
                              "nom": {
                                "type": "string"
                              }
                            }
                          },
                          "organisme_nom": {
                            "type": "string"
                          },
                          "organisme_code": {
                            "type": "string"
                          },
                          "numero": {
                            "type": "string"
                          },
                          "date_debut": {
                            "format": "date",
                            "type": "string"
                          },
                          "date_fin": {
                            "format": "date",
                            "type": "string"
                          },
                          "statut": {
                            "description": "Statut stocké. « Expiré » n'y figure jamais.",
                            "anyOf": [
                              {
                                "const": "valide",
                                "type": "string"
                              },
                              {
                                "const": "suspendu",
                                "type": "string"
                              },
                              {
                                "const": "retire",
                                "type": "string"
                              }
                            ]
                          },
                          "etat": {
                            "description": "État calculé à la date de référence par le domaine (`etatCertificat`).",
                            "anyOf": [
                              {
                                "const": "en_vigueur",
                                "type": "string"
                              },
                              {
                                "const": "pas_commence",
                                "type": "string"
                              },
                              {
                                "const": "expire",
                                "type": "string"
                              },
                              {
                                "const": "suspendu",
                                "type": "string"
                              },
                              {
                                "const": "retire",
                                "type": "string"
                              }
                            ]
                          },
                          "alerte": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "niveau",
                              "jours_restants"
                            ],
                            "properties": {
                              "niveau": {
                                "anyOf": [
                                  {
                                    "const": "ok",
                                    "type": "string"
                                  },
                                  {
                                    "const": "expire_bientot",
                                    "type": "string"
                                  },
                                  {
                                    "const": "expire",
                                    "type": "string"
                                  }
                                ]
                              },
                              "jours_restants": {
                                "type": "integer"
                              }
                            }
                          },
                          "a_pdf": {
                            "description": "Vrai si le PDF du certificat est joint.",
                            "type": "boolean"
                          },
                          "portee": {
                            "description": "Portée du certificat (AM-07). Vide : portée non renseignée.",
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "dimension",
                                "element",
                                "libelle_fr",
                                "libelle_en",
                                "inclus"
                              ],
                              "properties": {
                                "dimension": {
                                  "anyOf": [
                                    {
                                      "const": "activite",
                                      "type": "string"
                                    },
                                    {
                                      "const": "produit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "site",
                                      "type": "string"
                                    },
                                    {
                                      "const": "unite",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "element": {
                                  "description": "Code d'activité, ou identifiant du produit, du site ou de l'unité.",
                                  "type": "string"
                                },
                                "libelle_fr": {
                                  "type": "string"
                                },
                                "libelle_en": {
                                  "type": "string"
                                },
                                "inclus": {
                                  "description": "Faux : exclu expressément.",
                                  "type": "boolean"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/conformite/statuts": {
      "get": {
        "operationId": "syntheseStatuts",
        "summary": "Synthèse des statuts de conformité par référentiel à une date",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Pour chaque référentiel actif, le nombre d'unités par état de conformité à la date.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "date_reference",
                    "referentiels"
                  ],
                  "properties": {
                    "date_reference": {
                      "format": "date",
                      "type": "string"
                    },
                    "referentiels": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle_fr",
                          "libelle_en",
                          "etats"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "etats": {
                            "description": "Nombre d'unités (producteurs, parcelles, zones de cueillette) par état de conformité à la date. Une unité sans statut n'est pas comptée.",
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "etat",
                                "unites"
                              ],
                              "properties": {
                                "etat": {
                                  "additionalProperties": false,
                                  "type": "object",
                                  "required": [
                                    "code",
                                    "libelle_fr",
                                    "libelle_en",
                                    "categorie"
                                  ],
                                  "properties": {
                                    "code": {
                                      "type": "string"
                                    },
                                    "libelle_fr": {
                                      "type": "string"
                                    },
                                    "libelle_en": {
                                      "type": "string"
                                    },
                                    "categorie": {
                                      "anyOf": [
                                        {
                                          "const": "bio",
                                          "type": "string"
                                        },
                                        {
                                          "const": "conversion",
                                          "type": "string"
                                        },
                                        {
                                          "const": "conventionnel",
                                          "type": "string"
                                        },
                                        {
                                          "const": "hors_statut",
                                          "type": "string"
                                        }
                                      ]
                                    }
                                  }
                                },
                                "unites": {
                                  "minimum": 1,
                                  "type": "integer"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Date invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "enregistrerStatutConformite",
        "summary": "Ajouter une ligne à l'historique du statut de conformité d'une unité ; toute révision exige un motif (`certification.manage`, RG-150)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "referentiel_id",
                  "etat",
                  "date_effet"
                ],
                "properties": {
                  "producteur_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "parcelle_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "zone_cueillette_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "referentiel_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "etat": {
                    "pattern": "^[a-z][a-z0-9_]*$",
                    "type": "string"
                  },
                  "debut_conversion": {
                    "format": "date",
                    "type": "string"
                  },
                  "date_eligibilite": {
                    "format": "date",
                    "type": "string"
                  },
                  "date_effet": {
                    "format": "date",
                    "type": "string"
                  },
                  "reference_decision": {
                    "minLength": 1,
                    "maxLength": 300,
                    "type": "string"
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "La ligne d'historique est ajoutée.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unité inconnue (`unite_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Statut refusé par la base, par exemple révision sans motif (`statut_refuse`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/conformite/portee": {
      "get": {
        "operationId": "porteeConformite",
        "summary": "Écarts de portée des certificats par référentiel coché, à une date",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Pour chaque référentiel actif, les activités déclarées que la portée des certificats en vigueur ne couvre pas (AM-07), et les certificats en vigueur sans portée renseignée.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "date_reference",
                    "referentiels"
                  ],
                  "properties": {
                    "date_reference": {
                      "format": "date",
                      "type": "string"
                    },
                    "referentiels": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle_fr",
                          "libelle_en",
                          "certificats_en_vigueur",
                          "sans_portee",
                          "ecarts"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "certificats_en_vigueur": {
                            "minimum": 0,
                            "type": "integer"
                          },
                          "sans_portee": {
                            "type": "array",
                            "items": {
                              "description": "Numéro d'un certificat en vigueur dont la portée n'est pas renseignée.",
                              "type": "string"
                            }
                          },
                          "ecarts": {
                            "description": "Activités déclarées que la portée des certificats en vigueur ne couvre pas (`ecartsDePortee` du domaine).",
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "activite",
                                "site",
                                "raison"
                              ],
                              "properties": {
                                "activite": {
                                  "additionalProperties": false,
                                  "type": "object",
                                  "required": [
                                    "code",
                                    "libelle_fr",
                                    "libelle_en"
                                  ],
                                  "properties": {
                                    "code": {
                                      "type": "string"
                                    },
                                    "libelle_fr": {
                                      "type": "string"
                                    },
                                    "libelle_en": {
                                      "type": "string"
                                    }
                                  }
                                },
                                "site": {
                                  "anyOf": [
                                    {
                                      "type": "null"
                                    },
                                    {
                                      "additionalProperties": false,
                                      "type": "object",
                                      "required": [
                                        "code",
                                        "nom"
                                      ],
                                      "properties": {
                                        "code": {
                                          "type": "string"
                                        },
                                        "nom": {
                                          "type": "string"
                                        }
                                      }
                                    }
                                  ]
                                },
                                "raison": {
                                  "anyOf": [
                                    {
                                      "const": "activite_hors_portee",
                                      "type": "string"
                                    },
                                    {
                                      "const": "activite_exclue",
                                      "type": "string"
                                    },
                                    {
                                      "const": "site_hors_portee",
                                      "type": "string"
                                    }
                                  ]
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Date invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/conformite/grille": {
      "get": {
        "operationId": "lireGrille",
        "summary": "Grille de conformité des référentiels cochés : statut de chaque point et synthèse « prêt pour l'audit »",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Pour chaque référentiel actif, les points de la dernière version publiée de sa grille avec leur statut (satisfait, preuve manquante, écart ouvert, à vérifier, non applicable) calculé à la date, et la synthèse par référentiel et par thème. Lecture seule : aucune évaluation n'est écrite.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "date_reference",
                    "referentiels",
                    "synthese"
                  ],
                  "properties": {
                    "date_reference": {
                      "format": "date",
                      "type": "string"
                    },
                    "referentiels": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle_fr",
                          "libelle_en",
                          "pack_version",
                          "points"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "pack_version": {
                            "description": "Version du pack qui publie la grille ; vide : le référentiel n'a pas de grille publiée.",
                            "anyOf": [
                              {
                                "type": "null"
                              },
                              {
                                "type": "string"
                              }
                            ]
                          },
                          "points": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "code",
                                "libelle_fr",
                                "libelle_en",
                                "theme",
                                "source",
                                "mode",
                                "objet",
                                "preuve_attendue",
                                "echeance",
                                "activites",
                                "statut",
                                "cause_non_applicable",
                                "preuves",
                                "declaration"
                              ],
                              "properties": {
                                "code": {
                                  "type": "string"
                                },
                                "libelle_fr": {
                                  "type": "string"
                                },
                                "libelle_en": {
                                  "type": "string"
                                },
                                "theme": {
                                  "type": "string"
                                },
                                "source": {
                                  "type": "string"
                                },
                                "mode": {
                                  "anyOf": [
                                    {
                                      "const": "automatique",
                                      "type": "string"
                                    },
                                    {
                                      "const": "manuel",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "objet": {
                                  "type": "string"
                                },
                                "preuve_attendue": {
                                  "anyOf": [
                                    {
                                      "type": "null"
                                    },
                                    {
                                      "type": "string"
                                    }
                                  ]
                                },
                                "echeance": {
                                  "anyOf": [
                                    {
                                      "type": "null"
                                    },
                                    {
                                      "type": "string"
                                    }
                                  ]
                                },
                                "activites": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                },
                                "statut": {
                                  "anyOf": [
                                    {
                                      "const": "satisfait",
                                      "type": "string"
                                    },
                                    {
                                      "const": "preuve_manquante",
                                      "type": "string"
                                    },
                                    {
                                      "const": "ecart_ouvert",
                                      "type": "string"
                                    },
                                    {
                                      "const": "a_verifier",
                                      "type": "string"
                                    },
                                    {
                                      "const": "non_applicable",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "cause_non_applicable": {
                                  "anyOf": [
                                    {
                                      "type": "null"
                                    },
                                    {
                                      "const": "hors_dates",
                                      "type": "string"
                                    },
                                    {
                                      "const": "module_inactif",
                                      "type": "string"
                                    },
                                    {
                                      "const": "activite_non_exercee",
                                      "type": "string"
                                    },
                                    {
                                      "const": "declare",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "preuves": {
                                  "minimum": 0,
                                  "description": "Pièces liées au point.",
                                  "type": "integer"
                                },
                                "declaration": {
                                  "anyOf": [
                                    {
                                      "type": "null"
                                    },
                                    {
                                      "additionalProperties": false,
                                      "type": "object",
                                      "required": [
                                        "statut",
                                        "motif",
                                        "par",
                                        "le"
                                      ],
                                      "properties": {
                                        "statut": {
                                          "type": "string"
                                        },
                                        "motif": {
                                          "anyOf": [
                                            {
                                              "type": "null"
                                            },
                                            {
                                              "type": "string"
                                            }
                                          ]
                                        },
                                        "par": {
                                          "anyOf": [
                                            {
                                              "type": "null"
                                            },
                                            {
                                              "type": "string"
                                            }
                                          ]
                                        },
                                        "le": {
                                          "format": "date-time",
                                          "type": "string"
                                        }
                                      }
                                    }
                                  ]
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "synthese": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "referentiel",
                          "theme",
                          "decompte",
                          "applicables",
                          "satisfaits_cp"
                        ],
                        "properties": {
                          "referentiel": {
                            "type": "string"
                          },
                          "theme": {
                            "description": "Vide : total du référentiel.",
                            "anyOf": [
                              {
                                "type": "null"
                              },
                              {
                                "type": "string"
                              }
                            ]
                          },
                          "decompte": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "satisfait",
                              "preuve_manquante",
                              "ecart_ouvert",
                              "a_verifier",
                              "non_applicable"
                            ],
                            "properties": {
                              "satisfait": {
                                "minimum": 0,
                                "type": "integer"
                              },
                              "preuve_manquante": {
                                "minimum": 0,
                                "type": "integer"
                              },
                              "ecart_ouvert": {
                                "minimum": 0,
                                "type": "integer"
                              },
                              "a_verifier": {
                                "minimum": 0,
                                "type": "integer"
                              },
                              "non_applicable": {
                                "minimum": 0,
                                "type": "integer"
                              }
                            }
                          },
                          "applicables": {
                            "minimum": 0,
                            "type": "integer"
                          },
                          "satisfaits_cp": {
                            "description": "Part des points satisfaits parmi les applicables, en centièmes de point.",
                            "anyOf": [
                              {
                                "type": "null"
                              },
                              {
                                "minimum": 0,
                                "maximum": 10000,
                                "type": "integer"
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Date invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/conformite/grille/evaluer": {
      "post": {
        "operationId": "evaluerGrille",
        "summary": "Enregistrer l'évaluation des points automatiques et ouvrir les constats d'écart (`review.resolve`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Une évaluation est écrite par point automatique applicable ; un constat d'écart est ouvert pour un écart qui n'a pas déjà un constat ouvert.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "date_reference",
                    "evaluations_ecrites",
                    "constats_ouverts"
                  ],
                  "properties": {
                    "date_reference": {
                      "format": "date",
                      "type": "string"
                    },
                    "evaluations_ecrites": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "constats_ouverts": {
                      "minimum": 0,
                      "description": "Constats d'écart écrits ; un écart déjà constaté et encore ouvert n'en écrit pas un second.",
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Date invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/conformite/evaluations": {
      "post": {
        "operationId": "declarerPoint",
        "summary": "Déclarer le statut d'un point manuel, avec motif (`review.resolve`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "referentiel",
                  "point",
                  "statut"
                ],
                "properties": {
                  "referentiel": {
                    "minLength": 1,
                    "type": "string"
                  },
                  "point": {
                    "minLength": 1,
                    "type": "string"
                  },
                  "statut": {
                    "anyOf": [
                      {
                        "const": "satisfait",
                        "type": "string"
                      },
                      {
                        "const": "ecart_ouvert",
                        "type": "string"
                      },
                      {
                        "const": "a_verifier",
                        "type": "string"
                      },
                      {
                        "const": "non_applicable",
                        "type": "string"
                      }
                    ]
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Obligatoire pour « satisfait » et « non applicable ».",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Évaluation enregistrée (ajout seul) ; elle fait foi jusqu'à la suivante.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "statut",
                    "evalue_le"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "satisfait",
                          "type": "string"
                        },
                        {
                          "const": "preuve_manquante",
                          "type": "string"
                        },
                        {
                          "const": "ecart_ouvert",
                          "type": "string"
                        },
                        {
                          "const": "a_verifier",
                          "type": "string"
                        },
                        {
                          "const": "non_applicable",
                          "type": "string"
                        }
                      ]
                    },
                    "evalue_le": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide, motif manquant pour « satisfait » ou « non applicable » (`motif_requis`), ou point automatique (`point_automatique`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Référentiel ou point inconnu dans l'organisation active (`referentiel_inconnu`, `point_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/conformite/preuves": {
      "post": {
        "operationId": "lierPreuve",
        "summary": "Lier une pièce déjà déposée à un point de contrôle (`review.resolve`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "referentiel",
                  "point",
                  "fichier_id"
                ],
                "properties": {
                  "referentiel": {
                    "minLength": 1,
                    "type": "string"
                  },
                  "point": {
                    "minLength": 1,
                    "type": "string"
                  },
                  "fichier_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Pièce liée au point (ajout seul).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "cree_le"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Référentiel, point ou fichier inconnu dans l'organisation active (`referentiel_inconnu`, `point_inconnu`, `fichier_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/conformite/verdict": {
      "get": {
        "operationId": "verdictConformite",
        "summary": "Une unité peut-elle revendiquer un référentiel à une date ?",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "referentiel",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "producteur",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "parcelle",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "date",
            "in": "query",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Le verdict du domaine (`peutRevendiquer`) : statut de l'unité à la date et certificat en vigueur du groupement ou de l'opérateur.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "date_reference",
                    "peut",
                    "raison",
                    "vendable_sous",
                    "etat",
                    "certificats"
                  ],
                  "properties": {
                    "date_reference": {
                      "format": "date",
                      "type": "string"
                    },
                    "peut": {
                      "type": "boolean"
                    },
                    "raison": {
                      "description": "Raison du refus (`statut_inconnu`, `statut_hors_qualite`, `etat_non_revendicable`, `certificat_expire`…), si elle ne le peut pas.",
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "vendable_sous": {
                      "description": "État sous lequel l'unité reste vendable quand elle ne peut pas revendiquer.",
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "code",
                            "libelle_fr",
                            "libelle_en",
                            "categorie"
                          ],
                          "properties": {
                            "code": {
                              "type": "string"
                            },
                            "libelle_fr": {
                              "type": "string"
                            },
                            "libelle_en": {
                              "type": "string"
                            },
                            "categorie": {
                              "anyOf": [
                                {
                                  "const": "bio",
                                  "type": "string"
                                },
                                {
                                  "const": "conversion",
                                  "type": "string"
                                },
                                {
                                  "const": "conventionnel",
                                  "type": "string"
                                },
                                {
                                  "const": "hors_statut",
                                  "type": "string"
                                }
                              ]
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "etat": {
                      "description": "Statut de conformité de l'unité à la date, tel que le référentiel le définit ; revendiqué si `peut`.",
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "code",
                            "libelle_fr",
                            "libelle_en",
                            "categorie"
                          ],
                          "properties": {
                            "code": {
                              "type": "string"
                            },
                            "libelle_fr": {
                              "type": "string"
                            },
                            "libelle_en": {
                              "type": "string"
                            },
                            "categorie": {
                              "anyOf": [
                                {
                                  "const": "bio",
                                  "type": "string"
                                },
                                {
                                  "const": "conversion",
                                  "type": "string"
                                },
                                {
                                  "const": "conventionnel",
                                  "type": "string"
                                },
                                {
                                  "const": "hors_statut",
                                  "type": "string"
                                }
                              ]
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "certificats": {
                      "minimum": 0,
                      "description": "Certificats du groupement et de l'opérateur pour ce référentiel.",
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre manquant ou invalide : une seule unité (`producteur` ou `parcelle`) est attendue (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Référentiel ou unité inconnu (`referentiel_inconnu`, `unite_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/contrats": {
      "get": {
        "operationId": "listerContrats",
        "summary": "Contrats de l'organisation active, avec leur valeur engagée par devise",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "campagne",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "statut",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Contrats par code.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "contrats"
                  ],
                  "properties": {
                    "contrats": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "type",
                          "statut",
                          "contrepartie",
                          "campagne_code",
                          "date_debut",
                          "date_fin",
                          "lignes",
                          "valeur_engagee"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "type": {
                            "anyOf": [
                              {
                                "const": "achat",
                                "type": "string"
                              },
                              {
                                "const": "vente",
                                "type": "string"
                              },
                              {
                                "const": "prestation",
                                "type": "string"
                              }
                            ]
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "brouillon",
                                "type": "string"
                              },
                              {
                                "const": "actif",
                                "type": "string"
                              },
                              {
                                "const": "solde",
                                "type": "string"
                              },
                              {
                                "const": "resilie",
                                "type": "string"
                              }
                            ]
                          },
                          "contrepartie": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "type",
                              "code",
                              "nom"
                            ],
                            "properties": {
                              "type": {
                                "anyOf": [
                                  {
                                    "const": "producteur",
                                    "type": "string"
                                  },
                                  {
                                    "const": "groupement",
                                    "type": "string"
                                  },
                                  {
                                    "const": "fournisseur",
                                    "type": "string"
                                  },
                                  {
                                    "const": "client",
                                    "type": "string"
                                  }
                                ]
                              },
                              "code": {
                                "type": "string"
                              },
                              "nom": {
                                "type": "string"
                              }
                            }
                          },
                          "campagne_code": {
                            "type": "string"
                          },
                          "date_debut": {
                            "format": "date",
                            "type": "string"
                          },
                          "date_fin": {
                            "format": "date",
                            "type": "string"
                          },
                          "lignes": {
                            "minimum": 0,
                            "type": "integer"
                          },
                          "valeur_engagee": {
                            "description": "Par devise : somme des lignes au prix de base, hors primes, un arrondi par ligne (`valeurLigne`).",
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "devise",
                                "valeur"
                              ],
                              "properties": {
                                "devise": {
                                  "pattern": "^[A-Z]{3}$",
                                  "type": "string"
                                },
                                "valeur": {
                                  "description": "Unités mineures de la devise.",
                                  "type": "integer"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "creerContrat",
        "summary": "Créer un contrat en brouillon, avec ses lignes et ses primes (`contracts.manage`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "code",
                  "type",
                  "campagne_id",
                  "date_debut",
                  "date_fin",
                  "lignes"
                ],
                "properties": {
                  "code": {
                    "minLength": 1,
                    "maxLength": 40,
                    "type": "string"
                  },
                  "type": {
                    "anyOf": [
                      {
                        "const": "achat",
                        "type": "string"
                      },
                      {
                        "const": "vente",
                        "type": "string"
                      },
                      {
                        "const": "prestation",
                        "type": "string"
                      }
                    ]
                  },
                  "producteur_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "groupement_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "fournisseur_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "client_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "campagne_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "date_debut": {
                    "format": "date",
                    "type": "string"
                  },
                  "date_fin": {
                    "format": "date",
                    "type": "string"
                  },
                  "conditions_paiement": {
                    "minLength": 1,
                    "maxLength": 300,
                    "type": "string"
                  },
                  "fichier_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "lignes": {
                    "minItems": 1,
                    "type": "array",
                    "items": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "produit_id",
                        "quantite_engagee_g",
                        "prix_unite_mineure",
                        "devise",
                        "unite_prix"
                      ],
                      "properties": {
                        "produit_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "quantite_engagee_g": {
                          "minimum": 1,
                          "type": "integer"
                        },
                        "prix_unite_mineure": {
                          "minimum": 0,
                          "type": "integer"
                        },
                        "devise": {
                          "pattern": "^[A-Z]{3}$",
                          "type": "string"
                        },
                        "unite_prix": {
                          "pattern": "^[a-z]+$",
                          "type": "string"
                        },
                        "tolerance_cp": {
                          "minimum": 0,
                          "maximum": 10000,
                          "type": "integer"
                        },
                        "formule_refaction": {
                          "anyOf": [
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "type"
                              ],
                              "properties": {
                                "type": {
                                  "const": "aucune",
                                  "type": "string"
                                }
                              }
                            },
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "type",
                                "humidite_max_cp",
                                "impuretes_max_cp"
                              ],
                              "properties": {
                                "type": {
                                  "const": "excedent_lineaire",
                                  "type": "string"
                                },
                                "humidite_max_cp": {
                                  "minimum": 0,
                                  "maximum": 10000,
                                  "type": "integer"
                                },
                                "impuretes_max_cp": {
                                  "minimum": 0,
                                  "maximum": 10000,
                                  "type": "integer"
                                },
                                "arrondi": {
                                  "anyOf": [
                                    {
                                      "const": "plus_proche",
                                      "type": "string"
                                    },
                                    {
                                      "const": "inferieur",
                                      "type": "string"
                                    },
                                    {
                                      "const": "superieur",
                                      "type": "string"
                                    }
                                  ]
                                }
                              }
                            },
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "type",
                                "humidite_norme_cp"
                              ],
                              "properties": {
                                "type": {
                                  "const": "lineaire_simple",
                                  "type": "string"
                                },
                                "humidite_norme_cp": {
                                  "minimum": 0,
                                  "maximum": 9999,
                                  "type": "integer"
                                },
                                "arrondi": {
                                  "anyOf": [
                                    {
                                      "const": "plus_proche",
                                      "type": "string"
                                    },
                                    {
                                      "const": "inferieur",
                                      "type": "string"
                                    },
                                    {
                                      "const": "superieur",
                                      "type": "string"
                                    }
                                  ]
                                }
                              }
                            },
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "type",
                                "humidite_norme_cp"
                              ],
                              "properties": {
                                "type": {
                                  "const": "bilan_de_masse",
                                  "type": "string"
                                },
                                "humidite_norme_cp": {
                                  "minimum": 0,
                                  "maximum": 9999,
                                  "type": "integer"
                                },
                                "arrondi": {
                                  "anyOf": [
                                    {
                                      "const": "plus_proche",
                                      "type": "string"
                                    },
                                    {
                                      "const": "inferieur",
                                      "type": "string"
                                    },
                                    {
                                      "const": "superieur",
                                      "type": "string"
                                    }
                                  ]
                                }
                              }
                            }
                          ]
                        },
                        "primes": {
                          "type": "array",
                          "items": {
                            "anyOf": [
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "type",
                                  "mode",
                                  "montant_unite_mineure"
                                ],
                                "properties": {
                                  "type": {
                                    "anyOf": [
                                      {
                                        "const": "bio",
                                        "type": "string"
                                      },
                                      {
                                        "const": "equitable",
                                        "type": "string"
                                      },
                                      {
                                        "const": "qualite",
                                        "type": "string"
                                      }
                                    ]
                                  },
                                  "mode": {
                                    "const": "montant",
                                    "type": "string"
                                  },
                                  "montant_unite_mineure": {
                                    "minimum": 0,
                                    "type": "integer"
                                  }
                                }
                              },
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "type",
                                  "mode",
                                  "taux_cp"
                                ],
                                "properties": {
                                  "type": {
                                    "anyOf": [
                                      {
                                        "const": "bio",
                                        "type": "string"
                                      },
                                      {
                                        "const": "equitable",
                                        "type": "string"
                                      },
                                      {
                                        "const": "qualite",
                                        "type": "string"
                                      }
                                    ]
                                  },
                                  "mode": {
                                    "const": "taux",
                                    "type": "string"
                                  },
                                  "taux_cp": {
                                    "minimum": 0,
                                    "maximum": 10000,
                                    "type": "integer"
                                  }
                                }
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Le contrat est créé en brouillon.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "contrat_id",
                    "lignes"
                  ],
                  "properties": {
                    "contrat_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "lignes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "produit_id",
                          "ligne_id"
                        ],
                        "properties": {
                          "produit_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "ligne_id": {
                            "format": "uuid",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Contrepartie, type, campagne ou dates refusés par la base (`contrat_refuse`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/contrats/{id}": {
      "get": {
        "operationId": "lireContrat",
        "summary": "Contrat : lignes, primes, formule de réfaction",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Le contrat et le détail de ses lignes.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "type",
                    "statut",
                    "contrepartie",
                    "campagne_code",
                    "date_debut",
                    "date_fin",
                    "lignes",
                    "valeur_engagee",
                    "conditions_paiement",
                    "a_pdf",
                    "detail_lignes"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "type": {
                      "anyOf": [
                        {
                          "const": "achat",
                          "type": "string"
                        },
                        {
                          "const": "vente",
                          "type": "string"
                        },
                        {
                          "const": "prestation",
                          "type": "string"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "solde",
                          "type": "string"
                        },
                        {
                          "const": "resilie",
                          "type": "string"
                        }
                      ]
                    },
                    "contrepartie": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "type",
                        "code",
                        "nom"
                      ],
                      "properties": {
                        "type": {
                          "anyOf": [
                            {
                              "const": "producteur",
                              "type": "string"
                            },
                            {
                              "const": "groupement",
                              "type": "string"
                            },
                            {
                              "const": "fournisseur",
                              "type": "string"
                            },
                            {
                              "const": "client",
                              "type": "string"
                            }
                          ]
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom": {
                          "type": "string"
                        }
                      }
                    },
                    "campagne_code": {
                      "type": "string"
                    },
                    "date_debut": {
                      "format": "date",
                      "type": "string"
                    },
                    "date_fin": {
                      "format": "date",
                      "type": "string"
                    },
                    "lignes": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "valeur_engagee": {
                      "description": "Par devise : somme des lignes au prix de base, hors primes, un arrondi par ligne (`valeurLigne`).",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "devise",
                          "valeur"
                        ],
                        "properties": {
                          "devise": {
                            "pattern": "^[A-Z]{3}$",
                            "type": "string"
                          },
                          "valeur": {
                            "description": "Unités mineures de la devise.",
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "conditions_paiement": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "a_pdf": {
                      "type": "boolean"
                    },
                    "detail_lignes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "produit",
                          "quantite_engagee_g",
                          "prix_unite_mineure",
                          "devise",
                          "unite_prix",
                          "tolerance_cp",
                          "formule",
                          "valeur_engagee",
                          "primes"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "produit": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "code",
                              "nom_fr",
                              "nom_en"
                            ],
                            "properties": {
                              "code": {
                                "type": "string"
                              },
                              "nom_fr": {
                                "type": "string"
                              },
                              "nom_en": {
                                "type": "string"
                              }
                            }
                          },
                          "quantite_engagee_g": {
                            "minimum": 1,
                            "type": "integer"
                          },
                          "prix_unite_mineure": {
                            "minimum": 0,
                            "type": "integer"
                          },
                          "devise": {
                            "type": "string"
                          },
                          "unite_prix": {
                            "type": "string"
                          },
                          "tolerance_cp": {
                            "minimum": 0,
                            "maximum": 10000,
                            "type": "integer"
                          },
                          "formule": {
                            "description": "Formule de réfaction ; nulle si celle qui est stockée ne passe pas le schéma (jamais devinée).",
                            "anyOf": [
                              {
                                "anyOf": [
                                  {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "type"
                                    ],
                                    "properties": {
                                      "type": {
                                        "const": "aucune",
                                        "type": "string"
                                      }
                                    }
                                  },
                                  {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "type",
                                      "humidite_max_cp",
                                      "impuretes_max_cp",
                                      "arrondi"
                                    ],
                                    "properties": {
                                      "type": {
                                        "const": "excedent_lineaire",
                                        "type": "string"
                                      },
                                      "humidite_max_cp": {
                                        "minimum": 0,
                                        "maximum": 10000,
                                        "type": "integer"
                                      },
                                      "impuretes_max_cp": {
                                        "minimum": 0,
                                        "maximum": 10000,
                                        "type": "integer"
                                      },
                                      "arrondi": {
                                        "anyOf": [
                                          {
                                            "const": "plus_proche",
                                            "type": "string"
                                          },
                                          {
                                            "const": "inferieur",
                                            "type": "string"
                                          },
                                          {
                                            "const": "superieur",
                                            "type": "string"
                                          }
                                        ]
                                      }
                                    }
                                  },
                                  {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "type",
                                      "humidite_norme_cp",
                                      "arrondi"
                                    ],
                                    "properties": {
                                      "type": {
                                        "const": "lineaire_simple",
                                        "type": "string"
                                      },
                                      "humidite_norme_cp": {
                                        "minimum": 0,
                                        "maximum": 9999,
                                        "type": "integer"
                                      },
                                      "arrondi": {
                                        "anyOf": [
                                          {
                                            "const": "plus_proche",
                                            "type": "string"
                                          },
                                          {
                                            "const": "inferieur",
                                            "type": "string"
                                          },
                                          {
                                            "const": "superieur",
                                            "type": "string"
                                          }
                                        ]
                                      }
                                    }
                                  },
                                  {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "type",
                                      "humidite_norme_cp",
                                      "arrondi"
                                    ],
                                    "properties": {
                                      "type": {
                                        "const": "bilan_de_masse",
                                        "type": "string"
                                      },
                                      "humidite_norme_cp": {
                                        "minimum": 0,
                                        "maximum": 9999,
                                        "type": "integer"
                                      },
                                      "arrondi": {
                                        "anyOf": [
                                          {
                                            "const": "plus_proche",
                                            "type": "string"
                                          },
                                          {
                                            "const": "inferieur",
                                            "type": "string"
                                          },
                                          {
                                            "const": "superieur",
                                            "type": "string"
                                          }
                                        ]
                                      }
                                    }
                                  }
                                ]
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "valeur_engagee": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "devise",
                              "valeur"
                            ],
                            "properties": {
                              "devise": {
                                "pattern": "^[A-Z]{3}$",
                                "type": "string"
                              },
                              "valeur": {
                                "description": "Unités mineures de la devise.",
                                "type": "integer"
                              }
                            }
                          },
                          "primes": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "type",
                                "mode",
                                "montant_unite_mineure",
                                "devise",
                                "taux_cp"
                              ],
                              "properties": {
                                "type": {
                                  "anyOf": [
                                    {
                                      "const": "bio",
                                      "type": "string"
                                    },
                                    {
                                      "const": "equitable",
                                      "type": "string"
                                    },
                                    {
                                      "const": "qualite",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "mode": {
                                  "anyOf": [
                                    {
                                      "const": "montant",
                                      "type": "string"
                                    },
                                    {
                                      "const": "taux",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "montant_unite_mineure": {
                                  "anyOf": [
                                    {
                                      "type": "integer"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "devise": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "taux_cp": {
                                  "anyOf": [
                                    {
                                      "type": "integer"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Contrat inconnu dans l'organisation active (`contrat_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/capacites": {
      "get": {
        "operationId": "listerCapacites",
        "summary": "Capacités de la campagne : version courante par cible, circuit de validation et solde",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "campagne",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "etat",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "La version la plus récente de chaque (cible, campagne), par code de cible. La capacité est calculée par la base.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "seuil_alerte_cp",
                    "capacites"
                  ],
                  "properties": {
                    "seuil_alerte_cp": {
                      "type": "integer"
                    },
                    "capacites": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "version",
                          "versions_precedentes",
                          "campagne_code",
                          "cible",
                          "producteur",
                          "groupement_code",
                          "surface_mesuree_m2",
                          "rendement_g_ha",
                          "rendement_motif",
                          "capacite_g",
                          "auteur",
                          "cree_le",
                          "etat",
                          "applicable",
                          "validations",
                          "solde"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "version": {
                            "minimum": 1,
                            "type": "integer"
                          },
                          "versions_precedentes": {
                            "minimum": 0,
                            "description": "Nombre de versions antérieures de cette capacité pour la cible et la campagne (ajout seul).",
                            "type": "integer"
                          },
                          "campagne_code": {
                            "type": "string"
                          },
                          "cible": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "type",
                              "code"
                            ],
                            "properties": {
                              "type": {
                                "anyOf": [
                                  {
                                    "const": "parcelle",
                                    "type": "string"
                                  },
                                  {
                                    "const": "zone_cueillette",
                                    "type": "string"
                                  }
                                ]
                              },
                              "code": {
                                "type": "string"
                              }
                            }
                          },
                          "producteur": {
                            "anyOf": [
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "code",
                                  "nom_complet"
                                ],
                                "properties": {
                                  "code": {
                                    "type": "string"
                                  },
                                  "nom_complet": {
                                    "type": "string"
                                  }
                                }
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "groupement_code": {
                            "type": "string"
                          },
                          "surface_mesuree_m2": {
                            "type": "integer"
                          },
                          "rendement_g_ha": {
                            "type": "integer"
                          },
                          "rendement_motif": {
                            "description": "Motif de la dernière révision du rendement connue à la création de la capacité (RG-023).",
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "capacite_g": {
                            "description": "Calculée par la base : surface mesurée × rendement. Jamais saisie.",
                            "type": "integer"
                          },
                          "auteur": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "nom_affiche"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "nom_affiche": {
                                "type": "string"
                              }
                            }
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "etat": {
                            "description": "Décidé par la base (`etat_validation_capacite`).",
                            "anyOf": [
                              {
                                "const": "en_attente",
                                "type": "string"
                              },
                              {
                                "const": "validee",
                                "type": "string"
                              },
                              {
                                "const": "refusee",
                                "type": "string"
                              }
                            ]
                          },
                          "applicable": {
                            "description": "Vrai si cette version est la capacité applicable : validée, sur le polygone en vigueur, cible éligible, producteur hors contrôle (EC-012).",
                            "type": "boolean"
                          },
                          "validations": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "role",
                                "decision",
                                "validateur",
                                "commentaire",
                                "cree_le"
                              ],
                              "properties": {
                                "role": {
                                  "anyOf": [
                                    {
                                      "const": "direction",
                                      "type": "string"
                                    },
                                    {
                                      "const": "rsci",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "decision": {
                                  "anyOf": [
                                    {
                                      "const": "approuve",
                                      "type": "string"
                                    },
                                    {
                                      "const": "refuse",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "validateur": {
                                  "additionalProperties": false,
                                  "type": "object",
                                  "required": [
                                    "id",
                                    "nom_affiche"
                                  ],
                                  "properties": {
                                    "id": {
                                      "format": "uuid",
                                      "type": "string"
                                    },
                                    "nom_affiche": {
                                      "type": "string"
                                    }
                                  }
                                },
                                "commentaire": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "cree_le": {
                                  "format": "date-time",
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "solde": {
                            "description": "Absent tant que la capacité n'est pas validée.",
                            "anyOf": [
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "consomme_g",
                                  "reste_g",
                                  "taux_cp",
                                  "niveau"
                                ],
                                "properties": {
                                  "consomme_g": {
                                    "type": "integer"
                                  },
                                  "reste_g": {
                                    "description": "Négatif en cas de dépassement : jamais masqué (RG-022).",
                                    "type": "integer"
                                  },
                                  "taux_cp": {
                                    "description": "Consommé sur capacité, en centièmes de point.",
                                    "type": "integer"
                                  },
                                  "niveau": {
                                    "anyOf": [
                                      {
                                        "const": "normal",
                                        "type": "string"
                                      },
                                      {
                                        "const": "seuil",
                                        "type": "string"
                                      },
                                      {
                                        "const": "depassement",
                                        "type": "string"
                                      }
                                    ]
                                  }
                                }
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Campagne absente ou état inconnu (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Campagne inconnue (`campagne_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "proposerCapacite",
        "summary": "Proposer une capacité : la base la calcule (surface mesurée × rendement), la validation reste à `capacity.approve`",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "campagne_id"
                ],
                "properties": {
                  "parcelle_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "zone_cueillette_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "campagne_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "La capacité proposée, en attente de validation.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "version",
                    "versions_precedentes",
                    "campagne_code",
                    "cible",
                    "producteur",
                    "groupement_code",
                    "surface_mesuree_m2",
                    "rendement_g_ha",
                    "rendement_motif",
                    "capacite_g",
                    "auteur",
                    "cree_le",
                    "etat",
                    "applicable",
                    "validations",
                    "solde"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "version": {
                      "minimum": 1,
                      "type": "integer"
                    },
                    "versions_precedentes": {
                      "minimum": 0,
                      "description": "Nombre de versions antérieures de cette capacité pour la cible et la campagne (ajout seul).",
                      "type": "integer"
                    },
                    "campagne_code": {
                      "type": "string"
                    },
                    "cible": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "type",
                        "code"
                      ],
                      "properties": {
                        "type": {
                          "anyOf": [
                            {
                              "const": "parcelle",
                              "type": "string"
                            },
                            {
                              "const": "zone_cueillette",
                              "type": "string"
                            }
                          ]
                        },
                        "code": {
                          "type": "string"
                        }
                      }
                    },
                    "producteur": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "code",
                            "nom_complet"
                          ],
                          "properties": {
                            "code": {
                              "type": "string"
                            },
                            "nom_complet": {
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "groupement_code": {
                      "type": "string"
                    },
                    "surface_mesuree_m2": {
                      "type": "integer"
                    },
                    "rendement_g_ha": {
                      "type": "integer"
                    },
                    "rendement_motif": {
                      "description": "Motif de la dernière révision du rendement connue à la création de la capacité (RG-023).",
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "capacite_g": {
                      "description": "Calculée par la base : surface mesurée × rendement. Jamais saisie.",
                      "type": "integer"
                    },
                    "auteur": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "nom_affiche"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "nom_affiche": {
                          "type": "string"
                        }
                      }
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "etat": {
                      "description": "Décidé par la base (`etat_validation_capacite`).",
                      "anyOf": [
                        {
                          "const": "en_attente",
                          "type": "string"
                        },
                        {
                          "const": "validee",
                          "type": "string"
                        },
                        {
                          "const": "refusee",
                          "type": "string"
                        }
                      ]
                    },
                    "applicable": {
                      "description": "Vrai si cette version est la capacité applicable : validée, sur le polygone en vigueur, cible éligible, producteur hors contrôle (EC-012).",
                      "type": "boolean"
                    },
                    "validations": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "role",
                          "decision",
                          "validateur",
                          "commentaire",
                          "cree_le"
                        ],
                        "properties": {
                          "role": {
                            "anyOf": [
                              {
                                "const": "direction",
                                "type": "string"
                              },
                              {
                                "const": "rsci",
                                "type": "string"
                              }
                            ]
                          },
                          "decision": {
                            "anyOf": [
                              {
                                "const": "approuve",
                                "type": "string"
                              },
                              {
                                "const": "refuse",
                                "type": "string"
                              }
                            ]
                          },
                          "validateur": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "nom_affiche"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "nom_affiche": {
                                "type": "string"
                              }
                            }
                          },
                          "commentaire": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    },
                    "solde": {
                      "description": "Absent tant que la capacité n'est pas validée.",
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "consomme_g",
                            "reste_g",
                            "taux_cp",
                            "niveau"
                          ],
                          "properties": {
                            "consomme_g": {
                              "type": "integer"
                            },
                            "reste_g": {
                              "description": "Négatif en cas de dépassement : jamais masqué (RG-022).",
                              "type": "integer"
                            },
                            "taux_cp": {
                              "description": "Consommé sur capacité, en centièmes de point.",
                              "type": "integer"
                            },
                            "niveau": {
                              "anyOf": [
                                {
                                  "const": "normal",
                                  "type": "string"
                                },
                                {
                                  "const": "seuil",
                                  "type": "string"
                                },
                                {
                                  "const": "depassement",
                                  "type": "string"
                                }
                              ]
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide ou cible mal désignée (`corps_invalide`, `cible_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Cible ou campagne inconnue (`cible_introuvable`, `campagne_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Cible non éligible (AV1-01) : `polygone_absent`, `polygone_invalide`, `chevauchement_non_leve`, `producteur_en_controle`, `rendement_inconnu`, `campagne_cloturee` ; module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/capacites/{id}/validations": {
      "post": {
        "operationId": "validerCapacite",
        "summary": "Valider ou refuser une capacité sous un rôle, direction ou RSCI (`capacity.approve`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "role",
                  "decision"
                ],
                "properties": {
                  "role": {
                    "anyOf": [
                      {
                        "const": "direction",
                        "type": "string"
                      },
                      {
                        "const": "rsci",
                        "type": "string"
                      }
                    ]
                  },
                  "decision": {
                    "anyOf": [
                      {
                        "const": "approuve",
                        "type": "string"
                      },
                      {
                        "const": "refuse",
                        "type": "string"
                      }
                    ]
                  },
                  "commentaire": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "La capacité après la validation. Elle est validée quand la direction et le RSCI ont approuvé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "version",
                    "versions_precedentes",
                    "campagne_code",
                    "cible",
                    "producteur",
                    "groupement_code",
                    "surface_mesuree_m2",
                    "rendement_g_ha",
                    "rendement_motif",
                    "capacite_g",
                    "auteur",
                    "cree_le",
                    "etat",
                    "applicable",
                    "validations",
                    "solde"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "version": {
                      "minimum": 1,
                      "type": "integer"
                    },
                    "versions_precedentes": {
                      "minimum": 0,
                      "description": "Nombre de versions antérieures de cette capacité pour la cible et la campagne (ajout seul).",
                      "type": "integer"
                    },
                    "campagne_code": {
                      "type": "string"
                    },
                    "cible": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "type",
                        "code"
                      ],
                      "properties": {
                        "type": {
                          "anyOf": [
                            {
                              "const": "parcelle",
                              "type": "string"
                            },
                            {
                              "const": "zone_cueillette",
                              "type": "string"
                            }
                          ]
                        },
                        "code": {
                          "type": "string"
                        }
                      }
                    },
                    "producteur": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "code",
                            "nom_complet"
                          ],
                          "properties": {
                            "code": {
                              "type": "string"
                            },
                            "nom_complet": {
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "groupement_code": {
                      "type": "string"
                    },
                    "surface_mesuree_m2": {
                      "type": "integer"
                    },
                    "rendement_g_ha": {
                      "type": "integer"
                    },
                    "rendement_motif": {
                      "description": "Motif de la dernière révision du rendement connue à la création de la capacité (RG-023).",
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "capacite_g": {
                      "description": "Calculée par la base : surface mesurée × rendement. Jamais saisie.",
                      "type": "integer"
                    },
                    "auteur": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "nom_affiche"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "nom_affiche": {
                          "type": "string"
                        }
                      }
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "etat": {
                      "description": "Décidé par la base (`etat_validation_capacite`).",
                      "anyOf": [
                        {
                          "const": "en_attente",
                          "type": "string"
                        },
                        {
                          "const": "validee",
                          "type": "string"
                        },
                        {
                          "const": "refusee",
                          "type": "string"
                        }
                      ]
                    },
                    "applicable": {
                      "description": "Vrai si cette version est la capacité applicable : validée, sur le polygone en vigueur, cible éligible, producteur hors contrôle (EC-012).",
                      "type": "boolean"
                    },
                    "validations": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "role",
                          "decision",
                          "validateur",
                          "commentaire",
                          "cree_le"
                        ],
                        "properties": {
                          "role": {
                            "anyOf": [
                              {
                                "const": "direction",
                                "type": "string"
                              },
                              {
                                "const": "rsci",
                                "type": "string"
                              }
                            ]
                          },
                          "decision": {
                            "anyOf": [
                              {
                                "const": "approuve",
                                "type": "string"
                              },
                              {
                                "const": "refuse",
                                "type": "string"
                              }
                            ]
                          },
                          "validateur": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "nom_affiche"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "nom_affiche": {
                                "type": "string"
                              }
                            }
                          },
                          "commentaire": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    },
                    "solde": {
                      "description": "Absent tant que la capacité n'est pas validée.",
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "consomme_g",
                            "reste_g",
                            "taux_cp",
                            "niveau"
                          ],
                          "properties": {
                            "consomme_g": {
                              "type": "integer"
                            },
                            "reste_g": {
                              "description": "Négatif en cas de dépassement : jamais masqué (RG-022).",
                              "type": "integer"
                            },
                            "taux_cp": {
                              "description": "Consommé sur capacité, en centièmes de point.",
                              "type": "integer"
                            },
                            "niveau": {
                              "anyOf": [
                                {
                                  "const": "normal",
                                  "type": "string"
                                },
                                {
                                  "const": "seuil",
                                  "type": "string"
                                },
                                {
                                  "const": "depassement",
                                  "type": "string"
                                }
                              ]
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide, ou refus sans commentaire (`corps_invalide`, `commentaire_requis`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant, rôle non détenu ou séparation des tâches (`droit_manquant`, `role_non_detenu`, `permission_manquante`, `separation_des_taches`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Capacité inconnue (`capacite_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Ce rôle ou cette personne a déjà validé cette capacité (`validation_refusee`) ; module en lecture seule (`module_inactif`, `details.module`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/contrats/{id}/activer": {
      "post": {
        "operationId": "activerContrat",
        "summary": "Activer un contrat en brouillon (`contracts.manage`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Le contrat actif.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "type",
                    "statut",
                    "contrepartie",
                    "campagne_code",
                    "date_debut",
                    "date_fin",
                    "lignes",
                    "valeur_engagee",
                    "conditions_paiement",
                    "a_pdf",
                    "detail_lignes"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "type": {
                      "anyOf": [
                        {
                          "const": "achat",
                          "type": "string"
                        },
                        {
                          "const": "vente",
                          "type": "string"
                        },
                        {
                          "const": "prestation",
                          "type": "string"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "solde",
                          "type": "string"
                        },
                        {
                          "const": "resilie",
                          "type": "string"
                        }
                      ]
                    },
                    "contrepartie": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "type",
                        "code",
                        "nom"
                      ],
                      "properties": {
                        "type": {
                          "anyOf": [
                            {
                              "const": "producteur",
                              "type": "string"
                            },
                            {
                              "const": "groupement",
                              "type": "string"
                            },
                            {
                              "const": "fournisseur",
                              "type": "string"
                            },
                            {
                              "const": "client",
                              "type": "string"
                            }
                          ]
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom": {
                          "type": "string"
                        }
                      }
                    },
                    "campagne_code": {
                      "type": "string"
                    },
                    "date_debut": {
                      "format": "date",
                      "type": "string"
                    },
                    "date_fin": {
                      "format": "date",
                      "type": "string"
                    },
                    "lignes": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "valeur_engagee": {
                      "description": "Par devise : somme des lignes au prix de base, hors primes, un arrondi par ligne (`valeurLigne`).",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "devise",
                          "valeur"
                        ],
                        "properties": {
                          "devise": {
                            "pattern": "^[A-Z]{3}$",
                            "type": "string"
                          },
                          "valeur": {
                            "description": "Unités mineures de la devise.",
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "conditions_paiement": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "a_pdf": {
                      "type": "boolean"
                    },
                    "detail_lignes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "produit",
                          "quantite_engagee_g",
                          "prix_unite_mineure",
                          "devise",
                          "unite_prix",
                          "tolerance_cp",
                          "formule",
                          "valeur_engagee",
                          "primes"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "produit": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "code",
                              "nom_fr",
                              "nom_en"
                            ],
                            "properties": {
                              "code": {
                                "type": "string"
                              },
                              "nom_fr": {
                                "type": "string"
                              },
                              "nom_en": {
                                "type": "string"
                              }
                            }
                          },
                          "quantite_engagee_g": {
                            "minimum": 1,
                            "type": "integer"
                          },
                          "prix_unite_mineure": {
                            "minimum": 0,
                            "type": "integer"
                          },
                          "devise": {
                            "type": "string"
                          },
                          "unite_prix": {
                            "type": "string"
                          },
                          "tolerance_cp": {
                            "minimum": 0,
                            "maximum": 10000,
                            "type": "integer"
                          },
                          "formule": {
                            "description": "Formule de réfaction ; nulle si celle qui est stockée ne passe pas le schéma (jamais devinée).",
                            "anyOf": [
                              {
                                "anyOf": [
                                  {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "type"
                                    ],
                                    "properties": {
                                      "type": {
                                        "const": "aucune",
                                        "type": "string"
                                      }
                                    }
                                  },
                                  {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "type",
                                      "humidite_max_cp",
                                      "impuretes_max_cp",
                                      "arrondi"
                                    ],
                                    "properties": {
                                      "type": {
                                        "const": "excedent_lineaire",
                                        "type": "string"
                                      },
                                      "humidite_max_cp": {
                                        "minimum": 0,
                                        "maximum": 10000,
                                        "type": "integer"
                                      },
                                      "impuretes_max_cp": {
                                        "minimum": 0,
                                        "maximum": 10000,
                                        "type": "integer"
                                      },
                                      "arrondi": {
                                        "anyOf": [
                                          {
                                            "const": "plus_proche",
                                            "type": "string"
                                          },
                                          {
                                            "const": "inferieur",
                                            "type": "string"
                                          },
                                          {
                                            "const": "superieur",
                                            "type": "string"
                                          }
                                        ]
                                      }
                                    }
                                  },
                                  {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "type",
                                      "humidite_norme_cp",
                                      "arrondi"
                                    ],
                                    "properties": {
                                      "type": {
                                        "const": "lineaire_simple",
                                        "type": "string"
                                      },
                                      "humidite_norme_cp": {
                                        "minimum": 0,
                                        "maximum": 9999,
                                        "type": "integer"
                                      },
                                      "arrondi": {
                                        "anyOf": [
                                          {
                                            "const": "plus_proche",
                                            "type": "string"
                                          },
                                          {
                                            "const": "inferieur",
                                            "type": "string"
                                          },
                                          {
                                            "const": "superieur",
                                            "type": "string"
                                          }
                                        ]
                                      }
                                    }
                                  },
                                  {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "type",
                                      "humidite_norme_cp",
                                      "arrondi"
                                    ],
                                    "properties": {
                                      "type": {
                                        "const": "bilan_de_masse",
                                        "type": "string"
                                      },
                                      "humidite_norme_cp": {
                                        "minimum": 0,
                                        "maximum": 9999,
                                        "type": "integer"
                                      },
                                      "arrondi": {
                                        "anyOf": [
                                          {
                                            "const": "plus_proche",
                                            "type": "string"
                                          },
                                          {
                                            "const": "inferieur",
                                            "type": "string"
                                          },
                                          {
                                            "const": "superieur",
                                            "type": "string"
                                          }
                                        ]
                                      }
                                    }
                                  }
                                ]
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "valeur_engagee": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "devise",
                              "valeur"
                            ],
                            "properties": {
                              "devise": {
                                "pattern": "^[A-Z]{3}$",
                                "type": "string"
                              },
                              "valeur": {
                                "description": "Unités mineures de la devise.",
                                "type": "integer"
                              }
                            }
                          },
                          "primes": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "type",
                                "mode",
                                "montant_unite_mineure",
                                "devise",
                                "taux_cp"
                              ],
                              "properties": {
                                "type": {
                                  "anyOf": [
                                    {
                                      "const": "bio",
                                      "type": "string"
                                    },
                                    {
                                      "const": "equitable",
                                      "type": "string"
                                    },
                                    {
                                      "const": "qualite",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "mode": {
                                  "anyOf": [
                                    {
                                      "const": "montant",
                                      "type": "string"
                                    },
                                    {
                                      "const": "taux",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "montant_unite_mineure": {
                                  "anyOf": [
                                    {
                                      "type": "integer"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "devise": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "taux_cp": {
                                  "anyOf": [
                                    {
                                      "type": "integer"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Contrat inconnu (`contrat_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Sans ligne, campagne clôturée ou contrat hors brouillon (`activation_refusee`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/rendements": {
      "post": {
        "operationId": "definirRendement",
        "summary": "Définir le rendement de référence d'une parcelle ou d'une zone, avec son motif (`capacity.propose`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "valeur_g_ha",
                  "motif"
                ],
                "properties": {
                  "parcelle_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "zone_cueillette_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "valeur_g_ha": {
                    "minimum": 1,
                    "type": "integer"
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Nouvelle version du rendement (ajout seul).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "version"
                  ],
                  "properties": {
                    "version": {
                      "minimum": 1,
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide ou cible mal désignée (`corps_invalide`, `cible_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Parcelle ou zone inconnue (`cible_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Rendement refusé par la base (`rendement_refuse`) ; module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/fournisseurs": {
      "post": {
        "operationId": "creerFournisseur",
        "summary": "Créer un fournisseur avec son certificat, en une seule transaction (`certification.manage`, EC-053)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "fournisseur",
                  "certificat"
                ],
                "properties": {
                  "fournisseur": {
                    "additionalProperties": false,
                    "type": "object",
                    "required": [
                      "code",
                      "nom",
                      "pays",
                      "ville",
                      "adresse",
                      "telephone",
                      "email",
                      "contact"
                    ],
                    "properties": {
                      "code": {
                        "minLength": 1,
                        "maxLength": 40,
                        "type": "string"
                      },
                      "nom": {
                        "minLength": 1,
                        "maxLength": 300,
                        "type": "string"
                      },
                      "pays": {
                        "pattern": "^[A-Z]{2}$",
                        "description": "Code ISO 3166-1 alpha-2.",
                        "type": "string"
                      },
                      "ville": {
                        "minLength": 1,
                        "maxLength": 300,
                        "type": "string"
                      },
                      "adresse": {
                        "minLength": 1,
                        "maxLength": 300,
                        "type": "string"
                      },
                      "telephone": {
                        "minLength": 1,
                        "maxLength": 300,
                        "type": "string"
                      },
                      "email": {
                        "pattern": "^[^@\\s]+@[^@\\s]+$",
                        "maxLength": 254,
                        "type": "string"
                      },
                      "contact": {
                        "minLength": 1,
                        "maxLength": 300,
                        "type": "string"
                      }
                    }
                  },
                  "certificat": {
                    "additionalProperties": false,
                    "type": "object",
                    "required": [
                      "referentiel_id",
                      "organisme_nom",
                      "organisme_code",
                      "numero",
                      "date_debut",
                      "date_fin",
                      "fichier_id"
                    ],
                    "properties": {
                      "referentiel_id": {
                        "format": "uuid",
                        "type": "string"
                      },
                      "organisme_nom": {
                        "minLength": 1,
                        "maxLength": 300,
                        "type": "string"
                      },
                      "organisme_code": {
                        "minLength": 1,
                        "maxLength": 300,
                        "type": "string"
                      },
                      "numero": {
                        "minLength": 1,
                        "maxLength": 300,
                        "type": "string"
                      },
                      "portee": {
                        "maxItems": 500,
                        "type": "array",
                        "items": {
                          "anyOf": [
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "dimension",
                                "element",
                                "inclus"
                              ],
                              "properties": {
                                "dimension": {
                                  "const": "activite",
                                  "type": "string"
                                },
                                "element": {
                                  "pattern": "^[a-z][a-z0-9_]*$",
                                  "type": "string"
                                },
                                "inclus": {
                                  "type": "boolean"
                                }
                              }
                            },
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "dimension",
                                "element",
                                "inclus"
                              ],
                              "properties": {
                                "dimension": {
                                  "const": "produit",
                                  "type": "string"
                                },
                                "element": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "inclus": {
                                  "type": "boolean"
                                }
                              }
                            },
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "dimension",
                                "element",
                                "inclus"
                              ],
                              "properties": {
                                "dimension": {
                                  "const": "site",
                                  "type": "string"
                                },
                                "element": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "inclus": {
                                  "type": "boolean"
                                }
                              }
                            },
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "dimension",
                                "unite",
                                "element",
                                "inclus"
                              ],
                              "properties": {
                                "dimension": {
                                  "const": "unite",
                                  "type": "string"
                                },
                                "unite": {
                                  "anyOf": [
                                    {
                                      "const": "producteur",
                                      "type": "string"
                                    },
                                    {
                                      "const": "parcelle",
                                      "type": "string"
                                    },
                                    {
                                      "const": "zone_cueillette",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "element": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "inclus": {
                                  "type": "boolean"
                                }
                              }
                            }
                          ]
                        }
                      },
                      "date_debut": {
                        "format": "date",
                        "type": "string"
                      },
                      "date_fin": {
                        "format": "date",
                        "type": "string"
                      },
                      "fichier_id": {
                        "format": "uuid",
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Le fournisseur et son certificat sont créés.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "fournisseur_id",
                    "certificat_id"
                  ],
                  "properties": {
                    "fournisseur_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "certificat_id": {
                      "format": "uuid",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Fournisseur ou certificat refusé par la base : rien n'est créé (`fournisseur_refuse`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/activites": {
      "get": {
        "operationId": "listerActivites",
        "summary": "Activités de premier niveau du catalogue, avec leur état déclaré pour l'organisation active (AM-04)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les 13 activités de premier niveau, dans l'ordre du catalogue.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "activites"
                  ],
                  "properties": {
                    "activites": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "regroupement",
                          "libelle_fr",
                          "libelle_en",
                          "etat",
                          "dernier_changement",
                          "sites_actifs"
                        ],
                        "properties": {
                          "code": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          },
                          "regroupement": {
                            "anyOf": [
                              {
                                "const": "production",
                                "type": "string"
                              },
                              {
                                "const": "achat",
                                "type": "string"
                              },
                              {
                                "const": "nettoyage_triage",
                                "type": "string"
                              },
                              {
                                "const": "transformation",
                                "type": "string"
                              },
                              {
                                "const": "vente_export",
                                "type": "string"
                              }
                            ]
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "etat": {
                            "anyOf": [
                              {
                                "const": "active",
                                "type": "string"
                              },
                              {
                                "const": "desactivee",
                                "type": "string"
                              }
                            ]
                          },
                          "dernier_changement": {
                            "anyOf": [
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "motif",
                                  "auteur",
                                  "cree_le"
                                ],
                                "properties": {
                                  "motif": {
                                    "type": "string"
                                  },
                                  "auteur": {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "id",
                                      "nom_affiche"
                                    ],
                                    "properties": {
                                      "id": {
                                        "format": "uuid",
                                        "type": "string"
                                      },
                                      "nom_affiche": {
                                        "type": "string"
                                      }
                                    }
                                  },
                                  "cree_le": {
                                    "format": "date-time",
                                    "type": "string"
                                  }
                                }
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "sites_actifs": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "id",
                                "code"
                              ],
                              "properties": {
                                "id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "code": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/activites/{code}/etat": {
      "post": {
        "operationId": "changerEtatActivite",
        "summary": "Déclarer ou retirer une activité de l'organisation, ou d'un de ses sites, avec un motif (`modules.manage`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^[a-z][a-z0-9_]*$",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "etat",
                  "motif"
                ],
                "properties": {
                  "etat": {
                    "anyOf": [
                      {
                        "const": "active",
                        "type": "string"
                      },
                      {
                        "const": "desactivee",
                        "type": "string"
                      }
                    ]
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  },
                  "site_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "L'activité après le changement.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "code",
                    "regroupement",
                    "libelle_fr",
                    "libelle_en",
                    "etat",
                    "dernier_changement",
                    "sites_actifs"
                  ],
                  "properties": {
                    "code": {
                      "pattern": "^[a-z][a-z0-9_]*$",
                      "type": "string"
                    },
                    "regroupement": {
                      "anyOf": [
                        {
                          "const": "production",
                          "type": "string"
                        },
                        {
                          "const": "achat",
                          "type": "string"
                        },
                        {
                          "const": "nettoyage_triage",
                          "type": "string"
                        },
                        {
                          "const": "transformation",
                          "type": "string"
                        },
                        {
                          "const": "vente_export",
                          "type": "string"
                        }
                      ]
                    },
                    "libelle_fr": {
                      "type": "string"
                    },
                    "libelle_en": {
                      "type": "string"
                    },
                    "etat": {
                      "anyOf": [
                        {
                          "const": "active",
                          "type": "string"
                        },
                        {
                          "const": "desactivee",
                          "type": "string"
                        }
                      ]
                    },
                    "dernier_changement": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "motif",
                            "auteur",
                            "cree_le"
                          ],
                          "properties": {
                            "motif": {
                              "type": "string"
                            },
                            "auteur": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "id",
                                "nom_affiche"
                              ],
                              "properties": {
                                "id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "nom_affiche": {
                                  "type": "string"
                                }
                              }
                            },
                            "cree_le": {
                              "format": "date-time",
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "sites_actifs": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Activité de premier niveau ou site inconnus (`activite_inconnue`, `site_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Changement sans effet (`etat_inchange`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/arbre-activites": {
      "get": {
        "operationId": "lireArbreActivites",
        "summary": "Arbre d'activités de l'organisation, copié de son pack filière, avec l'état de chaque nœud (AM-04)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "site_id",
            "in": "query",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les nœuds, parents avant enfants, dans l'ordre du pack. Vide tant que le pack n'est pas chargé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "noeuds"
                  ],
                  "properties": {
                    "noeuds": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "chemin",
                          "type",
                          "niveau",
                          "libelle_fr",
                          "libelle_en",
                          "obligatoire",
                          "critique",
                          "sous_traitable",
                          "ordre",
                          "provisoire",
                          "etat",
                          "dernier_changement"
                        ],
                        "properties": {
                          "chemin": {
                            "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){0,2}$",
                            "type": "string"
                          },
                          "type": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          },
                          "niveau": {
                            "minimum": 1,
                            "maximum": 3,
                            "type": "integer"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "obligatoire": {
                            "type": "boolean"
                          },
                          "critique": {
                            "type": "boolean"
                          },
                          "sous_traitable": {
                            "type": "boolean"
                          },
                          "ordre": {
                            "type": "integer"
                          },
                          "provisoire": {
                            "type": "boolean"
                          },
                          "etat": {
                            "anyOf": [
                              {
                                "const": "active",
                                "type": "string"
                              },
                              {
                                "const": "desactivee",
                                "type": "string"
                              }
                            ]
                          },
                          "dernier_changement": {
                            "anyOf": [
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "motif",
                                  "auteur",
                                  "cree_le"
                                ],
                                "properties": {
                                  "motif": {
                                    "type": "string"
                                  },
                                  "auteur": {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "id",
                                      "nom_affiche"
                                    ],
                                    "properties": {
                                      "id": {
                                        "format": "uuid",
                                        "type": "string"
                                      },
                                      "nom_affiche": {
                                        "type": "string"
                                      }
                                    }
                                  },
                                  "cree_le": {
                                    "format": "date-time",
                                    "type": "string"
                                  }
                                }
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ma-filiere": {
      "get": {
        "operationId": "lireMaFiliere",
        "summary": "Ce que les packs filière de l'organisation apportent : produits, arbre avec le contrat de chaque nœud, paramètres (AM-04, EC-118)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Un élément par pack dont l'arbre est copié chez l'organisation, en version figée. Lecture ouverte aux membres.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "packs"
                  ],
                  "properties": {
                    "packs": {
                      "description": "Packs filière dont l'organisation a copié l'arbre ; vide tant qu'aucun pack n'est chargé.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle",
                          "version",
                          "produits",
                          "arbre",
                          "parametres"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "libelle": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "fr",
                              "en"
                            ],
                            "properties": {
                              "fr": {
                                "type": "string"
                              },
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "version": {
                            "description": "Version figée à l'ouverture du compte (celle de l'arbre de l'organisation).",
                            "type": "string"
                          },
                          "produits": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "code",
                                "nom",
                                "unite",
                                "est_matiere_premiere"
                              ],
                              "properties": {
                                "code": {
                                  "type": "string"
                                },
                                "nom": {
                                  "additionalProperties": false,
                                  "type": "object",
                                  "required": [
                                    "fr",
                                    "en"
                                  ],
                                  "properties": {
                                    "fr": {
                                      "type": "string"
                                    },
                                    "en": {
                                      "type": "string"
                                    }
                                  }
                                },
                                "unite": {
                                  "type": "string"
                                },
                                "est_matiere_premiere": {
                                  "type": "boolean"
                                }
                              }
                            }
                          },
                          "arbre": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "description": "Boîte d'activité d'un pack : ses entrées, ses sorties typées, ses mesures et ses paramètres (EC-118).",
                              "type": "object",
                              "required": [
                                "chemin",
                                "type",
                                "libelle",
                                "obligatoire",
                                "critique",
                                "sous_traitable",
                                "ordre",
                                "entrees",
                                "sorties",
                                "mesures",
                                "parametres"
                              ],
                              "properties": {
                                "chemin": {
                                  "type": "string"
                                },
                                "type": {
                                  "type": "string"
                                },
                                "libelle": {
                                  "additionalProperties": false,
                                  "type": "object",
                                  "required": [
                                    "fr",
                                    "en"
                                  ],
                                  "properties": {
                                    "fr": {
                                      "type": "string"
                                    },
                                    "en": {
                                      "type": "string"
                                    }
                                  }
                                },
                                "obligatoire": {
                                  "type": "boolean"
                                },
                                "critique": {
                                  "type": "boolean"
                                },
                                "sous_traitable": {
                                  "type": "boolean"
                                },
                                "ordre": {
                                  "type": "integer"
                                },
                                "entrees": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                },
                                "sorties": {
                                  "type": "array",
                                  "items": {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "produit",
                                      "nature"
                                    ],
                                    "properties": {
                                      "produit": {
                                        "type": "string"
                                      },
                                      "nature": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                },
                                "mesures": {
                                  "type": "array",
                                  "items": {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "code",
                                      "libelle",
                                      "unite",
                                      "type"
                                    ],
                                    "properties": {
                                      "code": {
                                        "type": "string"
                                      },
                                      "libelle": {
                                        "additionalProperties": false,
                                        "type": "object",
                                        "required": [
                                          "fr",
                                          "en"
                                        ],
                                        "properties": {
                                          "fr": {
                                            "type": "string"
                                          },
                                          "en": {
                                            "type": "string"
                                          }
                                        }
                                      },
                                      "unite": {
                                        "type": "string"
                                      },
                                      "type": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                },
                                "parametres": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          },
                          "parametres": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "cle",
                                "unite",
                                "surchargeable",
                                "bornes"
                              ],
                              "properties": {
                                "cle": {
                                  "type": "string"
                                },
                                "unite": {
                                  "type": "string"
                                },
                                "surchargeable": {
                                  "type": "boolean"
                                },
                                "bornes": {
                                  "anyOf": [
                                    {
                                      "additionalProperties": false,
                                      "type": "object",
                                      "required": [
                                        "min",
                                        "max"
                                      ],
                                      "properties": {
                                        "min": {
                                          "type": "number"
                                        },
                                        "max": {
                                          "type": "number"
                                        }
                                      }
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/arbre-activites/initialiser": {
      "post": {
        "operationId": "initialiserArbreActivites",
        "summary": "Ouvrir le compte depuis l'arbre du pack : activer les nœuds choisis, ou tous, avec un motif (`modules.manage`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "motif"
                ],
                "properties": {
                  "noeuds": {
                    "maxItems": 200,
                    "type": "array",
                    "items": {
                      "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){0,2}$",
                      "type": "string"
                    }
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "L'arbre après l'activation. Rejouable : un nœud déjà actif est laissé tel quel.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "noeuds"
                  ],
                  "properties": {
                    "noeuds": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "chemin",
                          "type",
                          "niveau",
                          "libelle_fr",
                          "libelle_en",
                          "obligatoire",
                          "critique",
                          "sous_traitable",
                          "ordre",
                          "provisoire",
                          "etat",
                          "dernier_changement"
                        ],
                        "properties": {
                          "chemin": {
                            "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){0,2}$",
                            "type": "string"
                          },
                          "type": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          },
                          "niveau": {
                            "minimum": 1,
                            "maximum": 3,
                            "type": "integer"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "obligatoire": {
                            "type": "boolean"
                          },
                          "critique": {
                            "type": "boolean"
                          },
                          "sous_traitable": {
                            "type": "boolean"
                          },
                          "ordre": {
                            "type": "integer"
                          },
                          "provisoire": {
                            "type": "boolean"
                          },
                          "etat": {
                            "anyOf": [
                              {
                                "const": "active",
                                "type": "string"
                              },
                              {
                                "const": "desactivee",
                                "type": "string"
                              }
                            ]
                          },
                          "dernier_changement": {
                            "anyOf": [
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "motif",
                                  "auteur",
                                  "cree_le"
                                ],
                                "properties": {
                                  "motif": {
                                    "type": "string"
                                  },
                                  "auteur": {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "id",
                                      "nom_affiche"
                                    ],
                                    "properties": {
                                      "id": {
                                        "format": "uuid",
                                        "type": "string"
                                      },
                                      "nom_affiche": {
                                        "type": "string"
                                      }
                                    }
                                  },
                                  "cree_le": {
                                    "format": "date-time",
                                    "type": "string"
                                  }
                                }
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Nœud absent de l'arbre de l'organisation (`noeud_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Un nœud choisi sans son parent (`parent_inactif`) ou un nœud obligatoire laissé de côté (`noeud_obligatoire_parent_actif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/arbre-activites/{chemin}/etat": {
      "post": {
        "operationId": "changerEtatNoeud",
        "summary": "Activer ou désactiver un nœud de l'arbre, pour l'organisation ou un site, avec un motif (`modules.manage`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "chemin",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){0,2}$",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "etat",
                  "motif"
                ],
                "properties": {
                  "etat": {
                    "anyOf": [
                      {
                        "const": "active",
                        "type": "string"
                      },
                      {
                        "const": "desactivee",
                        "type": "string"
                      }
                    ]
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  },
                  "site_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Le nœud après le changement. Désactiver un nœud désactive ses enfants.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "chemin",
                    "type",
                    "niveau",
                    "libelle_fr",
                    "libelle_en",
                    "obligatoire",
                    "critique",
                    "sous_traitable",
                    "ordre",
                    "provisoire",
                    "etat",
                    "dernier_changement"
                  ],
                  "properties": {
                    "chemin": {
                      "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){0,2}$",
                      "type": "string"
                    },
                    "type": {
                      "pattern": "^[a-z][a-z0-9_]*$",
                      "type": "string"
                    },
                    "niveau": {
                      "minimum": 1,
                      "maximum": 3,
                      "type": "integer"
                    },
                    "libelle_fr": {
                      "type": "string"
                    },
                    "libelle_en": {
                      "type": "string"
                    },
                    "obligatoire": {
                      "type": "boolean"
                    },
                    "critique": {
                      "type": "boolean"
                    },
                    "sous_traitable": {
                      "type": "boolean"
                    },
                    "ordre": {
                      "type": "integer"
                    },
                    "provisoire": {
                      "type": "boolean"
                    },
                    "etat": {
                      "anyOf": [
                        {
                          "const": "active",
                          "type": "string"
                        },
                        {
                          "const": "desactivee",
                          "type": "string"
                        }
                      ]
                    },
                    "dernier_changement": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "motif",
                            "auteur",
                            "cree_le"
                          ],
                          "properties": {
                            "motif": {
                              "type": "string"
                            },
                            "auteur": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "id",
                                "nom_affiche"
                              ],
                              "properties": {
                                "id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "nom_affiche": {
                                  "type": "string"
                                }
                              }
                            },
                            "cree_le": {
                              "format": "date-time",
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Nœud ou site inconnus (`noeud_inconnu`, `site_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Changement sans effet (`etat_inchange`), parent inactif (`parent_inactif`), nœud obligatoire ou critique dont le parent est actif (`noeud_obligatoire_parent_actif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/onboarding": {
      "get": {
        "operationId": "lireOnboarding",
        "summary": "Parcours d'onboarding : familles de culture, packs disponibles avec leur arbre, activités, modules et situation actuelle (`modules.manage`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Tout ce qu'il faut pour afficher le parcours et préremplir le récapitulatif.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "organisation",
                    "etat",
                    "familles",
                    "packs",
                    "activites",
                    "modules",
                    "situation"
                  ],
                  "properties": {
                    "organisation": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "nom",
                        "pays"
                      ],
                      "properties": {
                        "nom": {
                          "type": "string"
                        },
                        "pays": {
                          "type": "string"
                        }
                      }
                    },
                    "etat": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "requis",
                        "etat"
                      ],
                      "properties": {
                        "requis": {
                          "type": "boolean"
                        },
                        "etat": {
                          "anyOf": [
                            {
                              "const": "jamais",
                              "type": "string"
                            },
                            {
                              "const": "reporte",
                              "type": "string"
                            },
                            {
                              "const": "termine",
                              "type": "string"
                            },
                            {
                              "const": "rouvert",
                              "type": "string"
                            }
                          ]
                        }
                      }
                    },
                    "familles": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle_fr",
                          "libelle_en",
                          "disponible"
                        ],
                        "properties": {
                          "code": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "disponible": {
                            "type": "boolean"
                          }
                        }
                      }
                    },
                    "packs": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "famille",
                          "code",
                          "version",
                          "libelle_fr",
                          "libelle_en",
                          "noeuds"
                        ],
                        "properties": {
                          "famille": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          },
                          "code": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          },
                          "version": {
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "noeuds": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "chemin",
                                "type",
                                "niveau",
                                "libelle_fr",
                                "libelle_en",
                                "obligatoire",
                                "critique"
                              ],
                              "properties": {
                                "chemin": {
                                  "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){0,2}$",
                                  "type": "string"
                                },
                                "type": {
                                  "pattern": "^[a-z][a-z0-9_]*$",
                                  "type": "string"
                                },
                                "niveau": {
                                  "minimum": 1,
                                  "maximum": 3,
                                  "type": "integer"
                                },
                                "libelle_fr": {
                                  "type": "string"
                                },
                                "libelle_en": {
                                  "type": "string"
                                },
                                "obligatoire": {
                                  "type": "boolean"
                                },
                                "critique": {
                                  "type": "boolean"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "activites": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle_fr",
                          "libelle_en",
                          "groupe"
                        ],
                        "properties": {
                          "code": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "groupe": {
                            "anyOf": [
                              {
                                "const": "roles",
                                "type": "string"
                              },
                              {
                                "const": "etapes",
                                "type": "string"
                              }
                            ]
                          }
                        }
                      }
                    },
                    "modules": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle_fr",
                          "libelle_en",
                          "requis",
                          "propose_par",
                          "exigence"
                        ],
                        "properties": {
                          "code": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "requis": {
                            "type": "array",
                            "items": {
                              "pattern": "^[a-z][a-z0-9_]*$",
                              "type": "string"
                            }
                          },
                          "propose_par": {
                            "type": "array",
                            "items": {
                              "pattern": "^[a-z][a-z0-9_]*$",
                              "type": "string"
                            }
                          },
                          "exigence": {
                            "type": "boolean"
                          }
                        }
                      }
                    },
                    "situation": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "activites",
                        "noeuds",
                        "modules",
                        "reponses"
                      ],
                      "properties": {
                        "activites": {
                          "type": "array",
                          "items": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          }
                        },
                        "noeuds": {
                          "type": "array",
                          "items": {
                            "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){0,2}$",
                            "type": "string"
                          }
                        },
                        "modules": {
                          "type": "array",
                          "items": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          }
                        },
                        "reponses": {
                          "anyOf": [
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "properties": {
                                "famille": {
                                  "pattern": "^[a-z][a-z0-9_]*$",
                                  "type": "string"
                                },
                                "activites": {
                                  "maxItems": 20,
                                  "type": "array",
                                  "items": {
                                    "pattern": "^[a-z][a-z0-9_]*$",
                                    "type": "string"
                                  }
                                },
                                "exigences": {
                                  "maxItems": 20,
                                  "type": "array",
                                  "items": {
                                    "pattern": "^[a-z][a-z0-9_]*$",
                                    "type": "string"
                                  }
                                },
                                "familles_souhaitees": {
                                  "maxItems": 20,
                                  "type": "array",
                                  "items": {
                                    "pattern": "^[a-z][a-z0-9_]*$",
                                    "type": "string"
                                  }
                                }
                              }
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/onboarding/reporter": {
      "post": {
        "operationId": "reporterOnboarding",
        "summary": "Reporter le parcours (« Plus tard ») en gardant un brouillon des réponses (`modules.manage`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "properties": {
                  "reponses": {
                    "additionalProperties": false,
                    "type": "object",
                    "properties": {
                      "famille": {
                        "pattern": "^[a-z][a-z0-9_]*$",
                        "type": "string"
                      },
                      "activites": {
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "pattern": "^[a-z][a-z0-9_]*$",
                          "type": "string"
                        }
                      },
                      "exigences": {
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "pattern": "^[a-z][a-z0-9_]*$",
                          "type": "string"
                        }
                      },
                      "familles_souhaitees": {
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "pattern": "^[a-z][a-z0-9_]*$",
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Le nouvel état du parcours.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "requis",
                    "etat"
                  ],
                  "properties": {
                    "requis": {
                      "type": "boolean"
                    },
                    "etat": {
                      "anyOf": [
                        {
                          "const": "jamais",
                          "type": "string"
                        },
                        {
                          "const": "reporte",
                          "type": "string"
                        },
                        {
                          "const": "termine",
                          "type": "string"
                        },
                        {
                          "const": "rouvert",
                          "type": "string"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/onboarding/terminer": {
      "post": {
        "operationId": "terminerOnboarding",
        "summary": "Appliquer le récapitulatif : charger le pack de la famille, déclarer les activités, activer les nœuds et les modules (`modules.manage`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "reponses",
                  "noeuds",
                  "modules"
                ],
                "properties": {
                  "reponses": {
                    "additionalProperties": false,
                    "type": "object",
                    "required": [
                      "famille",
                      "activites",
                      "exigences"
                    ],
                    "properties": {
                      "famille": {
                        "pattern": "^[a-z][a-z0-9_]*$",
                        "type": "string"
                      },
                      "activites": {
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "pattern": "^[a-z][a-z0-9_]*$",
                          "type": "string"
                        }
                      },
                      "exigences": {
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "pattern": "^[a-z][a-z0-9_]*$",
                          "type": "string"
                        }
                      },
                      "familles_souhaitees": {
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "pattern": "^[a-z][a-z0-9_]*$",
                          "type": "string"
                        }
                      }
                    }
                  },
                  "noeuds": {
                    "maxItems": 200,
                    "type": "array",
                    "items": {
                      "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){0,2}$",
                      "type": "string"
                    }
                  },
                  "modules": {
                    "maxItems": 30,
                    "type": "array",
                    "items": {
                      "pattern": "^[a-z][a-z0-9_]*$",
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ce qui a été appliqué. Rejouable : ce qui est déjà actif est laissé tel quel, rien n'est désactivé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "pack",
                    "activites_declarees",
                    "noeuds_actives",
                    "modules_actives",
                    "etat"
                  ],
                  "properties": {
                    "pack": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "code",
                        "version"
                      ],
                      "properties": {
                        "code": {
                          "pattern": "^[a-z][a-z0-9_]*$",
                          "type": "string"
                        },
                        "version": {
                          "type": "string"
                        }
                      }
                    },
                    "activites_declarees": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "noeuds_actives": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "modules_actives": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "etat": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "requis",
                        "etat"
                      ],
                      "properties": {
                        "requis": {
                          "type": "boolean"
                        },
                        "etat": {
                          "anyOf": [
                            {
                              "const": "jamais",
                              "type": "string"
                            },
                            {
                              "const": "reporte",
                              "type": "string"
                            },
                            {
                              "const": "termine",
                              "type": "string"
                            },
                            {
                              "const": "rouvert",
                              "type": "string"
                            }
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`, `famille_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Nœud, module ou activité inconnus (`noeud_inconnu`, `module_inconnu`, `activite_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Famille sans pack (`famille_indisponible`), pack non publié (`pack_non_publie`), garde-fou de l'arbre ou des modules (`parent_inactif`, `noeud_obligatoire_parent_actif`, `dependance_inactive`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/onboarding/rouvrir": {
      "post": {
        "operationId": "rouvrirOnboarding",
        "summary": "Rouvrir le parcours pour le rejouer (tests, nouvelle activité) ; rien n'est désactivé (`modules.manage`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Le nouvel état du parcours.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "requis",
                    "etat"
                  ],
                  "properties": {
                    "requis": {
                      "type": "boolean"
                    },
                    "etat": {
                      "anyOf": [
                        {
                          "const": "jamais",
                          "type": "string"
                        },
                        {
                          "const": "reporte",
                          "type": "string"
                        },
                        {
                          "const": "termine",
                          "type": "string"
                        },
                        {
                          "const": "rouvert",
                          "type": "string"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/modules": {
      "get": {
        "operationId": "listerModules",
        "summary": "Modules avec leur état pour l'organisation active, leurs dépendances et ceux que les activités déclarées proposent (AM-05)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Tous les modules, noyau compris, dans l'ordre du catalogue.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "modules"
                  ],
                  "properties": {
                    "modules": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle_fr",
                          "libelle_en",
                          "toujours_actif",
                          "etat",
                          "requis",
                          "propose_par",
                          "propose",
                          "dernier_changement"
                        ],
                        "properties": {
                          "code": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "toujours_actif": {
                            "type": "boolean"
                          },
                          "etat": {
                            "anyOf": [
                              {
                                "const": "actif",
                                "type": "string"
                              },
                              {
                                "const": "inactif",
                                "type": "string"
                              }
                            ]
                          },
                          "requis": {
                            "type": "array",
                            "items": {
                              "pattern": "^[a-z][a-z0-9_]*$",
                              "type": "string"
                            }
                          },
                          "propose_par": {
                            "type": "array",
                            "items": {
                              "pattern": "^[a-z][a-z0-9_]*$",
                              "type": "string"
                            }
                          },
                          "propose": {
                            "type": "boolean"
                          },
                          "dernier_changement": {
                            "anyOf": [
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "motif",
                                  "auteur",
                                  "cree_le"
                                ],
                                "properties": {
                                  "motif": {
                                    "type": "string"
                                  },
                                  "auteur": {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "id",
                                      "nom_affiche"
                                    ],
                                    "properties": {
                                      "id": {
                                        "format": "uuid",
                                        "type": "string"
                                      },
                                      "nom_affiche": {
                                        "type": "string"
                                      }
                                    }
                                  },
                                  "cree_le": {
                                    "format": "date-time",
                                    "type": "string"
                                  }
                                }
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/modules/{code}/etat": {
      "post": {
        "operationId": "changerEtatModule",
        "summary": "Activer ou désactiver un module de l'organisation, avec un motif (`modules.manage`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^[a-z][a-z0-9_]*$",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "etat",
                  "motif"
                ],
                "properties": {
                  "etat": {
                    "anyOf": [
                      {
                        "const": "actif",
                        "type": "string"
                      },
                      {
                        "const": "inactif",
                        "type": "string"
                      }
                    ]
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Le module après le changement.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "code",
                    "libelle_fr",
                    "libelle_en",
                    "toujours_actif",
                    "etat",
                    "requis",
                    "propose_par",
                    "propose",
                    "dernier_changement"
                  ],
                  "properties": {
                    "code": {
                      "pattern": "^[a-z][a-z0-9_]*$",
                      "type": "string"
                    },
                    "libelle_fr": {
                      "type": "string"
                    },
                    "libelle_en": {
                      "type": "string"
                    },
                    "toujours_actif": {
                      "type": "boolean"
                    },
                    "etat": {
                      "anyOf": [
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "inactif",
                          "type": "string"
                        }
                      ]
                    },
                    "requis": {
                      "type": "array",
                      "items": {
                        "pattern": "^[a-z][a-z0-9_]*$",
                        "type": "string"
                      }
                    },
                    "propose_par": {
                      "type": "array",
                      "items": {
                        "pattern": "^[a-z][a-z0-9_]*$",
                        "type": "string"
                      }
                    },
                    "propose": {
                      "type": "boolean"
                    },
                    "dernier_changement": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "motif",
                            "auteur",
                            "cree_le"
                          ],
                          "properties": {
                            "motif": {
                              "type": "string"
                            },
                            "auteur": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "id",
                                "nom_affiche"
                              ],
                              "properties": {
                                "id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "nom_affiche": {
                                  "type": "string"
                                }
                              }
                            },
                            "cree_le": {
                              "format": "date-time",
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Module inconnu (`module_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Noyau, changement sans effet, dépendance inactive ou module requis par un module actif (`module_toujours_actif`, `etat_inchange`, `dependance_inactive`, `module_requis`) ; `details.modules` liste les modules en cause.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/controles": {
      "get": {
        "operationId": "listerControles",
        "summary": "File de contrôle de l'organisation active (`review.resolve`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "statut",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "const": "ouvert",
                  "type": "string"
                },
                {
                  "const": "en_cours",
                  "type": "string"
                },
                {
                  "const": "leve",
                  "type": "string"
                }
              ]
            }
          },
          {
            "name": "limite",
            "in": "query",
            "required": false,
            "schema": {
              "minimum": 1,
              "maximum": 200,
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Contrôles du statut demandé (par défaut ni levés), du plus ancien au plus récent.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "controles"
                  ],
                  "properties": {
                    "controles": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "motif",
                          "statut",
                          "details",
                          "producteur_id",
                          "commande_id",
                          "decision",
                          "motif_decision",
                          "decide_par",
                          "decide_le",
                          "cree_le",
                          "bloquant",
                          "decisions_possibles"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "motif": {
                            "type": "string"
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "ouvert",
                                "type": "string"
                              },
                              {
                                "const": "en_cours",
                                "type": "string"
                              },
                              {
                                "const": "leve",
                                "type": "string"
                              }
                            ]
                          },
                          "details": {
                            "additionalProperties": true,
                            "type": "object",
                            "properties": {}
                          },
                          "producteur_id": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "commande_id": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "decision": {
                            "anyOf": [
                              {
                                "anyOf": [
                                  {
                                    "const": "regularisation",
                                    "type": "string"
                                  },
                                  {
                                    "const": "declassement",
                                    "type": "string"
                                  },
                                  {
                                    "const": "non_conformite",
                                    "type": "string"
                                  },
                                  {
                                    "const": "fusion",
                                    "type": "string"
                                  },
                                  {
                                    "const": "correction",
                                    "type": "string"
                                  },
                                  {
                                    "const": "confirmation",
                                    "type": "string"
                                  },
                                  {
                                    "const": "ecart_manuel",
                                    "type": "string"
                                  },
                                  {
                                    "const": "reprise_manuelle",
                                    "type": "string"
                                  }
                                ]
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "motif_decision": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "decide_par": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "decide_le": {
                            "anyOf": [
                              {
                                "format": "date-time",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "bloquant": {
                            "description": "Vrai si la commande n'a pas été écrite (données illisibles, version obsolète, empreinte incohérente) : à traiter en premier (protocole §6.3 et §9).",
                            "type": "boolean"
                          },
                          "decisions_possibles": {
                            "description": "Décisions que la route `lever` accepte pour ce motif (protocole §9). La fusion s'enregistre par son action, pas par cette route.",
                            "type": "array",
                            "items": {
                              "anyOf": [
                                {
                                  "const": "regularisation",
                                  "type": "string"
                                },
                                {
                                  "const": "declassement",
                                  "type": "string"
                                },
                                {
                                  "const": "non_conformite",
                                  "type": "string"
                                },
                                {
                                  "const": "fusion",
                                  "type": "string"
                                },
                                {
                                  "const": "correction",
                                  "type": "string"
                                },
                                {
                                  "const": "confirmation",
                                  "type": "string"
                                },
                                {
                                  "const": "ecart_manuel",
                                  "type": "string"
                                },
                                {
                                  "const": "reprise_manuelle",
                                  "type": "string"
                                }
                              ]
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/controles/{id}/lever": {
      "post": {
        "operationId": "leverControle",
        "summary": "Lever un contrôle par une décision motivée (`review.resolve`)",
        "tags": [
          "Back-office"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "decision",
                  "motif_decision"
                ],
                "properties": {
                  "decision": {
                    "anyOf": [
                      {
                        "const": "regularisation",
                        "type": "string"
                      },
                      {
                        "const": "declassement",
                        "type": "string"
                      },
                      {
                        "const": "non_conformite",
                        "type": "string"
                      },
                      {
                        "const": "fusion",
                        "type": "string"
                      },
                      {
                        "const": "correction",
                        "type": "string"
                      },
                      {
                        "const": "confirmation",
                        "type": "string"
                      },
                      {
                        "const": "ecart_manuel",
                        "type": "string"
                      },
                      {
                        "const": "reprise_manuelle",
                        "type": "string"
                      }
                    ]
                  },
                  "motif_decision": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Motif écrit : toute décision en exige un (protocole §9).",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contrôle levé, avec sa décision, son décideur et sa date.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "motif",
                    "statut",
                    "details",
                    "producteur_id",
                    "commande_id",
                    "decision",
                    "motif_decision",
                    "decide_par",
                    "decide_le",
                    "cree_le",
                    "bloquant",
                    "decisions_possibles"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "motif": {
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "ouvert",
                          "type": "string"
                        },
                        {
                          "const": "en_cours",
                          "type": "string"
                        },
                        {
                          "const": "leve",
                          "type": "string"
                        }
                      ]
                    },
                    "details": {
                      "additionalProperties": true,
                      "type": "object",
                      "properties": {}
                    },
                    "producteur_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "commande_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "decision": {
                      "anyOf": [
                        {
                          "anyOf": [
                            {
                              "const": "regularisation",
                              "type": "string"
                            },
                            {
                              "const": "declassement",
                              "type": "string"
                            },
                            {
                              "const": "non_conformite",
                              "type": "string"
                            },
                            {
                              "const": "fusion",
                              "type": "string"
                            },
                            {
                              "const": "correction",
                              "type": "string"
                            },
                            {
                              "const": "confirmation",
                              "type": "string"
                            },
                            {
                              "const": "ecart_manuel",
                              "type": "string"
                            },
                            {
                              "const": "reprise_manuelle",
                              "type": "string"
                            }
                          ]
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "motif_decision": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "decide_par": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "decide_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "bloquant": {
                      "description": "Vrai si la commande n'a pas été écrite (données illisibles, version obsolète, empreinte incohérente) : à traiter en premier (protocole §6.3 et §9).",
                      "type": "boolean"
                    },
                    "decisions_possibles": {
                      "description": "Décisions que la route `lever` accepte pour ce motif (protocole §9). La fusion s'enregistre par son action, pas par cette route.",
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "const": "regularisation",
                            "type": "string"
                          },
                          {
                            "const": "declassement",
                            "type": "string"
                          },
                          {
                            "const": "non_conformite",
                            "type": "string"
                          },
                          {
                            "const": "fusion",
                            "type": "string"
                          },
                          {
                            "const": "correction",
                            "type": "string"
                          },
                          {
                            "const": "confirmation",
                            "type": "string"
                          },
                          {
                            "const": "ecart_manuel",
                            "type": "string"
                          },
                          {
                            "const": "reprise_manuelle",
                            "type": "string"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps ou identifiant invalide, décision non permise pour ce motif (`decision_non_permise`), ou décision qui passe par son action (`decision_par_action`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant, ou levée par l'auteur de la commande (`levee_par_auteur`, SB-12).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Contrôle inconnu dans l'organisation active (`controle_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Contrôle déjà levé (`controle_deja_leve`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/utilisateurs": {
      "get": {
        "operationId": "listerUtilisateurs",
        "summary": "Utilisateurs de l'organisation active (`users.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Utilisateurs de l'organisation.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "utilisateurs"
                  ],
                  "properties": {
                    "utilisateurs": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "identifiant",
                          "nom_affiche",
                          "telephone",
                          "statut",
                          "cree_le"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "identifiant": {
                            "pattern": "^[a-z0-9_-]{3,32}$",
                            "description": "Identifiant local, sans le code de l'organisation.",
                            "type": "string"
                          },
                          "nom_affiche": {
                            "type": "string"
                          },
                          "telephone": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "actif",
                                "type": "string"
                              },
                              {
                                "const": "suspendu",
                                "type": "string"
                              },
                              {
                                "const": "desactive",
                                "type": "string"
                              }
                            ]
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "creerUtilisateur",
        "summary": "Créer un compte de l'organisation (`users.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "identifiant",
                  "nom_affiche"
                ],
                "properties": {
                  "identifiant": {
                    "pattern": "^[a-z0-9_-]{3,32}$",
                    "description": "Identifiant local, sans le code de l'organisation.",
                    "type": "string"
                  },
                  "nom_affiche": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  },
                  "telephone": {
                    "minLength": 3,
                    "maxLength": 30,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Compte créé dans Keycloak, rattaché à l'organisation, et en base. Le mot de passe provisoire n'est rendu qu'ici.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "utilisateur",
                    "identifiant_connexion",
                    "mot_de_passe_temporaire"
                  ],
                  "properties": {
                    "utilisateur": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "identifiant",
                        "nom_affiche",
                        "telephone",
                        "statut",
                        "cree_le"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "identifiant": {
                          "pattern": "^[a-z0-9_-]{3,32}$",
                          "description": "Identifiant local, sans le code de l'organisation.",
                          "type": "string"
                        },
                        "nom_affiche": {
                          "type": "string"
                        },
                        "telephone": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "actif",
                              "type": "string"
                            },
                            {
                              "const": "suspendu",
                              "type": "string"
                            },
                            {
                              "const": "desactive",
                              "type": "string"
                            }
                          ]
                        },
                        "cree_le": {
                          "format": "date-time",
                          "type": "string"
                        }
                      }
                    },
                    "identifiant_connexion": {
                      "description": "`{code organisation en minuscules}.{identifiant local}`, saisi tel quel au back-office.",
                      "type": "string"
                    },
                    "mot_de_passe_temporaire": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Identifiant déjà utilisé (`identifiant_deja_utilise`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible ou en échec (`identite_indisponible`) : rien n'est créé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/utilisateurs/{id}/desactiver": {
      "post": {
        "operationId": "desactiverUtilisateur",
        "summary": "Désactiver un compte, révoquer ses sessions et ses appareils (`users.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "motif"
                ],
                "properties": {
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Motif écrit, conservé au journal d'audit.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Compte désactivé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "identifiant",
                    "nom_affiche",
                    "telephone",
                    "statut",
                    "cree_le"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "identifiant": {
                      "pattern": "^[a-z0-9_-]{3,32}$",
                      "description": "Identifiant local, sans le code de l'organisation.",
                      "type": "string"
                    },
                    "nom_affiche": {
                      "type": "string"
                    },
                    "telephone": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "actif",
                          "type": "string"
                        },
                        {
                          "const": "suspendu",
                          "type": "string"
                        },
                        {
                          "const": "desactive",
                          "type": "string"
                        }
                      ]
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps ou identifiant invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant, ou compte qui n'est pas membre de l'organisation active (`compte_hors_organisation`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Compte inconnu dans l'organisation active (`utilisateur_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Auto-désactivation (`auto_desactivation_refusee`), ou dernier détenteur de `users.manage` (`dernier_administrateur`) (EC-062).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible ou en échec (`identite_indisponible`) : rien n'est changé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/utilisateurs/{id}/reinitialiser-mot-de-passe": {
      "post": {
        "operationId": "reinitialiserMotDePasse",
        "summary": "Réinitialiser le mot de passe d'un compte (`users.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Mot de passe provisoire, rendu une fois ; sessions révoquées.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "mot_de_passe_temporaire"
                  ],
                  "properties": {
                    "mot_de_passe_temporaire": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Identifiant invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant, ou compte hors de l'organisation active (`compte_hors_organisation`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Compte inconnu dans l'organisation active (`utilisateur_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible ou en échec (`identite_indisponible`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/utilisateurs/{id}/revoquer-sessions": {
      "post": {
        "operationId": "revoquerSessions",
        "summary": "Révoquer toutes les sessions d'un compte (`users.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "204": {
            "description": "Sessions révoquées : reconnexion complète obligatoire."
          },
          "400": {
            "description": "Identifiant invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant, ou compte hors de l'organisation active (`compte_hors_organisation`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Compte inconnu dans l'organisation active (`utilisateur_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible ou en échec (`identite_indisponible`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ensembles-permissions": {
      "get": {
        "operationId": "listerEnsembles",
        "summary": "Ensembles de permissions de l'organisation (`permission_sets.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Ensembles configurés.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "ensembles"
                  ],
                  "properties": {
                    "ensembles": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "libelle",
                          "permissions",
                          "sensible"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "pattern": "^[a-z0-9_]+$",
                            "type": "string"
                          },
                          "libelle": {
                            "type": "string"
                          },
                          "permissions": {
                            "uniqueItems": true,
                            "type": "array",
                            "items": {
                              "minLength": 1,
                              "type": "string"
                            }
                          },
                          "sensible": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "creerEnsemble",
        "summary": "Créer un ensemble de permissions (`permission_sets.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "code",
                  "libelle",
                  "permissions"
                ],
                "properties": {
                  "code": {
                    "pattern": "^[a-z0-9_]+$",
                    "type": "string"
                  },
                  "libelle": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  },
                  "permissions": {
                    "uniqueItems": true,
                    "type": "array",
                    "items": {
                      "minLength": 1,
                      "type": "string"
                    }
                  },
                  "sensible": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Ensemble créé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "libelle",
                    "permissions",
                    "sensible"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "pattern": "^[a-z0-9_]+$",
                      "type": "string"
                    },
                    "libelle": {
                      "type": "string"
                    },
                    "permissions": {
                      "uniqueItems": true,
                      "type": "array",
                      "items": {
                        "minLength": 1,
                        "type": "string"
                      }
                    },
                    "sensible": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide, ou permission hors catalogue (`permission_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Code déjà utilisé (`ensemble_existant`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ensembles-permissions/{id}": {
      "patch": {
        "operationId": "modifierEnsemble",
        "summary": "Modifier un ensemble de permissions (`permission_sets.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "minProperties": 1,
                "type": "object",
                "properties": {
                  "libelle": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  },
                  "permissions": {
                    "uniqueItems": true,
                    "type": "array",
                    "items": {
                      "minLength": 1,
                      "type": "string"
                    }
                  },
                  "sensible": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ensemble modifié ; le second facteur des titulaires est resynchronisé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "libelle",
                    "permissions",
                    "sensible"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "pattern": "^[a-z0-9_]+$",
                      "type": "string"
                    },
                    "libelle": {
                      "type": "string"
                    },
                    "permissions": {
                      "uniqueItems": true,
                      "type": "array",
                      "items": {
                        "minLength": 1,
                        "type": "string"
                      }
                    },
                    "sensible": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide, ou permission hors catalogue (`permission_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Ensemble inconnu (`ensemble_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible ou en échec (`identite_indisponible`) : rien n'est changé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/utilisateurs/{id}/attributions": {
      "post": {
        "operationId": "attribuerEnsemble",
        "summary": "Attribuer un ensemble de permissions à un compte (`permission_sets.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "ensemble_id"
                ],
                "properties": {
                  "ensemble_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Attribution ouverte ; le compte entre dans le groupe du second facteur si l'ensemble est sensible.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "utilisateur_id",
                    "ensemble_id",
                    "debut",
                    "fin"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "utilisateur_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "ensemble_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "debut": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "fin": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps ou identifiant invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Compte (`utilisateur_inconnu`) ou ensemble (`ensemble_inconnu`) inconnu de l'organisation active.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible ou en échec (`identite_indisponible`) : rien n'est changé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/attributions/{id}/terminer": {
      "post": {
        "operationId": "terminerAttribution",
        "summary": "Terminer une attribution d'ensemble (`permission_sets.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Attribution terminée : la permission est retirée dès la requête suivante.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "utilisateur_id",
                    "ensemble_id",
                    "debut",
                    "fin"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "utilisateur_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "ensemble_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "debut": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "fin": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Identifiant invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Attribution inconnue (`attribution_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible ou en échec (`identite_indisponible`) : rien n'est changé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/appareils/{id}/revoquer": {
      "post": {
        "operationId": "revoquerAppareil",
        "summary": "Révoquer un appareil (`devices.manage`)",
        "tags": [
          "Identité"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "motif"
                ],
                "properties": {
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Motif écrit, conservé au journal d'audit.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Appareil révoqué, session hors-ligne de l'agent révoquée, plus aucun jeton PowerSync.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "statut",
                    "revoque_le"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "statut": {
                      "const": "revoque",
                      "type": "string"
                    },
                    "revoque_le": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps ou identifiant invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Appareil inconnu dans l'organisation active (`appareil_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Appareil déjà révoqué (`appareil_deja_revoque`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible ou en échec (`identite_indisponible`) : l'appareil reste actif.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/lots": {
      "get": {
        "operationId": "listerLots",
        "summary": "Lots de l'organisation, avec leur quantité calculée depuis le compte du lot (I4)",
        "tags": [
          "Lots"
        ],
        "parameters": [
          {
            "name": "campagne",
            "in": "query",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "statut",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "emplacement",
            "in": "query",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les lots, du plus récent au plus ancien. La quantité n'est jamais stockée : c'est le solde du compte du lot.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "lots"
                  ],
                  "properties": {
                    "lots": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "reference_provisoire",
                          "numero",
                          "nature",
                          "produit_id",
                          "produit_code",
                          "qualite",
                          "qualites",
                          "statut",
                          "campagne_id",
                          "quantite_totale_g",
                          "quantite_disponible_g",
                          "emplacement_id",
                          "mouvement_creation_id",
                          "date_operation"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "reference_provisoire": {
                            "type": "string"
                          },
                          "numero": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "nature": {
                            "type": "string"
                          },
                          "produit_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "produit_code": {
                            "type": "string"
                          },
                          "qualite": {
                            "type": "string"
                          },
                          "qualites": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {
                                "type": "string"
                              }
                            }
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "brouillon",
                                "type": "string"
                              },
                              {
                                "const": "en_attente",
                                "type": "string"
                              },
                              {
                                "const": "valide",
                                "type": "string"
                              },
                              {
                                "const": "rejete",
                                "type": "string"
                              },
                              {
                                "const": "annule",
                                "type": "string"
                              },
                              {
                                "const": "consomme",
                                "type": "string"
                              },
                              {
                                "const": "quarantaine",
                                "type": "string"
                              },
                              {
                                "const": "archive",
                                "type": "string"
                              }
                            ]
                          },
                          "campagne_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "quantite_totale_g": {
                            "type": "integer"
                          },
                          "quantite_disponible_g": {
                            "type": "integer"
                          },
                          "emplacement_id": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "mouvement_creation_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "date_operation": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Filtre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/lots/{id}": {
      "get": {
        "operationId": "lireLot",
        "summary": "Un lot, avec son emplacement courant et ses quantités",
        "tags": [
          "Lots"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Le lot.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "reference_provisoire",
                    "numero",
                    "nature",
                    "produit_id",
                    "produit_code",
                    "qualite",
                    "qualites",
                    "statut",
                    "campagne_id",
                    "quantite_totale_g",
                    "quantite_disponible_g",
                    "emplacement_id",
                    "mouvement_creation_id",
                    "date_operation"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "reference_provisoire": {
                      "type": "string"
                    },
                    "numero": {
                      "anyOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "nature": {
                      "type": "string"
                    },
                    "produit_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "produit_code": {
                      "type": "string"
                    },
                    "qualite": {
                      "type": "string"
                    },
                    "qualites": {
                      "type": "object",
                      "patternProperties": {
                        "^(.*)$": {
                          "type": "string"
                        }
                      }
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "en_attente",
                          "type": "string"
                        },
                        {
                          "const": "valide",
                          "type": "string"
                        },
                        {
                          "const": "rejete",
                          "type": "string"
                        },
                        {
                          "const": "annule",
                          "type": "string"
                        },
                        {
                          "const": "consomme",
                          "type": "string"
                        },
                        {
                          "const": "quarantaine",
                          "type": "string"
                        },
                        {
                          "const": "archive",
                          "type": "string"
                        }
                      ]
                    },
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "quantite_totale_g": {
                      "type": "integer"
                    },
                    "quantite_disponible_g": {
                      "type": "integer"
                    },
                    "emplacement_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "mouvement_creation_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "date_operation": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Lot inconnu dans l'organisation active (`lot_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/emplacements/{id}/stock": {
      "get": {
        "operationId": "lireStockEmplacement",
        "summary": "Stock d'un emplacement : lots présents, quantité et niveau par rapport à la capacité",
        "tags": [
          "Lots"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Le stock calculé depuis les comptes des lots présents. Un dépassement de capacité est signalé, jamais masqué.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "emplacement_id",
                    "code",
                    "nom",
                    "actif",
                    "qualites_autorisees",
                    "capacite_g",
                    "stock_g",
                    "nombre_lots",
                    "niveau"
                  ],
                  "properties": {
                    "emplacement_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "nom": {
                      "type": "string"
                    },
                    "actif": {
                      "type": "boolean"
                    },
                    "qualites_autorisees": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "capacite_g": {
                      "anyOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "stock_g": {
                      "type": "integer"
                    },
                    "nombre_lots": {
                      "type": "integer"
                    },
                    "niveau": {
                      "anyOf": [
                        {
                          "const": "normal",
                          "type": "string"
                        },
                        {
                          "const": "depassement",
                          "type": "string"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Emplacement inconnu (`emplacement_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/lots/{id}/deplacer": {
      "post": {
        "operationId": "deplacerLot",
        "summary": "Déplacer un lot vers un emplacement (`stock.manage`) : événement en ajout seul, aucun mouvement de matière",
        "tags": [
          "Lots"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "emplacement_id"
                ],
                "properties": {
                  "emplacement_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Le lot déplacé et le niveau de l'emplacement d'arrivée.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "lot",
                    "niveau_emplacement",
                    "excedent_g"
                  ],
                  "properties": {
                    "lot": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "reference_provisoire",
                        "numero",
                        "nature",
                        "produit_id",
                        "produit_code",
                        "qualite",
                        "qualites",
                        "statut",
                        "campagne_id",
                        "quantite_totale_g",
                        "quantite_disponible_g",
                        "emplacement_id",
                        "mouvement_creation_id",
                        "date_operation"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "reference_provisoire": {
                          "type": "string"
                        },
                        "numero": {
                          "anyOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "nature": {
                          "type": "string"
                        },
                        "produit_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "produit_code": {
                          "type": "string"
                        },
                        "qualite": {
                          "type": "string"
                        },
                        "qualites": {
                          "type": "object",
                          "patternProperties": {
                            "^(.*)$": {
                              "type": "string"
                            }
                          }
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "brouillon",
                              "type": "string"
                            },
                            {
                              "const": "en_attente",
                              "type": "string"
                            },
                            {
                              "const": "valide",
                              "type": "string"
                            },
                            {
                              "const": "rejete",
                              "type": "string"
                            },
                            {
                              "const": "annule",
                              "type": "string"
                            },
                            {
                              "const": "consomme",
                              "type": "string"
                            },
                            {
                              "const": "quarantaine",
                              "type": "string"
                            },
                            {
                              "const": "archive",
                              "type": "string"
                            }
                          ]
                        },
                        "campagne_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "quantite_totale_g": {
                          "type": "integer"
                        },
                        "quantite_disponible_g": {
                          "type": "integer"
                        },
                        "emplacement_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "mouvement_creation_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "date_operation": {
                          "format": "date-time",
                          "type": "string"
                        }
                      }
                    },
                    "niveau_emplacement": {
                      "anyOf": [
                        {
                          "const": "normal",
                          "type": "string"
                        },
                        {
                          "const": "depassement",
                          "type": "string"
                        }
                      ]
                    },
                    "excedent_g": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`, `permission_manquante`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Lot ou emplacement inconnu (`lot_introuvable`, `emplacement_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Déplacement refusé : `lot_non_deplacable`, `emplacement_inactif`, `qualite_non_autorisee` (RG-154), `emplacement_inchange` ; module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/receptions": {
      "get": {
        "operationId": "listerReceptions",
        "summary": "Réceptions de l'organisation, de la plus récente à la plus ancienne",
        "tags": [
          "Réception"
        ],
        "parameters": [
          {
            "name": "campagne",
            "in": "query",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "statut",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les réceptions, avec leur poids net marchand.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "receptions"
                  ],
                  "properties": {
                    "receptions": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "campagne_id",
                          "produit_id",
                          "lot_id",
                          "statut",
                          "date_operation",
                          "net_marchand_g"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "campagne_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "produit_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "lot_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "en_attente",
                                "type": "string"
                              },
                              {
                                "const": "validee",
                                "type": "string"
                              },
                              {
                                "const": "rejetee",
                                "type": "string"
                              }
                            ]
                          },
                          "date_operation": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "net_marchand_g": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Filtre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "enregistrerReception",
        "summary": "Enregistrer une réception (`reception.manage`) : double pesée, mesures, poids net marchand sur la formule du contrat, lot en attente (I4)",
        "tags": [
          "Réception"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "campagne_id",
                  "produit_id",
                  "qualite",
                  "pesees"
                ],
                "properties": {
                  "campagne_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "produit_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "producteur_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "fournisseur_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "contrat_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "qualite": {
                    "minLength": 1,
                    "maxLength": 100,
                    "type": "string"
                  },
                  "qualites": {
                    "type": "object",
                    "patternProperties": {
                      "^(.*)$": {
                        "minLength": 1,
                        "maxLength": 100,
                        "type": "string"
                      }
                    }
                  },
                  "date_operation": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "pesees": {
                    "minItems": 1,
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "brut_g",
                        "tare_g"
                      ],
                      "properties": {
                        "brut_g": {
                          "minimum": 0,
                          "description": "Poids brut en grammes.",
                          "type": "integer"
                        },
                        "tare_g": {
                          "minimum": 0,
                          "description": "Tare en grammes, jamais supérieure au brut.",
                          "type": "integer"
                        }
                      }
                    }
                  },
                  "humidite_cp": {
                    "minimum": 0,
                    "maximum": 10000,
                    "description": "Centièmes de point : 1 250 = 12,50 %.",
                    "type": "integer"
                  },
                  "impuretes_cp": {
                    "minimum": 0,
                    "maximum": 10000,
                    "description": "Centièmes de point : 1 250 = 12,50 %.",
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "La réception et son lot, en attente de validation. Le net n'est jamais saisi : il est calculé (RG-170).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "campagne_id",
                    "produit_id",
                    "producteur_id",
                    "fournisseur_id",
                    "contrat_id",
                    "date_operation",
                    "statut",
                    "formule_refaction",
                    "detail_calcul",
                    "net_marchand_g",
                    "pesees",
                    "humidite_cp",
                    "impuretes_cp",
                    "derogation_motif",
                    "constats",
                    "lot"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "produit_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "producteur_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "fournisseur_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "contrat_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "date_operation": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "en_attente",
                          "type": "string"
                        },
                        {
                          "const": "validee",
                          "type": "string"
                        },
                        {
                          "const": "rejetee",
                          "type": "string"
                        }
                      ]
                    },
                    "formule_refaction": {
                      "type": "object",
                      "patternProperties": {
                        "^(.*)$": {}
                      }
                    },
                    "detail_calcul": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "brut_g",
                        "tare_g",
                        "net_g",
                        "excedent_cp",
                        "refaction_g",
                        "net_marchand_g"
                      ],
                      "properties": {
                        "brut_g": {
                          "type": "integer"
                        },
                        "tare_g": {
                          "type": "integer"
                        },
                        "net_g": {
                          "type": "integer"
                        },
                        "excedent_cp": {
                          "type": "integer"
                        },
                        "refaction_g": {
                          "type": "integer"
                        },
                        "net_marchand_g": {
                          "type": "integer"
                        }
                      }
                    },
                    "net_marchand_g": {
                      "type": "integer"
                    },
                    "pesees": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "brut_g",
                          "tare_g"
                        ],
                        "properties": {
                          "brut_g": {
                            "minimum": 0,
                            "description": "Poids brut en grammes.",
                            "type": "integer"
                          },
                          "tare_g": {
                            "minimum": 0,
                            "description": "Tare en grammes, jamais supérieure au brut.",
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "humidite_cp": {
                      "anyOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "impuretes_cp": {
                      "anyOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "derogation_motif": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "constats": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "regle_code",
                          "version",
                          "origine",
                          "resultat",
                          "issue",
                          "motif",
                          "statut",
                          "note",
                          "valeurs"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "regle_code": {
                            "type": "string"
                          },
                          "version": {
                            "type": "string"
                          },
                          "origine": {
                            "anyOf": [
                              {
                                "const": "pack",
                                "type": "string"
                              },
                              {
                                "const": "processus",
                                "type": "string"
                              }
                            ]
                          },
                          "resultat": {
                            "anyOf": [
                              {
                                "const": "ecart",
                                "type": "string"
                              },
                              {
                                "const": "a_verifier",
                                "type": "string"
                              }
                            ]
                          },
                          "issue": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "motif": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "type": "string"
                          },
                          "note": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "valeurs": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          }
                        }
                      }
                    },
                    "lot": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "reference_provisoire",
                        "numero",
                        "nature",
                        "produit_id",
                        "produit_code",
                        "qualite",
                        "qualites",
                        "statut",
                        "campagne_id",
                        "quantite_totale_g",
                        "quantite_disponible_g",
                        "emplacement_id",
                        "mouvement_creation_id",
                        "date_operation"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "reference_provisoire": {
                          "type": "string"
                        },
                        "numero": {
                          "anyOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "nature": {
                          "type": "string"
                        },
                        "produit_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "produit_code": {
                          "type": "string"
                        },
                        "qualite": {
                          "type": "string"
                        },
                        "qualites": {
                          "type": "object",
                          "patternProperties": {
                            "^(.*)$": {
                              "type": "string"
                            }
                          }
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "brouillon",
                              "type": "string"
                            },
                            {
                              "const": "en_attente",
                              "type": "string"
                            },
                            {
                              "const": "valide",
                              "type": "string"
                            },
                            {
                              "const": "rejete",
                              "type": "string"
                            },
                            {
                              "const": "annule",
                              "type": "string"
                            },
                            {
                              "const": "consomme",
                              "type": "string"
                            },
                            {
                              "const": "quarantaine",
                              "type": "string"
                            },
                            {
                              "const": "archive",
                              "type": "string"
                            }
                          ]
                        },
                        "campagne_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "quantite_totale_g": {
                          "type": "integer"
                        },
                        "quantite_disponible_g": {
                          "type": "integer"
                        },
                        "emplacement_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "mouvement_creation_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "date_operation": {
                          "format": "date-time",
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`) ; un producteur ou un fournisseur, pas les deux (`reception_origine_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`, `permission_manquante`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Campagne, produit, producteur, fournisseur ou contrat inconnu.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Refus : `tare_superieure_au_brut`, `mesure_qualite_manquante` (la formule du contrat l'exige), `contrat_non_actif`, `contrat_sans_ligne_pour_le_produit`, `formule_invalide`, `poids_net_nul`, `referentiel_non_coche`, `referentiel_sans_etats`, `etat_inconnu`, `etat_hors_statut` (qualité par référentiel, AM-16) ; module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/receptions/{id}": {
      "get": {
        "operationId": "lireReception",
        "summary": "Une réception : pesées, mesures, calcul figé du poids net marchand, constats et lot",
        "tags": [
          "Réception"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "La réception, avec la formule de réfaction retenue et le détail du calcul (RG-171) et un constat par issue (AM-15).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "campagne_id",
                    "produit_id",
                    "producteur_id",
                    "fournisseur_id",
                    "contrat_id",
                    "date_operation",
                    "statut",
                    "formule_refaction",
                    "detail_calcul",
                    "net_marchand_g",
                    "pesees",
                    "humidite_cp",
                    "impuretes_cp",
                    "derogation_motif",
                    "constats",
                    "lot"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "produit_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "producteur_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "fournisseur_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "contrat_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "date_operation": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "en_attente",
                          "type": "string"
                        },
                        {
                          "const": "validee",
                          "type": "string"
                        },
                        {
                          "const": "rejetee",
                          "type": "string"
                        }
                      ]
                    },
                    "formule_refaction": {
                      "type": "object",
                      "patternProperties": {
                        "^(.*)$": {}
                      }
                    },
                    "detail_calcul": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "brut_g",
                        "tare_g",
                        "net_g",
                        "excedent_cp",
                        "refaction_g",
                        "net_marchand_g"
                      ],
                      "properties": {
                        "brut_g": {
                          "type": "integer"
                        },
                        "tare_g": {
                          "type": "integer"
                        },
                        "net_g": {
                          "type": "integer"
                        },
                        "excedent_cp": {
                          "type": "integer"
                        },
                        "refaction_g": {
                          "type": "integer"
                        },
                        "net_marchand_g": {
                          "type": "integer"
                        }
                      }
                    },
                    "net_marchand_g": {
                      "type": "integer"
                    },
                    "pesees": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "brut_g",
                          "tare_g"
                        ],
                        "properties": {
                          "brut_g": {
                            "minimum": 0,
                            "description": "Poids brut en grammes.",
                            "type": "integer"
                          },
                          "tare_g": {
                            "minimum": 0,
                            "description": "Tare en grammes, jamais supérieure au brut.",
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "humidite_cp": {
                      "anyOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "impuretes_cp": {
                      "anyOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "derogation_motif": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "constats": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "regle_code",
                          "version",
                          "origine",
                          "resultat",
                          "issue",
                          "motif",
                          "statut",
                          "note",
                          "valeurs"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "regle_code": {
                            "type": "string"
                          },
                          "version": {
                            "type": "string"
                          },
                          "origine": {
                            "anyOf": [
                              {
                                "const": "pack",
                                "type": "string"
                              },
                              {
                                "const": "processus",
                                "type": "string"
                              }
                            ]
                          },
                          "resultat": {
                            "anyOf": [
                              {
                                "const": "ecart",
                                "type": "string"
                              },
                              {
                                "const": "a_verifier",
                                "type": "string"
                              }
                            ]
                          },
                          "issue": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "motif": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "type": "string"
                          },
                          "note": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "valeurs": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          }
                        }
                      }
                    },
                    "lot": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "reference_provisoire",
                        "numero",
                        "nature",
                        "produit_id",
                        "produit_code",
                        "qualite",
                        "qualites",
                        "statut",
                        "campagne_id",
                        "quantite_totale_g",
                        "quantite_disponible_g",
                        "emplacement_id",
                        "mouvement_creation_id",
                        "date_operation"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "reference_provisoire": {
                          "type": "string"
                        },
                        "numero": {
                          "anyOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "nature": {
                          "type": "string"
                        },
                        "produit_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "produit_code": {
                          "type": "string"
                        },
                        "qualite": {
                          "type": "string"
                        },
                        "qualites": {
                          "type": "object",
                          "patternProperties": {
                            "^(.*)$": {
                              "type": "string"
                            }
                          }
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "brouillon",
                              "type": "string"
                            },
                            {
                              "const": "en_attente",
                              "type": "string"
                            },
                            {
                              "const": "valide",
                              "type": "string"
                            },
                            {
                              "const": "rejete",
                              "type": "string"
                            },
                            {
                              "const": "annule",
                              "type": "string"
                            },
                            {
                              "const": "consomme",
                              "type": "string"
                            },
                            {
                              "const": "quarantaine",
                              "type": "string"
                            },
                            {
                              "const": "archive",
                              "type": "string"
                            }
                          ]
                        },
                        "campagne_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "quantite_totale_g": {
                          "type": "integer"
                        },
                        "quantite_disponible_g": {
                          "type": "integer"
                        },
                        "emplacement_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "mouvement_creation_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "date_operation": {
                          "format": "date-time",
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Réception inconnue dans l'organisation active (`reception_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/receptions/{id}/valider": {
      "post": {
        "operationId": "validerReception",
        "summary": "Valider une réception (`reception.manage`) : certificat (RG-014), seuils (RG-172), règles du référentiel, quarantaine (I5), numéro officiel",
        "tags": [
          "Réception"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "properties": {
                  "note": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  },
                  "derogation_motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "La réception validée, avec ses constats. `quarantaine` est vrai quand le lot a été mis en quarantaine.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "reception",
                    "quarantaine"
                  ],
                  "properties": {
                    "reception": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "campagne_id",
                        "produit_id",
                        "producteur_id",
                        "fournisseur_id",
                        "contrat_id",
                        "date_operation",
                        "statut",
                        "formule_refaction",
                        "detail_calcul",
                        "net_marchand_g",
                        "pesees",
                        "humidite_cp",
                        "impuretes_cp",
                        "derogation_motif",
                        "constats",
                        "lot"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "campagne_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "produit_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "producteur_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "fournisseur_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "contrat_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "date_operation": {
                          "format": "date-time",
                          "type": "string"
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "en_attente",
                              "type": "string"
                            },
                            {
                              "const": "validee",
                              "type": "string"
                            },
                            {
                              "const": "rejetee",
                              "type": "string"
                            }
                          ]
                        },
                        "formule_refaction": {
                          "type": "object",
                          "patternProperties": {
                            "^(.*)$": {}
                          }
                        },
                        "detail_calcul": {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "brut_g",
                            "tare_g",
                            "net_g",
                            "excedent_cp",
                            "refaction_g",
                            "net_marchand_g"
                          ],
                          "properties": {
                            "brut_g": {
                              "type": "integer"
                            },
                            "tare_g": {
                              "type": "integer"
                            },
                            "net_g": {
                              "type": "integer"
                            },
                            "excedent_cp": {
                              "type": "integer"
                            },
                            "refaction_g": {
                              "type": "integer"
                            },
                            "net_marchand_g": {
                              "type": "integer"
                            }
                          }
                        },
                        "net_marchand_g": {
                          "type": "integer"
                        },
                        "pesees": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "brut_g",
                              "tare_g"
                            ],
                            "properties": {
                              "brut_g": {
                                "minimum": 0,
                                "description": "Poids brut en grammes.",
                                "type": "integer"
                              },
                              "tare_g": {
                                "minimum": 0,
                                "description": "Tare en grammes, jamais supérieure au brut.",
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "humidite_cp": {
                          "anyOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "impuretes_cp": {
                          "anyOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "derogation_motif": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "constats": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "regle_code",
                              "version",
                              "origine",
                              "resultat",
                              "issue",
                              "motif",
                              "statut",
                              "note",
                              "valeurs"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "regle_code": {
                                "type": "string"
                              },
                              "version": {
                                "type": "string"
                              },
                              "origine": {
                                "anyOf": [
                                  {
                                    "const": "pack",
                                    "type": "string"
                                  },
                                  {
                                    "const": "processus",
                                    "type": "string"
                                  }
                                ]
                              },
                              "resultat": {
                                "anyOf": [
                                  {
                                    "const": "ecart",
                                    "type": "string"
                                  },
                                  {
                                    "const": "a_verifier",
                                    "type": "string"
                                  }
                                ]
                              },
                              "issue": {
                                "anyOf": [
                                  {
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "motif": {
                                "anyOf": [
                                  {
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "statut": {
                                "type": "string"
                              },
                              "note": {
                                "anyOf": [
                                  {
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "valeurs": {
                                "type": "object",
                                "patternProperties": {
                                  "^(.*)$": {}
                                }
                              }
                            }
                          }
                        },
                        "lot": {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "id",
                            "reference_provisoire",
                            "numero",
                            "nature",
                            "produit_id",
                            "produit_code",
                            "qualite",
                            "qualites",
                            "statut",
                            "campagne_id",
                            "quantite_totale_g",
                            "quantite_disponible_g",
                            "emplacement_id",
                            "mouvement_creation_id",
                            "date_operation"
                          ],
                          "properties": {
                            "id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "reference_provisoire": {
                              "type": "string"
                            },
                            "numero": {
                              "anyOf": [
                                {
                                  "type": "integer"
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "nature": {
                              "type": "string"
                            },
                            "produit_id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "produit_code": {
                              "type": "string"
                            },
                            "qualite": {
                              "type": "string"
                            },
                            "qualites": {
                              "type": "object",
                              "patternProperties": {
                                "^(.*)$": {
                                  "type": "string"
                                }
                              }
                            },
                            "statut": {
                              "anyOf": [
                                {
                                  "const": "brouillon",
                                  "type": "string"
                                },
                                {
                                  "const": "en_attente",
                                  "type": "string"
                                },
                                {
                                  "const": "valide",
                                  "type": "string"
                                },
                                {
                                  "const": "rejete",
                                  "type": "string"
                                },
                                {
                                  "const": "annule",
                                  "type": "string"
                                },
                                {
                                  "const": "consomme",
                                  "type": "string"
                                },
                                {
                                  "const": "quarantaine",
                                  "type": "string"
                                },
                                {
                                  "const": "archive",
                                  "type": "string"
                                }
                              ]
                            },
                            "campagne_id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "quantite_totale_g": {
                              "type": "integer"
                            },
                            "quantite_disponible_g": {
                              "type": "integer"
                            },
                            "emplacement_id": {
                              "anyOf": [
                                {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "mouvement_creation_id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "date_operation": {
                              "format": "date-time",
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "quarantaine": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Réception inconnue (`reception_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Refus : `reception_bloquee` (les constats du refus sont conservés ; le détail dit si la direction peut déroger), `note_requise`, `reception_deja_decidee`, `reglage_invalide` ; module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/lots/{id}/lever-quarantaine": {
      "post": {
        "operationId": "leverQuarantaineLot",
        "summary": "Lever la quarantaine d'un lot (`stock.release_quarantine`) : motif obligatoire, le lot redevient validé (RG-161)",
        "tags": [
          "Lots"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "motif"
                ],
                "properties": {
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Le lot validé de nouveau ; ses sorties sont rouvertes (I5).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "reference_provisoire",
                    "numero",
                    "nature",
                    "produit_id",
                    "produit_code",
                    "qualite",
                    "qualites",
                    "statut",
                    "campagne_id",
                    "quantite_totale_g",
                    "quantite_disponible_g",
                    "emplacement_id",
                    "mouvement_creation_id",
                    "date_operation"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "reference_provisoire": {
                      "type": "string"
                    },
                    "numero": {
                      "anyOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "nature": {
                      "type": "string"
                    },
                    "produit_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "produit_code": {
                      "type": "string"
                    },
                    "qualite": {
                      "type": "string"
                    },
                    "qualites": {
                      "type": "object",
                      "patternProperties": {
                        "^(.*)$": {
                          "type": "string"
                        }
                      }
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "en_attente",
                          "type": "string"
                        },
                        {
                          "const": "valide",
                          "type": "string"
                        },
                        {
                          "const": "rejete",
                          "type": "string"
                        },
                        {
                          "const": "annule",
                          "type": "string"
                        },
                        {
                          "const": "consomme",
                          "type": "string"
                        },
                        {
                          "const": "quarantaine",
                          "type": "string"
                        },
                        {
                          "const": "archive",
                          "type": "string"
                        }
                      ]
                    },
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "quantite_totale_g": {
                      "type": "integer"
                    },
                    "quantite_disponible_g": {
                      "type": "integer"
                    },
                    "emplacement_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "mouvement_creation_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "date_operation": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Droit manquant (`droit_manquant`, `permission_manquante`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Lot inconnu (`lot_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Le lot n'est pas en quarantaine (`lot_pas_en_quarantaine`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/receptions/{id}/devalider": {
      "post": {
        "operationId": "devaliderReception",
        "summary": "Dévalider une réception (`stock.reverse`, direction) : contre-passe la création du lot, le lot est annulé (numéro conservé), la réception revient en attente sur un nouveau lot (RG-032)",
        "tags": [
          "Annulations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "motif"
                ],
                "properties": {
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Justification écrite, obligatoire.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "La réception en attente, son nouveau lot, la ligne du registre et le constat consigné (AM-15).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "registre",
                    "statut",
                    "lots_annules",
                    "lots_restitues",
                    "nouveau_lot_id"
                  ],
                  "properties": {
                    "registre": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "objet_type",
                        "objet_id",
                        "nature",
                        "motif",
                        "lot_id",
                        "lot_numero",
                        "campagne_id",
                        "mouvement_id",
                        "constat_id",
                        "cree_par",
                        "cree_le"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "objet_type": {
                          "anyOf": [
                            {
                              "const": "reception",
                              "type": "string"
                            },
                            {
                              "const": "etape_realisee",
                              "type": "string"
                            },
                            {
                              "const": "expedition",
                              "type": "string"
                            },
                            {
                              "const": "vente",
                              "type": "string"
                            },
                            {
                              "const": "lot",
                              "type": "string"
                            }
                          ]
                        },
                        "objet_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "nature": {
                          "anyOf": [
                            {
                              "const": "devalidation",
                              "type": "string"
                            },
                            {
                              "const": "annulation",
                              "type": "string"
                            }
                          ]
                        },
                        "motif": {
                          "type": "string"
                        },
                        "lot_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "lot_numero": {
                          "description": "Numéro officiel conservé du lot annulé (RG-143).",
                          "anyOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "campagne_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "mouvement_id": {
                          "description": "Mouvement de contre-passation.",
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "constat_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "cree_par": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "cree_le": {
                          "format": "date-time",
                          "type": "string"
                        }
                      }
                    },
                    "statut": {
                      "description": "Nouveau statut de l'objet défait.",
                      "type": "string"
                    },
                    "lots_annules": {
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "lots_restitues": {
                      "description": "Lots consommés qui redeviennent validés.",
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "nouveau_lot_id": {
                      "description": "Lot en attente repris par une réception dévalidée.",
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide : motif absent (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Réception inconnue (`reception_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "`aval_non_contrepasse` (`details.bloquants` nomme les objets d'aval à défaire d'abord), `lot_en_quarantaine` (lever la quarantaine d'abord, I5), `statut_non_defaisable`, `module_inactif` (lecture seule).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/etapes/{id}/devalider": {
      "post": {
        "operationId": "devaliderEtape",
        "summary": "Dévalider une étape validée (`stock.reverse`, direction) : contre-passe la transformation, annule les lots de sortie, rend leurs lots d'entrée, rouvre l'étape et l'ordre (RG-032)",
        "tags": [
          "Annulations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "motif"
                ],
                "properties": {
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Justification écrite, obligatoire.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "L'étape en cours, les lots annulés et restitués, la ligne du registre et le constat.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "registre",
                    "statut",
                    "lots_annules",
                    "lots_restitues",
                    "nouveau_lot_id"
                  ],
                  "properties": {
                    "registre": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "objet_type",
                        "objet_id",
                        "nature",
                        "motif",
                        "lot_id",
                        "lot_numero",
                        "campagne_id",
                        "mouvement_id",
                        "constat_id",
                        "cree_par",
                        "cree_le"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "objet_type": {
                          "anyOf": [
                            {
                              "const": "reception",
                              "type": "string"
                            },
                            {
                              "const": "etape_realisee",
                              "type": "string"
                            },
                            {
                              "const": "expedition",
                              "type": "string"
                            },
                            {
                              "const": "vente",
                              "type": "string"
                            },
                            {
                              "const": "lot",
                              "type": "string"
                            }
                          ]
                        },
                        "objet_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "nature": {
                          "anyOf": [
                            {
                              "const": "devalidation",
                              "type": "string"
                            },
                            {
                              "const": "annulation",
                              "type": "string"
                            }
                          ]
                        },
                        "motif": {
                          "type": "string"
                        },
                        "lot_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "lot_numero": {
                          "description": "Numéro officiel conservé du lot annulé (RG-143).",
                          "anyOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "campagne_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "mouvement_id": {
                          "description": "Mouvement de contre-passation.",
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "constat_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "cree_par": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "cree_le": {
                          "format": "date-time",
                          "type": "string"
                        }
                      }
                    },
                    "statut": {
                      "description": "Nouveau statut de l'objet défait.",
                      "type": "string"
                    },
                    "lots_annules": {
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "lots_restitues": {
                      "description": "Lots consommés qui redeviennent validés.",
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "nouveau_lot_id": {
                      "description": "Lot en attente repris par une réception dévalidée.",
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide : motif absent (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Étape inconnue (`etape_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "`aval_non_contrepasse` (`details.bloquants` nomme les objets d'aval à défaire d'abord), `lot_en_quarantaine` (lever la quarantaine d'abord, I5), `statut_non_defaisable`, `module_inactif`.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/expeditions/{id}/devalider": {
      "post": {
        "operationId": "devaliderExpedition",
        "summary": "Dévalider une expédition validée (`stock.reverse`, direction) : contre-passe le mouvement, rend les lots, l'expédition revient en brouillon et la vente soldée redevient validée (RG-032)",
        "tags": [
          "Annulations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "motif"
                ],
                "properties": {
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Justification écrite, obligatoire.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "L'expédition en brouillon, les lots restitués, la ligne du registre et le constat.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "registre",
                    "statut",
                    "lots_annules",
                    "lots_restitues",
                    "nouveau_lot_id"
                  ],
                  "properties": {
                    "registre": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "objet_type",
                        "objet_id",
                        "nature",
                        "motif",
                        "lot_id",
                        "lot_numero",
                        "campagne_id",
                        "mouvement_id",
                        "constat_id",
                        "cree_par",
                        "cree_le"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "objet_type": {
                          "anyOf": [
                            {
                              "const": "reception",
                              "type": "string"
                            },
                            {
                              "const": "etape_realisee",
                              "type": "string"
                            },
                            {
                              "const": "expedition",
                              "type": "string"
                            },
                            {
                              "const": "vente",
                              "type": "string"
                            },
                            {
                              "const": "lot",
                              "type": "string"
                            }
                          ]
                        },
                        "objet_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "nature": {
                          "anyOf": [
                            {
                              "const": "devalidation",
                              "type": "string"
                            },
                            {
                              "const": "annulation",
                              "type": "string"
                            }
                          ]
                        },
                        "motif": {
                          "type": "string"
                        },
                        "lot_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "lot_numero": {
                          "description": "Numéro officiel conservé du lot annulé (RG-143).",
                          "anyOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "campagne_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "mouvement_id": {
                          "description": "Mouvement de contre-passation.",
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "constat_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "cree_par": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "cree_le": {
                          "format": "date-time",
                          "type": "string"
                        }
                      }
                    },
                    "statut": {
                      "description": "Nouveau statut de l'objet défait.",
                      "type": "string"
                    },
                    "lots_annules": {
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "lots_restitues": {
                      "description": "Lots consommés qui redeviennent validés.",
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "nouveau_lot_id": {
                      "description": "Lot en attente repris par une réception dévalidée.",
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide : motif absent (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Expédition inconnue (`expedition_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "`aval_non_contrepasse` (`details.bloquants` nomme les objets d'aval à défaire d'abord), `lot_en_quarantaine` (lever la quarantaine d'abord, I5), `statut_non_defaisable`, `module_inactif`.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ventes/{id}/annuler": {
      "post": {
        "operationId": "annulerVente",
        "summary": "Annuler une vente (`stock.reverse`, direction) : seulement sans expédition validée, motif obligatoire (RG-143)",
        "tags": [
          "Annulations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "motif"
                ],
                "properties": {
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Justification écrite, obligatoire.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "La vente annulée et la ligne du registre.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "registre",
                    "statut",
                    "lots_annules",
                    "lots_restitues",
                    "nouveau_lot_id"
                  ],
                  "properties": {
                    "registre": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "objet_type",
                        "objet_id",
                        "nature",
                        "motif",
                        "lot_id",
                        "lot_numero",
                        "campagne_id",
                        "mouvement_id",
                        "constat_id",
                        "cree_par",
                        "cree_le"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "objet_type": {
                          "anyOf": [
                            {
                              "const": "reception",
                              "type": "string"
                            },
                            {
                              "const": "etape_realisee",
                              "type": "string"
                            },
                            {
                              "const": "expedition",
                              "type": "string"
                            },
                            {
                              "const": "vente",
                              "type": "string"
                            },
                            {
                              "const": "lot",
                              "type": "string"
                            }
                          ]
                        },
                        "objet_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "nature": {
                          "anyOf": [
                            {
                              "const": "devalidation",
                              "type": "string"
                            },
                            {
                              "const": "annulation",
                              "type": "string"
                            }
                          ]
                        },
                        "motif": {
                          "type": "string"
                        },
                        "lot_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "lot_numero": {
                          "description": "Numéro officiel conservé du lot annulé (RG-143).",
                          "anyOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "campagne_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "mouvement_id": {
                          "description": "Mouvement de contre-passation.",
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "constat_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "cree_par": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "cree_le": {
                          "format": "date-time",
                          "type": "string"
                        }
                      }
                    },
                    "statut": {
                      "description": "Nouveau statut de l'objet défait.",
                      "type": "string"
                    },
                    "lots_annules": {
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "lots_restitues": {
                      "description": "Lots consommés qui redeviennent validés.",
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "nouveau_lot_id": {
                      "description": "Lot en attente repris par une réception dévalidée.",
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide : motif absent (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Vente inconnue (`vente_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "`aval_non_contrepasse` (`details.bloquants` nomme les objets d'aval à défaire d'abord), `lot_en_quarantaine` (lever la quarantaine d'abord, I5), `statut_non_defaisable`, `module_inactif`.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/lots/{id}/annuler": {
      "post": {
        "operationId": "annulerLot",
        "summary": "Annuler un lot validé (`stock.reverse`, direction) : contre-passe sa création, numéro conservé, motif obligatoire ; impossible si le lot est consommé ou vendu (RG-143)",
        "tags": [
          "Annulations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "motif"
                ],
                "properties": {
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Justification écrite, obligatoire.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Le lot annulé et la ligne du registre.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "registre",
                    "statut",
                    "lots_annules",
                    "lots_restitues",
                    "nouveau_lot_id"
                  ],
                  "properties": {
                    "registre": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "objet_type",
                        "objet_id",
                        "nature",
                        "motif",
                        "lot_id",
                        "lot_numero",
                        "campagne_id",
                        "mouvement_id",
                        "constat_id",
                        "cree_par",
                        "cree_le"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "objet_type": {
                          "anyOf": [
                            {
                              "const": "reception",
                              "type": "string"
                            },
                            {
                              "const": "etape_realisee",
                              "type": "string"
                            },
                            {
                              "const": "expedition",
                              "type": "string"
                            },
                            {
                              "const": "vente",
                              "type": "string"
                            },
                            {
                              "const": "lot",
                              "type": "string"
                            }
                          ]
                        },
                        "objet_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "nature": {
                          "anyOf": [
                            {
                              "const": "devalidation",
                              "type": "string"
                            },
                            {
                              "const": "annulation",
                              "type": "string"
                            }
                          ]
                        },
                        "motif": {
                          "type": "string"
                        },
                        "lot_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "lot_numero": {
                          "description": "Numéro officiel conservé du lot annulé (RG-143).",
                          "anyOf": [
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "campagne_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "mouvement_id": {
                          "description": "Mouvement de contre-passation.",
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "constat_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "cree_par": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "cree_le": {
                          "format": "date-time",
                          "type": "string"
                        }
                      }
                    },
                    "statut": {
                      "description": "Nouveau statut de l'objet défait.",
                      "type": "string"
                    },
                    "lots_annules": {
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "lots_restitues": {
                      "description": "Lots consommés qui redeviennent validés.",
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "nouveau_lot_id": {
                      "description": "Lot en attente repris par une réception dévalidée.",
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide : motif absent (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Lot inconnu (`lot_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "`lot_consomme_ou_vendu`, `lot_issu_d_une_etape` (dévalider l'étape), `aval_non_contrepasse` (`details.bloquants` nomme les objets d'aval à défaire d'abord), `lot_en_quarantaine` (lever la quarantaine d'abord, I5), `statut_non_defaisable`",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/lots/{id}/descendance": {
      "get": {
        "operationId": "lireDescendanceLot",
        "summary": "Le lot et tous les lots créés à partir de lui, avec la profondeur (RG-160)",
        "tags": [
          "Rappel"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les lots de la descendance.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "lot_id",
                    "lots"
                  ],
                  "properties": {
                    "lot_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "lots": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "lot_id",
                          "profondeur"
                        ],
                        "properties": {
                          "lot_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "profondeur": {
                            "minimum": 0,
                            "description": "0 pour le lot de départ.",
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Lot inconnu (`lot_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/lots/{id}/ascendance": {
      "get": {
        "operationId": "lireAscendanceLot",
        "summary": "Le lot et tous les lots dont il provient, avec la profondeur (rappel ascendant, RG-160)",
        "tags": [
          "Rappel"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les lots d'origine.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "lot_id",
                    "lots"
                  ],
                  "properties": {
                    "lot_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "lots": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "lot_id",
                          "profondeur"
                        ],
                        "properties": {
                          "lot_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "profondeur": {
                            "minimum": 0,
                            "description": "0 pour le lot de départ.",
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Lot inconnu (`lot_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/rappels": {
      "post": {
        "operationId": "ouvrirRappel",
        "summary": "Ouvrir un rappel à partir d'un lot (`recall.manage`, direction) : plan figé, lots validés mis en quarantaine ; `simule` = exercice à blanc sans aucun effet (RG-160 à RG-163)",
        "tags": [
          "Rappel"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "lot_id",
                  "motif"
                ],
                "properties": {
                  "lot_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  },
                  "simule": {
                    "description": "Exercice à blanc (RG-163) : calcule et archive le plan, ne modifie aucune autre donnée. Faux par défaut.",
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Le rappel ouvert (ou la simulation archivée), avec son plan et sa chronologie.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "lot_depart_id",
                    "motif",
                    "simule",
                    "statut",
                    "plan",
                    "duree_calcul_ms",
                    "lots_mis_en_quarantaine",
                    "lots_non_bloquables",
                    "decision_cloture",
                    "organisme_informe_le",
                    "organisme_reference",
                    "quantite_retournee_g",
                    "quantite_detruite_g",
                    "quantite_declassee_g",
                    "clos_le",
                    "cree_par",
                    "cree_le",
                    "evenements"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "lot_depart_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "motif": {
                      "type": "string"
                    },
                    "simule": {
                      "type": "boolean"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "ouvert",
                          "type": "string"
                        },
                        {
                          "const": "clos",
                          "type": "string"
                        },
                        {
                          "const": "simule",
                          "type": "string"
                        }
                      ]
                    },
                    "plan": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "lot_depart_id",
                        "lots_descendants",
                        "lots_ascendants",
                        "clients",
                        "quantite_livree_g"
                      ],
                      "properties": {
                        "lot_depart_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "lots_descendants": {
                          "description": "Le lot de départ et ses descendants : ce que l'on bloque (RG-161).",
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "lot_id",
                              "profondeur"
                            ],
                            "properties": {
                              "lot_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "profondeur": {
                                "minimum": 0,
                                "description": "0 pour le lot de départ.",
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "lots_ascendants": {
                          "description": "Les lots d'origine : ce que l'on examine pour la cause.",
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "lot_id",
                              "profondeur"
                            ],
                            "properties": {
                              "lot_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "profondeur": {
                                "minimum": 0,
                                "description": "0 pour le lot de départ.",
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "clients": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "client_id",
                              "quantite_g",
                              "lots",
                              "ventes",
                              "expeditions"
                            ],
                            "properties": {
                              "client_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "quantite_g": {
                                "minimum": 0,
                                "description": "Grammes.",
                                "type": "integer"
                              },
                              "lots": {
                                "type": "array",
                                "items": {
                                  "format": "uuid",
                                  "type": "string"
                                }
                              },
                              "ventes": {
                                "type": "array",
                                "items": {
                                  "format": "uuid",
                                  "type": "string"
                                }
                              },
                              "expeditions": {
                                "type": "array",
                                "items": {
                                  "format": "uuid",
                                  "type": "string"
                                }
                              }
                            }
                          }
                        },
                        "quantite_livree_g": {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        }
                      }
                    },
                    "duree_calcul_ms": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "lots_mis_en_quarantaine": {
                      "description": "Lots effectivement passés en quarantaine à l'ouverture ; vide pour une simulation.",
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "lots_non_bloquables": {
                      "description": "Lots du plan qui ne sont pas validés (consommés, rejetés…) : à traiter à la main.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "lot_id",
                          "statut"
                        ],
                        "properties": {
                          "lot_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "statut": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "decision_cloture": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "organisme_informe_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "organisme_reference": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_retournee_g": {
                      "anyOf": [
                        {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_detruite_g": {
                      "anyOf": [
                        {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_declassee_g": {
                      "anyOf": [
                        {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "clos_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "cree_par": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "evenements": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "type",
                          "detail",
                          "cree_par",
                          "cree_le"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "type": {
                            "anyOf": [
                              {
                                "const": "ouverture",
                                "type": "string"
                              },
                              {
                                "const": "lot_quarantaine",
                                "type": "string"
                              },
                              {
                                "const": "organisme_informe",
                                "type": "string"
                              },
                              {
                                "const": "cloture",
                                "type": "string"
                              }
                            ]
                          },
                          "detail": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          },
                          "cree_par": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Lot inconnu (`lot_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/rappels/{id}": {
      "get": {
        "operationId": "lireRappel",
        "summary": "Dossier d'un rappel : plan, chronologie, clôture (RG-162)",
        "tags": [
          "Rappel"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Le dossier du rappel.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "lot_depart_id",
                    "motif",
                    "simule",
                    "statut",
                    "plan",
                    "duree_calcul_ms",
                    "lots_mis_en_quarantaine",
                    "lots_non_bloquables",
                    "decision_cloture",
                    "organisme_informe_le",
                    "organisme_reference",
                    "quantite_retournee_g",
                    "quantite_detruite_g",
                    "quantite_declassee_g",
                    "clos_le",
                    "cree_par",
                    "cree_le",
                    "evenements"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "lot_depart_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "motif": {
                      "type": "string"
                    },
                    "simule": {
                      "type": "boolean"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "ouvert",
                          "type": "string"
                        },
                        {
                          "const": "clos",
                          "type": "string"
                        },
                        {
                          "const": "simule",
                          "type": "string"
                        }
                      ]
                    },
                    "plan": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "lot_depart_id",
                        "lots_descendants",
                        "lots_ascendants",
                        "clients",
                        "quantite_livree_g"
                      ],
                      "properties": {
                        "lot_depart_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "lots_descendants": {
                          "description": "Le lot de départ et ses descendants : ce que l'on bloque (RG-161).",
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "lot_id",
                              "profondeur"
                            ],
                            "properties": {
                              "lot_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "profondeur": {
                                "minimum": 0,
                                "description": "0 pour le lot de départ.",
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "lots_ascendants": {
                          "description": "Les lots d'origine : ce que l'on examine pour la cause.",
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "lot_id",
                              "profondeur"
                            ],
                            "properties": {
                              "lot_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "profondeur": {
                                "minimum": 0,
                                "description": "0 pour le lot de départ.",
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "clients": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "client_id",
                              "quantite_g",
                              "lots",
                              "ventes",
                              "expeditions"
                            ],
                            "properties": {
                              "client_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "quantite_g": {
                                "minimum": 0,
                                "description": "Grammes.",
                                "type": "integer"
                              },
                              "lots": {
                                "type": "array",
                                "items": {
                                  "format": "uuid",
                                  "type": "string"
                                }
                              },
                              "ventes": {
                                "type": "array",
                                "items": {
                                  "format": "uuid",
                                  "type": "string"
                                }
                              },
                              "expeditions": {
                                "type": "array",
                                "items": {
                                  "format": "uuid",
                                  "type": "string"
                                }
                              }
                            }
                          }
                        },
                        "quantite_livree_g": {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        }
                      }
                    },
                    "duree_calcul_ms": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "lots_mis_en_quarantaine": {
                      "description": "Lots effectivement passés en quarantaine à l'ouverture ; vide pour une simulation.",
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "lots_non_bloquables": {
                      "description": "Lots du plan qui ne sont pas validés (consommés, rejetés…) : à traiter à la main.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "lot_id",
                          "statut"
                        ],
                        "properties": {
                          "lot_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "statut": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "decision_cloture": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "organisme_informe_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "organisme_reference": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_retournee_g": {
                      "anyOf": [
                        {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_detruite_g": {
                      "anyOf": [
                        {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_declassee_g": {
                      "anyOf": [
                        {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "clos_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "cree_par": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "evenements": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "type",
                          "detail",
                          "cree_par",
                          "cree_le"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "type": {
                            "anyOf": [
                              {
                                "const": "ouverture",
                                "type": "string"
                              },
                              {
                                "const": "lot_quarantaine",
                                "type": "string"
                              },
                              {
                                "const": "organisme_informe",
                                "type": "string"
                              },
                              {
                                "const": "cloture",
                                "type": "string"
                              }
                            ]
                          },
                          "detail": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          },
                          "cree_par": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Rappel inconnu (`rappel_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/rappels/{id}/cloturer": {
      "post": {
        "operationId": "cloturerRappel",
        "summary": "Clore un rappel (`recall.manage`, direction) : décision motivée, quantités, information de l'organisme certificateur (RG-162)",
        "tags": [
          "Rappel"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "decision"
                ],
                "properties": {
                  "decision": {
                    "minLength": 1,
                    "maxLength": 1000,
                    "description": "Décision de clôture (RG-162).",
                    "type": "string"
                  },
                  "organisme_informe": {
                    "description": "L'organisme certificateur a été informé.",
                    "type": "boolean"
                  },
                  "organisme_reference": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  },
                  "quantite_retournee_g": {
                    "minimum": 0,
                    "description": "Grammes.",
                    "type": "integer"
                  },
                  "quantite_detruite_g": {
                    "minimum": 0,
                    "description": "Grammes.",
                    "type": "integer"
                  },
                  "quantite_declassee_g": {
                    "minimum": 0,
                    "description": "Grammes.",
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Le rappel clos.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "lot_depart_id",
                    "motif",
                    "simule",
                    "statut",
                    "plan",
                    "duree_calcul_ms",
                    "lots_mis_en_quarantaine",
                    "lots_non_bloquables",
                    "decision_cloture",
                    "organisme_informe_le",
                    "organisme_reference",
                    "quantite_retournee_g",
                    "quantite_detruite_g",
                    "quantite_declassee_g",
                    "clos_le",
                    "cree_par",
                    "cree_le",
                    "evenements"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "lot_depart_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "motif": {
                      "type": "string"
                    },
                    "simule": {
                      "type": "boolean"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "ouvert",
                          "type": "string"
                        },
                        {
                          "const": "clos",
                          "type": "string"
                        },
                        {
                          "const": "simule",
                          "type": "string"
                        }
                      ]
                    },
                    "plan": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "lot_depart_id",
                        "lots_descendants",
                        "lots_ascendants",
                        "clients",
                        "quantite_livree_g"
                      ],
                      "properties": {
                        "lot_depart_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "lots_descendants": {
                          "description": "Le lot de départ et ses descendants : ce que l'on bloque (RG-161).",
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "lot_id",
                              "profondeur"
                            ],
                            "properties": {
                              "lot_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "profondeur": {
                                "minimum": 0,
                                "description": "0 pour le lot de départ.",
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "lots_ascendants": {
                          "description": "Les lots d'origine : ce que l'on examine pour la cause.",
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "lot_id",
                              "profondeur"
                            ],
                            "properties": {
                              "lot_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "profondeur": {
                                "minimum": 0,
                                "description": "0 pour le lot de départ.",
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "clients": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "client_id",
                              "quantite_g",
                              "lots",
                              "ventes",
                              "expeditions"
                            ],
                            "properties": {
                              "client_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "quantite_g": {
                                "minimum": 0,
                                "description": "Grammes.",
                                "type": "integer"
                              },
                              "lots": {
                                "type": "array",
                                "items": {
                                  "format": "uuid",
                                  "type": "string"
                                }
                              },
                              "ventes": {
                                "type": "array",
                                "items": {
                                  "format": "uuid",
                                  "type": "string"
                                }
                              },
                              "expeditions": {
                                "type": "array",
                                "items": {
                                  "format": "uuid",
                                  "type": "string"
                                }
                              }
                            }
                          }
                        },
                        "quantite_livree_g": {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        }
                      }
                    },
                    "duree_calcul_ms": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "lots_mis_en_quarantaine": {
                      "description": "Lots effectivement passés en quarantaine à l'ouverture ; vide pour une simulation.",
                      "type": "array",
                      "items": {
                        "format": "uuid",
                        "type": "string"
                      }
                    },
                    "lots_non_bloquables": {
                      "description": "Lots du plan qui ne sont pas validés (consommés, rejetés…) : à traiter à la main.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "lot_id",
                          "statut"
                        ],
                        "properties": {
                          "lot_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "statut": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "decision_cloture": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "organisme_informe_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "organisme_reference": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_retournee_g": {
                      "anyOf": [
                        {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_detruite_g": {
                      "anyOf": [
                        {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_declassee_g": {
                      "anyOf": [
                        {
                          "minimum": 0,
                          "description": "Grammes.",
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "clos_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "cree_par": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "evenements": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "type",
                          "detail",
                          "cree_par",
                          "cree_le"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "type": {
                            "anyOf": [
                              {
                                "const": "ouverture",
                                "type": "string"
                              },
                              {
                                "const": "lot_quarantaine",
                                "type": "string"
                              },
                              {
                                "const": "organisme_informe",
                                "type": "string"
                              },
                              {
                                "const": "cloture",
                                "type": "string"
                              }
                            ]
                          },
                          "detail": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          },
                          "cree_par": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Rappel inconnu (`rappel_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "`rappel_deja_clos` (une simulation ou un rappel clos ne change plus).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/bilan-matiere": {
      "get": {
        "operationId": "lireBilanMatiere",
        "summary": "Bilan matière d'une campagne, par produit, avec chaque perte et chaque rebut expliqué ligne par ligne (RG-053, RG-055)",
        "tags": [
          "Audit"
        ],
        "parameters": [
          {
            "name": "campagne",
            "in": "query",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "produit",
            "in": "query",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Le bilan par produit et les écarts.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "campagne_id",
                    "produits",
                    "ecarts",
                    "equilibre",
                    "explique"
                  ],
                  "properties": {
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "produits": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "produit_id",
                          "entrees_g",
                          "sorties_lots_g",
                          "rebuts_g",
                          "pertes_g",
                          "solde_g",
                          "equilibre",
                          "etapes"
                        ],
                        "properties": {
                          "produit_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "entrees_g": {
                            "minimum": 0,
                            "description": "Grammes.",
                            "type": "integer"
                          },
                          "sorties_lots_g": {
                            "minimum": 0,
                            "description": "Grammes.",
                            "type": "integer"
                          },
                          "rebuts_g": {
                            "minimum": 0,
                            "description": "Grammes.",
                            "type": "integer"
                          },
                          "pertes_g": {
                            "minimum": 0,
                            "description": "Grammes.",
                            "type": "integer"
                          },
                          "solde_g": {
                            "type": "integer"
                          },
                          "equilibre": {
                            "type": "boolean"
                          },
                          "etapes": {
                            "minimum": 0,
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "ecarts": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "etape_id",
                          "produit_id",
                          "ecart_g",
                          "explique_g",
                          "non_explique_g",
                          "lignes"
                        ],
                        "properties": {
                          "etape_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "produit_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "ecart_g": {
                            "minimum": 0,
                            "description": "Grammes.",
                            "type": "integer"
                          },
                          "explique_g": {
                            "minimum": 0,
                            "description": "Grammes.",
                            "type": "integer"
                          },
                          "non_explique_g": {
                            "minimum": 0,
                            "description": "Grammes.",
                            "type": "integer"
                          },
                          "lignes": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "etape_id",
                                "nature",
                                "quantite_g",
                                "libelle"
                              ],
                              "properties": {
                                "etape_id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "nature": {
                                  "anyOf": [
                                    {
                                      "const": "perte",
                                      "type": "string"
                                    },
                                    {
                                      "const": "rebut",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "quantite_g": {
                                  "minimum": 0,
                                  "description": "Grammes.",
                                  "type": "integer"
                                },
                                "libelle": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "equilibre": {
                      "type": "boolean"
                    },
                    "explique": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/campagnes/{id}/dossier-audit": {
      "post": {
        "operationId": "demanderDossierAudit",
        "summary": "Demander le dossier d'audit d'une campagne (`audit.export`, direction) : une tâche de fond le produit (RG-130)",
        "tags": [
          "Audit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "202": {
            "description": "La demande est inscrite ; la tâche produit le dossier.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "statut"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "statut": {
                      "const": "en_attente",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Campagne inconnue (`campagne_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/dossiers-audit/{id}": {
      "get": {
        "operationId": "lireDossierAudit",
        "summary": "Dossier d'audit : statut, empreinte, contenu structuré et édition imprimable (RG-130)",
        "tags": [
          "Audit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Le dossier, en attente, généré ou en échec.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "campagne_id",
                    "statut",
                    "empreinte",
                    "genere_le",
                    "erreur",
                    "contenu",
                    "edition_html"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "en_attente",
                          "type": "string"
                        },
                        {
                          "const": "genere",
                          "type": "string"
                        },
                        {
                          "const": "echec",
                          "type": "string"
                        }
                      ]
                    },
                    "empreinte": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "genere_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "erreur": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "contenu": {
                      "description": "Dossier structuré : bilan, constats, registre, rappels, écarts à présenter. Jamais un verdict.",
                      "anyOf": [
                        {
                          "type": "object",
                          "patternProperties": {
                            "^(.*)$": {}
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "edition_html": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Dossier inconnu (`dossier_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/registre-annulations/edition": {
      "get": {
        "operationId": "lireEditionRegistre",
        "summary": "Édition imprimable du registre des annulations, filtrable par campagne (RG-144)",
        "tags": [
          "Annulations"
        ],
        "parameters": [
          {
            "name": "campagne",
            "in": "query",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "L'édition HTML du registre.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "edition_html"
                  ],
                  "properties": {
                    "edition_html": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/registre-annulations": {
      "get": {
        "operationId": "listerRegistreAnnulations",
        "summary": "Registre des dévalidations et des annulations, du plus récent au plus ancien, filtrable par campagne et par nature (RG-144)",
        "tags": [
          "Annulations"
        ],
        "parameters": [
          {
            "name": "campagne",
            "in": "query",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "nature",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les lignes du registre, avec le numéro conservé des lots annulés.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "annulations"
                  ],
                  "properties": {
                    "annulations": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "objet_type",
                          "objet_id",
                          "nature",
                          "motif",
                          "lot_id",
                          "lot_numero",
                          "campagne_id",
                          "mouvement_id",
                          "constat_id",
                          "cree_par",
                          "cree_le"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "objet_type": {
                            "anyOf": [
                              {
                                "const": "reception",
                                "type": "string"
                              },
                              {
                                "const": "etape_realisee",
                                "type": "string"
                              },
                              {
                                "const": "expedition",
                                "type": "string"
                              },
                              {
                                "const": "vente",
                                "type": "string"
                              },
                              {
                                "const": "lot",
                                "type": "string"
                              }
                            ]
                          },
                          "objet_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "nature": {
                            "anyOf": [
                              {
                                "const": "devalidation",
                                "type": "string"
                              },
                              {
                                "const": "annulation",
                                "type": "string"
                              }
                            ]
                          },
                          "motif": {
                            "type": "string"
                          },
                          "lot_id": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "lot_numero": {
                            "description": "Numéro officiel conservé du lot annulé (RG-143).",
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "campagne_id": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "mouvement_id": {
                            "description": "Mouvement de contre-passation.",
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "constat_id": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "cree_par": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Paramètre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ventes": {
      "get": {
        "operationId": "listerVentes",
        "summary": "Ventes de l'organisation, avec leur quantité expédiée et leur reste, calculés sur les expéditions validées",
        "tags": [
          "Ventes"
        ],
        "parameters": [
          {
            "name": "client",
            "in": "query",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "statut",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les ventes, de la plus récente à la plus ancienne.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "ventes"
                  ],
                  "properties": {
                    "ventes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "client_id",
                          "contrat_id",
                          "spot",
                          "produit_id",
                          "produit_code",
                          "referentiel_code",
                          "quantite_engagee_g",
                          "prix_unite_mineure",
                          "unite_prix",
                          "devise",
                          "date_operation",
                          "statut",
                          "expedie_g",
                          "reste_g",
                          "valide_par",
                          "valide_le"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "client_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "contrat_id": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "spot": {
                            "type": "boolean"
                          },
                          "produit_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "produit_code": {
                            "type": "string"
                          },
                          "referentiel_code": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "quantite_engagee_g": {
                            "type": "integer"
                          },
                          "prix_unite_mineure": {
                            "type": "integer"
                          },
                          "unite_prix": {
                            "type": "string"
                          },
                          "devise": {
                            "type": "string"
                          },
                          "date_operation": {
                            "format": "date",
                            "type": "string"
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "brouillon",
                                "type": "string"
                              },
                              {
                                "const": "validee",
                                "type": "string"
                              },
                              {
                                "const": "soldee",
                                "type": "string"
                              },
                              {
                                "const": "annulee",
                                "type": "string"
                              }
                            ]
                          },
                          "expedie_g": {
                            "type": "integer"
                          },
                          "reste_g": {
                            "type": "integer"
                          },
                          "valide_par": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "valide_le": {
                            "anyOf": [
                              {
                                "format": "date-time",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Filtre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "creerVente",
        "summary": "Enregistrer une vente en brouillon (`sales.manage`) : engagement commercial, avec ou sans contrat (vente « spot »)",
        "tags": [
          "Ventes"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "client_id",
                  "produit_id",
                  "quantite_engagee_g",
                  "prix_unite_mineure",
                  "unite_prix",
                  "devise"
                ],
                "properties": {
                  "client_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "contrat_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "produit_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "referentiel_code": {
                    "minLength": 1,
                    "maxLength": 30,
                    "type": "string"
                  },
                  "quantite_engagee_g": {
                    "minimum": 1,
                    "type": "integer"
                  },
                  "prix_unite_mineure": {
                    "minimum": 0,
                    "type": "integer"
                  },
                  "unite_prix": {
                    "minLength": 1,
                    "maxLength": 20,
                    "type": "string"
                  },
                  "devise": {
                    "pattern": "^[A-Z]{3}$",
                    "type": "string"
                  },
                  "date_operation": {
                    "format": "date",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "La vente en brouillon. Le stock ne bouge pas : il baisse à la validation d'une expédition (RG-080).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "client_id",
                    "contrat_id",
                    "spot",
                    "produit_id",
                    "produit_code",
                    "referentiel_code",
                    "quantite_engagee_g",
                    "prix_unite_mineure",
                    "unite_prix",
                    "devise",
                    "date_operation",
                    "statut",
                    "expedie_g",
                    "reste_g",
                    "valide_par",
                    "valide_le"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "client_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "contrat_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "spot": {
                      "type": "boolean"
                    },
                    "produit_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "produit_code": {
                      "type": "string"
                    },
                    "referentiel_code": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_engagee_g": {
                      "type": "integer"
                    },
                    "prix_unite_mineure": {
                      "type": "integer"
                    },
                    "unite_prix": {
                      "type": "string"
                    },
                    "devise": {
                      "type": "string"
                    },
                    "date_operation": {
                      "format": "date",
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "validee",
                          "type": "string"
                        },
                        {
                          "const": "soldee",
                          "type": "string"
                        },
                        {
                          "const": "annulee",
                          "type": "string"
                        }
                      ]
                    },
                    "expedie_g": {
                      "type": "integer"
                    },
                    "reste_g": {
                      "type": "integer"
                    },
                    "valide_par": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "valide_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Client, produit, contrat ou référentiel inconnu (`client_introuvable`, `produit_introuvable`, `contrat_introuvable`, `referentiel_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Contrat incohérent, inactif ou sans ce produit (`contrat_incoherent`, `contrat_inactif`, `contrat_sans_produit`) ; module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ventes/{id}": {
      "get": {
        "operationId": "lireVente",
        "summary": "Une vente, avec son solde",
        "tags": [
          "Ventes"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "La vente.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "client_id",
                    "contrat_id",
                    "spot",
                    "produit_id",
                    "produit_code",
                    "referentiel_code",
                    "quantite_engagee_g",
                    "prix_unite_mineure",
                    "unite_prix",
                    "devise",
                    "date_operation",
                    "statut",
                    "expedie_g",
                    "reste_g",
                    "valide_par",
                    "valide_le"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "client_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "contrat_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "spot": {
                      "type": "boolean"
                    },
                    "produit_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "produit_code": {
                      "type": "string"
                    },
                    "referentiel_code": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_engagee_g": {
                      "type": "integer"
                    },
                    "prix_unite_mineure": {
                      "type": "integer"
                    },
                    "unite_prix": {
                      "type": "string"
                    },
                    "devise": {
                      "type": "string"
                    },
                    "date_operation": {
                      "format": "date",
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "validee",
                          "type": "string"
                        },
                        {
                          "const": "soldee",
                          "type": "string"
                        },
                        {
                          "const": "annulee",
                          "type": "string"
                        }
                      ]
                    },
                    "expedie_g": {
                      "type": "integer"
                    },
                    "reste_g": {
                      "type": "integer"
                    },
                    "valide_par": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "valide_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Vente inconnue dans l'organisation active (`vente_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ventes/{id}/valider": {
      "post": {
        "operationId": "validerVente",
        "summary": "Valider une vente (`sales.manage`) : elle est figée, les expéditions peuvent commencer",
        "tags": [
          "Ventes"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "La vente validée.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "client_id",
                    "contrat_id",
                    "spot",
                    "produit_id",
                    "produit_code",
                    "referentiel_code",
                    "quantite_engagee_g",
                    "prix_unite_mineure",
                    "unite_prix",
                    "devise",
                    "date_operation",
                    "statut",
                    "expedie_g",
                    "reste_g",
                    "valide_par",
                    "valide_le"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "client_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "contrat_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "spot": {
                      "type": "boolean"
                    },
                    "produit_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "produit_code": {
                      "type": "string"
                    },
                    "referentiel_code": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "quantite_engagee_g": {
                      "type": "integer"
                    },
                    "prix_unite_mineure": {
                      "type": "integer"
                    },
                    "unite_prix": {
                      "type": "string"
                    },
                    "devise": {
                      "type": "string"
                    },
                    "date_operation": {
                      "format": "date",
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "validee",
                          "type": "string"
                        },
                        {
                          "const": "soldee",
                          "type": "string"
                        },
                        {
                          "const": "annulee",
                          "type": "string"
                        }
                      ]
                    },
                    "expedie_g": {
                      "type": "integer"
                    },
                    "reste_g": {
                      "type": "integer"
                    },
                    "valide_par": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "valide_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Vente inconnue (`vente_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "La vente n'est plus en brouillon (`vente_deja_decidee`) ; module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/vehicules": {
      "post": {
        "operationId": "creerVehicule",
        "summary": "Enregistrer un véhicule (`shipping.manage`) : immatriculation unique par organisation",
        "tags": [
          "Expéditions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "immatriculation",
                  "type"
                ],
                "properties": {
                  "immatriculation": {
                    "minLength": 1,
                    "maxLength": 30,
                    "type": "string"
                  },
                  "type": {
                    "minLength": 1,
                    "maxLength": 60,
                    "type": "string"
                  },
                  "transporteur": {
                    "minLength": 1,
                    "maxLength": 120,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Le véhicule.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "immatriculation",
                    "type",
                    "transporteur",
                    "actif"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "immatriculation": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "transporteur": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "actif": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Immatriculation déjà utilisée (`vehicule_existant`) ; module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/vehicules/{id}/pv-nettoyage": {
      "post": {
        "operationId": "enregistrerPvNettoyage",
        "summary": "Enregistrer le PV de nettoyage d'un véhicule avant chargement (`shipping.manage`), signé par l'utilisateur ; en ajout seul",
        "tags": [
          "Expéditions"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "date_nettoyage",
                  "responsable",
                  "points_controle"
                ],
                "properties": {
                  "date_nettoyage": {
                    "format": "date",
                    "description": "Date réelle du nettoyage, au plus tard le jour de l'expédition.",
                    "type": "string"
                  },
                  "responsable": {
                    "minLength": 1,
                    "maxLength": 120,
                    "type": "string"
                  },
                  "points_controle": {
                    "minItems": 1,
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "code",
                        "controle"
                      ],
                      "properties": {
                        "code": {
                          "minLength": 1,
                          "maxLength": 60,
                          "type": "string"
                        },
                        "libelle": {
                          "minLength": 1,
                          "maxLength": 200,
                          "type": "string"
                        },
                        "controle": {
                          "description": "Vrai si le point a été contrôlé. Un PV n'est valable pour une expédition que si tous les points le sont.",
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Le PV de nettoyage. `complet` est vrai quand tous les points sont contrôlés ; un PV incomplet s'enregistre mais ne vaut pas pour une expédition.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "vehicule_id",
                    "date_nettoyage",
                    "responsable",
                    "points_controle",
                    "signataire_id",
                    "complet"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "vehicule_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "date_nettoyage": {
                      "format": "date",
                      "type": "string"
                    },
                    "responsable": {
                      "type": "string"
                    },
                    "points_controle": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "controle"
                        ],
                        "properties": {
                          "code": {
                            "minLength": 1,
                            "maxLength": 60,
                            "type": "string"
                          },
                          "libelle": {
                            "minLength": 1,
                            "maxLength": 200,
                            "type": "string"
                          },
                          "controle": {
                            "description": "Vrai si le point a été contrôlé. Un PV n'est valable pour une expédition que si tous les points le sont.",
                            "type": "boolean"
                          }
                        }
                      }
                    },
                    "signataire_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "complet": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`, `points_controle_invalides`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Véhicule inconnu (`vehicule_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/expeditions": {
      "post": {
        "operationId": "creerExpedition",
        "summary": "Préparer une expédition en brouillon (`shipping.manage`) : véhicule, PV de nettoyage et lignes (un lot, une quantité par ligne)",
        "tags": [
          "Expéditions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "vente_id",
                  "vehicule_id",
                  "pv_nettoyage_id",
                  "destination",
                  "lignes"
                ],
                "properties": {
                  "vente_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "vehicule_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "pv_nettoyage_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "date_operation": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "conteneur": {
                    "minLength": 1,
                    "maxLength": 60,
                    "type": "string"
                  },
                  "scelles": {
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "minLength": 1,
                      "maxLength": 60,
                      "type": "string"
                    }
                  },
                  "destination": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  },
                  "coi_reference": {
                    "minLength": 1,
                    "maxLength": 100,
                    "type": "string"
                  },
                  "nop_import_certificate": {
                    "minLength": 1,
                    "maxLength": 100,
                    "type": "string"
                  },
                  "eudr_reference": {
                    "minLength": 1,
                    "maxLength": 100,
                    "type": "string"
                  },
                  "lignes": {
                    "minItems": 1,
                    "maxItems": 200,
                    "type": "array",
                    "items": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "lot_id",
                        "quantite_g"
                      ],
                      "properties": {
                        "lot_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "quantite_g": {
                          "minimum": 1,
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "L'expédition en brouillon. Le stock ne bouge pas avant sa validation.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "vente_id",
                    "vehicule_id",
                    "pv_nettoyage_id",
                    "date_operation",
                    "conteneur",
                    "scelles",
                    "destination",
                    "coi_reference",
                    "nop_import_certificate",
                    "eudr_reference",
                    "statut",
                    "mouvement_id",
                    "lignes",
                    "quantite_g"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "vente_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "vehicule_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "pv_nettoyage_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "date_operation": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "conteneur": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "scelles": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "destination": {
                      "type": "string"
                    },
                    "coi_reference": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "nop_import_certificate": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "eudr_reference": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "validee",
                          "type": "string"
                        },
                        {
                          "const": "annulee",
                          "type": "string"
                        }
                      ]
                    },
                    "mouvement_id": {
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "lignes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "lot_id",
                          "lot_reference",
                          "lot_numero",
                          "quantite_g"
                        ],
                        "properties": {
                          "lot_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "lot_reference": {
                            "type": "string"
                          },
                          "lot_numero": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "quantite_g": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "quantite_g": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Vente, véhicule, PV de nettoyage ou lot inconnu (`vente_introuvable`, `vehicule_introuvable`, `pv_nettoyage_introuvable`, `lot_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "`vente_non_validee`, `vehicule_inactif`, `pv_nettoyage_invalide`, `lot_non_affectable` (RG-081), `produit_different`, `stock_insuffisant`, `quantite_depasse_engagement`, `referentiel_non_satisfait` (RG-156) ; module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/expeditions/{id}/valider": {
      "post": {
        "operationId": "validerExpedition",
        "summary": "Valider une expédition (`shipping.manage`) : chaîne de certificats (AV1-03), point d'accroche `vente.avant_expedition`, puis mouvement qui débite les lots (I1)",
        "tags": [
          "Expéditions"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "L'expédition validée, la vente (soldée si tout est parti), les constats et la chaîne de certificats relevée.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "expedition",
                    "vente",
                    "constats",
                    "chaine"
                  ],
                  "properties": {
                    "expedition": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "vente_id",
                        "vehicule_id",
                        "pv_nettoyage_id",
                        "date_operation",
                        "conteneur",
                        "scelles",
                        "destination",
                        "coi_reference",
                        "nop_import_certificate",
                        "eudr_reference",
                        "statut",
                        "mouvement_id",
                        "lignes",
                        "quantite_g"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "vente_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "vehicule_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "pv_nettoyage_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "date_operation": {
                          "format": "date-time",
                          "type": "string"
                        },
                        "conteneur": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "scelles": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "destination": {
                          "type": "string"
                        },
                        "coi_reference": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "nop_import_certificate": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "eudr_reference": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "brouillon",
                              "type": "string"
                            },
                            {
                              "const": "validee",
                              "type": "string"
                            },
                            {
                              "const": "annulee",
                              "type": "string"
                            }
                          ]
                        },
                        "mouvement_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "lignes": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "lot_id",
                              "lot_reference",
                              "lot_numero",
                              "quantite_g"
                            ],
                            "properties": {
                              "lot_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "lot_reference": {
                                "type": "string"
                              },
                              "lot_numero": {
                                "anyOf": [
                                  {
                                    "type": "integer"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "quantite_g": {
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "quantite_g": {
                          "type": "integer"
                        }
                      }
                    },
                    "vente": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "client_id",
                        "contrat_id",
                        "spot",
                        "produit_id",
                        "produit_code",
                        "referentiel_code",
                        "quantite_engagee_g",
                        "prix_unite_mineure",
                        "unite_prix",
                        "devise",
                        "date_operation",
                        "statut",
                        "expedie_g",
                        "reste_g",
                        "valide_par",
                        "valide_le"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "client_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "contrat_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "spot": {
                          "type": "boolean"
                        },
                        "produit_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "produit_code": {
                          "type": "string"
                        },
                        "referentiel_code": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "quantite_engagee_g": {
                          "type": "integer"
                        },
                        "prix_unite_mineure": {
                          "type": "integer"
                        },
                        "unite_prix": {
                          "type": "string"
                        },
                        "devise": {
                          "type": "string"
                        },
                        "date_operation": {
                          "format": "date",
                          "type": "string"
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "brouillon",
                              "type": "string"
                            },
                            {
                              "const": "validee",
                              "type": "string"
                            },
                            {
                              "const": "soldee",
                              "type": "string"
                            },
                            {
                              "const": "annulee",
                              "type": "string"
                            }
                          ]
                        },
                        "expedie_g": {
                          "type": "integer"
                        },
                        "reste_g": {
                          "type": "integer"
                        },
                        "valide_par": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "valide_le": {
                          "anyOf": [
                            {
                              "format": "date-time",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    },
                    "constats": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "regle_code",
                          "version",
                          "origine",
                          "resultat",
                          "issue",
                          "motif",
                          "statut",
                          "note",
                          "valeurs"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "regle_code": {
                            "type": "string"
                          },
                          "version": {
                            "type": "string"
                          },
                          "origine": {
                            "anyOf": [
                              {
                                "const": "pack",
                                "type": "string"
                              },
                              {
                                "const": "processus",
                                "type": "string"
                              }
                            ]
                          },
                          "resultat": {
                            "anyOf": [
                              {
                                "const": "ecart",
                                "type": "string"
                              },
                              {
                                "const": "a_verifier",
                                "type": "string"
                              }
                            ]
                          },
                          "issue": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "motif": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "type": "string"
                          },
                          "note": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "valeurs": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          }
                        }
                      }
                    },
                    "chaine": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "referentiel_code",
                        "date",
                        "peut",
                        "raison",
                        "maillons",
                        "ecarts_portee"
                      ],
                      "properties": {
                        "referentiel_code": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "date": {
                          "format": "date",
                          "type": "string"
                        },
                        "peut": {
                          "type": "boolean"
                        },
                        "raison": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "maillons": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "type",
                              "code",
                              "peut",
                              "raison"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "type": {
                                "anyOf": [
                                  {
                                    "const": "producteur",
                                    "type": "string"
                                  },
                                  {
                                    "const": "fournisseur",
                                    "type": "string"
                                  },
                                  {
                                    "const": "operateur",
                                    "type": "string"
                                  },
                                  {
                                    "const": "origine_inconnue",
                                    "type": "string"
                                  }
                                ]
                              },
                              "code": {
                                "type": "string"
                              },
                              "peut": {
                                "type": "boolean"
                              },
                              "raison": {
                                "anyOf": [
                                  {
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              }
                            }
                          }
                        },
                        "ecarts_portee": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "dimension",
                              "element",
                              "raison"
                            ],
                            "properties": {
                              "dimension": {
                                "anyOf": [
                                  {
                                    "const": "produit",
                                    "type": "string"
                                  },
                                  {
                                    "const": "unite",
                                    "type": "string"
                                  }
                                ]
                              },
                              "element": {
                                "type": "string"
                              },
                              "raison": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Expédition inconnue (`expedition_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "`chaine_certificat_refusee` (D6 : un maillon ne peut pas revendiquer le référentiel à la date de l'expédition ; `details` liste les maillons), `expedition_bloquee`, `expedition_deja_decidee`, `lot_non_affectable`, `lot_en_quarantaine`, `stock_epuise`, `referentiel_non_satisfait`, `reglage_invalide` ; module en lecture seule (`module_inactif`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/expeditions/{id}": {
      "get": {
        "operationId": "lireFicheExpedition",
        "summary": "Fiche d'expédition : l'expédition, sa vente, son véhicule, son PV de nettoyage et la chaîne de certificats jusqu'aux origines (RG-082)",
        "tags": [
          "Expéditions"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "La fiche. La chaîne est relevée à la date de l'expédition ; données seulement, aucun document n'est produit (EC-121).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "expedition",
                    "vente",
                    "vehicule",
                    "pv_nettoyage",
                    "chaine"
                  ],
                  "properties": {
                    "expedition": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "vente_id",
                        "vehicule_id",
                        "pv_nettoyage_id",
                        "date_operation",
                        "conteneur",
                        "scelles",
                        "destination",
                        "coi_reference",
                        "nop_import_certificate",
                        "eudr_reference",
                        "statut",
                        "mouvement_id",
                        "lignes",
                        "quantite_g"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "vente_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "vehicule_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "pv_nettoyage_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "date_operation": {
                          "format": "date-time",
                          "type": "string"
                        },
                        "conteneur": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "scelles": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "destination": {
                          "type": "string"
                        },
                        "coi_reference": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "nop_import_certificate": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "eudr_reference": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "brouillon",
                              "type": "string"
                            },
                            {
                              "const": "validee",
                              "type": "string"
                            },
                            {
                              "const": "annulee",
                              "type": "string"
                            }
                          ]
                        },
                        "mouvement_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "lignes": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "lot_id",
                              "lot_reference",
                              "lot_numero",
                              "quantite_g"
                            ],
                            "properties": {
                              "lot_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "lot_reference": {
                                "type": "string"
                              },
                              "lot_numero": {
                                "anyOf": [
                                  {
                                    "type": "integer"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "quantite_g": {
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "quantite_g": {
                          "type": "integer"
                        }
                      }
                    },
                    "vente": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "client_id",
                        "contrat_id",
                        "spot",
                        "produit_id",
                        "produit_code",
                        "referentiel_code",
                        "quantite_engagee_g",
                        "prix_unite_mineure",
                        "unite_prix",
                        "devise",
                        "date_operation",
                        "statut",
                        "expedie_g",
                        "reste_g",
                        "valide_par",
                        "valide_le"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "client_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "contrat_id": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "spot": {
                          "type": "boolean"
                        },
                        "produit_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "produit_code": {
                          "type": "string"
                        },
                        "referentiel_code": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "quantite_engagee_g": {
                          "type": "integer"
                        },
                        "prix_unite_mineure": {
                          "type": "integer"
                        },
                        "unite_prix": {
                          "type": "string"
                        },
                        "devise": {
                          "type": "string"
                        },
                        "date_operation": {
                          "format": "date",
                          "type": "string"
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "brouillon",
                              "type": "string"
                            },
                            {
                              "const": "validee",
                              "type": "string"
                            },
                            {
                              "const": "soldee",
                              "type": "string"
                            },
                            {
                              "const": "annulee",
                              "type": "string"
                            }
                          ]
                        },
                        "expedie_g": {
                          "type": "integer"
                        },
                        "reste_g": {
                          "type": "integer"
                        },
                        "valide_par": {
                          "anyOf": [
                            {
                              "format": "uuid",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "valide_le": {
                          "anyOf": [
                            {
                              "format": "date-time",
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    },
                    "vehicule": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "immatriculation",
                        "type",
                        "transporteur",
                        "actif"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "immatriculation": {
                          "type": "string"
                        },
                        "type": {
                          "type": "string"
                        },
                        "transporteur": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "actif": {
                          "type": "boolean"
                        }
                      }
                    },
                    "pv_nettoyage": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "vehicule_id",
                        "date_nettoyage",
                        "responsable",
                        "points_controle",
                        "signataire_id",
                        "complet"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "vehicule_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "date_nettoyage": {
                          "format": "date",
                          "type": "string"
                        },
                        "responsable": {
                          "type": "string"
                        },
                        "points_controle": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "code",
                              "controle"
                            ],
                            "properties": {
                              "code": {
                                "minLength": 1,
                                "maxLength": 60,
                                "type": "string"
                              },
                              "libelle": {
                                "minLength": 1,
                                "maxLength": 200,
                                "type": "string"
                              },
                              "controle": {
                                "description": "Vrai si le point a été contrôlé. Un PV n'est valable pour une expédition que si tous les points le sont.",
                                "type": "boolean"
                              }
                            }
                          }
                        },
                        "signataire_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "complet": {
                          "type": "boolean"
                        }
                      }
                    },
                    "chaine": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "referentiel_code",
                        "date",
                        "peut",
                        "raison",
                        "maillons",
                        "ecarts_portee"
                      ],
                      "properties": {
                        "referentiel_code": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "date": {
                          "format": "date",
                          "type": "string"
                        },
                        "peut": {
                          "type": "boolean"
                        },
                        "raison": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "maillons": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "type",
                              "code",
                              "peut",
                              "raison"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "type": {
                                "anyOf": [
                                  {
                                    "const": "producteur",
                                    "type": "string"
                                  },
                                  {
                                    "const": "fournisseur",
                                    "type": "string"
                                  },
                                  {
                                    "const": "operateur",
                                    "type": "string"
                                  },
                                  {
                                    "const": "origine_inconnue",
                                    "type": "string"
                                  }
                                ]
                              },
                              "code": {
                                "type": "string"
                              },
                              "peut": {
                                "type": "boolean"
                              },
                              "raison": {
                                "anyOf": [
                                  {
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              }
                            }
                          }
                        },
                        "ecarts_portee": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "dimension",
                              "element",
                              "raison"
                            ],
                            "properties": {
                              "dimension": {
                                "anyOf": [
                                  {
                                    "const": "produit",
                                    "type": "string"
                                  },
                                  {
                                    "const": "unite",
                                    "type": "string"
                                  }
                                ]
                              },
                              "element": {
                                "type": "string"
                              },
                              "raison": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Expédition inconnue (`expedition_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/organisations": {
      "post": {
        "operationId": "creerOrganisation",
        "summary": "Créer une organisation cliente (rôle `editeur_support` ou `editeur_admin`, EC-099)",
        "tags": [
          "Identité"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "code",
                  "nom",
                  "pays",
                  "administrateur"
                ],
                "properties": {
                  "code": {
                    "pattern": "^[A-Z0-9]{2,10}$",
                    "description": "Code immuable, `EXT` réservé (comptes externes).",
                    "type": "string"
                  },
                  "nom": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  },
                  "pays": {
                    "pattern": "^[A-Z]{2}$",
                    "type": "string"
                  },
                  "langue": {
                    "pattern": "^[a-z]{2,3}$",
                    "type": "string"
                  },
                  "fuseau_horaire": {
                    "minLength": 1,
                    "type": "string"
                  },
                  "devise_defaut": {
                    "pattern": "^[A-Z]{3}$",
                    "type": "string"
                  },
                  "administrateur": {
                    "additionalProperties": false,
                    "type": "object",
                    "required": [
                      "identifiant",
                      "nom_affiche"
                    ],
                    "properties": {
                      "identifiant": {
                        "pattern": "^[a-z0-9_-]{3,32}$",
                        "description": "Identifiant local, sans le code de l'organisation.",
                        "type": "string"
                      },
                      "nom_affiche": {
                        "minLength": 1,
                        "maxLength": 200,
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Organisation, ensembles par défaut et premier administrateur créés, en base et dans Keycloak.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "organisation",
                    "administrateur"
                  ],
                  "properties": {
                    "organisation": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "code",
                        "nom"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "code": {
                          "type": "string"
                        },
                        "nom": {
                          "type": "string"
                        }
                      }
                    },
                    "administrateur": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "identifiant_connexion",
                        "mot_de_passe_temporaire"
                      ],
                      "properties": {
                        "identifiant_connexion": {
                          "type": "string"
                        },
                        "mot_de_passe_temporaire": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide, ou code réservé (`EXT`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Code déjà utilisé (`organisation_existante`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak en échec (`identite_indisponible`) : aucune organisation orpheline, ni en base ni dans Keycloak.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/moi": {
      "get": {
        "operationId": "lireMoiEditeur",
        "summary": "Identité de l'appelant du cockpit : rôles de l'éditeur du jeton (ADR 0044)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sujet du jeton et rôles de l'éditeur qu'il porte.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "sub",
                    "roles"
                  ],
                  "properties": {
                    "sub": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "roles": {
                      "description": "Rôles de l'éditeur du jeton, sans doublon.",
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "const": "editeur_admin",
                            "type": "string"
                          },
                          {
                            "const": "editeur_parametrage",
                            "type": "string"
                          },
                          {
                            "const": "editeur_support",
                            "type": "string"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/organisations": {
      "get": {
        "operationId": "listerOrganisationsEditeur",
        "summary": "Toutes les organisations clientes, avec leur état et leur nombre de comptes actifs (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Organisations, par nom.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "organisations"
                  ],
                  "properties": {
                    "organisations": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "code",
                          "nom",
                          "pays",
                          "statut",
                          "cree_le",
                          "utilisateurs_actifs"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "nom": {
                            "type": "string"
                          },
                          "pays": {
                            "pattern": "^[A-Z]{2}$",
                            "type": "string"
                          },
                          "statut": {
                            "description": "`suspendue` : la garde d'authentification refuse l'organisation (`organisation_suspendue`) ; données et comptes conservés.",
                            "anyOf": [
                              {
                                "const": "active",
                                "type": "string"
                              },
                              {
                                "const": "suspendue",
                                "type": "string"
                              }
                            ]
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "utilisateurs_actifs": {
                            "minimum": 0,
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/organisations/{id}": {
      "get": {
        "operationId": "lireOrganisationEditeur",
        "summary": "Fiche d'une organisation cliente (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Identité, état, nombre de comptes et de modules actifs.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "nom",
                    "pays",
                    "langue",
                    "fuseau_horaire",
                    "devise_defaut",
                    "organisme_certificateur",
                    "statut",
                    "suspendue_le",
                    "cree_le",
                    "utilisateurs_actifs",
                    "utilisateurs_total",
                    "modules_actifs"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "nom": {
                      "type": "string"
                    },
                    "pays": {
                      "pattern": "^[A-Z]{2}$",
                      "type": "string"
                    },
                    "langue": {
                      "anyOf": [
                        {
                          "const": "fr",
                          "type": "string"
                        },
                        {
                          "const": "en",
                          "type": "string"
                        }
                      ]
                    },
                    "fuseau_horaire": {
                      "type": "string"
                    },
                    "devise_defaut": {
                      "type": "string"
                    },
                    "organisme_certificateur": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "statut": {
                      "description": "`suspendue` : la garde d'authentification refuse l'organisation (`organisation_suspendue`) ; données et comptes conservés.",
                      "anyOf": [
                        {
                          "const": "active",
                          "type": "string"
                        },
                        {
                          "const": "suspendue",
                          "type": "string"
                        }
                      ]
                    },
                    "suspendue_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "utilisateurs_actifs": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "utilisateurs_total": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "modules_actifs": {
                      "minimum": 0,
                      "description": "Modules à l'état `actif`, noyau compris.",
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation inconnue (`organisation_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "changerStatutOrganisationEditeur",
        "summary": "Suspendre ou réactiver une organisation (rôle `editeur_support` ou `editeur_admin`, EC-126)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "statut",
                  "motif"
                ],
                "properties": {
                  "statut": {
                    "description": "`suspendue` : la garde d'authentification refuse l'organisation (`organisation_suspendue`) ; données et comptes conservés.",
                    "anyOf": [
                      {
                        "const": "active",
                        "type": "string"
                      },
                      {
                        "const": "suspendue",
                        "type": "string"
                      }
                    ]
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "description": "Motif écrit, conservé au journal d'administration de l'organisation.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fiche après changement. Idempotent : demander l'état courant ne change rien et n'écrit rien au journal.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "code",
                    "nom",
                    "pays",
                    "langue",
                    "fuseau_horaire",
                    "devise_defaut",
                    "organisme_certificateur",
                    "statut",
                    "suspendue_le",
                    "cree_le",
                    "utilisateurs_actifs",
                    "utilisateurs_total",
                    "modules_actifs"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "nom": {
                      "type": "string"
                    },
                    "pays": {
                      "pattern": "^[A-Z]{2}$",
                      "type": "string"
                    },
                    "langue": {
                      "anyOf": [
                        {
                          "const": "fr",
                          "type": "string"
                        },
                        {
                          "const": "en",
                          "type": "string"
                        }
                      ]
                    },
                    "fuseau_horaire": {
                      "type": "string"
                    },
                    "devise_defaut": {
                      "type": "string"
                    },
                    "organisme_certificateur": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "statut": {
                      "description": "`suspendue` : la garde d'authentification refuse l'organisation (`organisation_suspendue`) ; données et comptes conservés.",
                      "anyOf": [
                        {
                          "const": "active",
                          "type": "string"
                        },
                        {
                          "const": "suspendue",
                          "type": "string"
                        }
                      ]
                    },
                    "suspendue_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "utilisateurs_actifs": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "utilisateurs_total": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "modules_actifs": {
                      "minimum": 0,
                      "description": "Modules à l'état `actif`, noyau compris.",
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (statut ou motif manquant).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation inconnue (`organisation_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/organisations/{id}/utilisateurs": {
      "get": {
        "operationId": "listerUtilisateursOrganisationEditeur",
        "summary": "Comptes d'une organisation cliente, en lecture (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Utilisateurs de l'organisation.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "utilisateurs"
                  ],
                  "properties": {
                    "utilisateurs": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "identifiant",
                          "nom_affiche",
                          "telephone",
                          "statut",
                          "cree_le"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "identifiant": {
                            "pattern": "^[a-z0-9_-]{3,32}$",
                            "description": "Identifiant local, sans le code de l'organisation.",
                            "type": "string"
                          },
                          "nom_affiche": {
                            "type": "string"
                          },
                          "telephone": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "actif",
                                "type": "string"
                              },
                              {
                                "const": "suspendu",
                                "type": "string"
                              },
                              {
                                "const": "desactive",
                                "type": "string"
                              }
                            ]
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation inconnue (`organisation_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/organisations/{id}/utilisateurs/{utilisateurId}/mot-de-passe": {
      "post": {
        "operationId": "reinitialiserMotDePasseUtilisateurOrganisationEditeur",
        "summary": "Réinitialiser le mot de passe d'un compte d'une organisation cliente (assistance, cockpit)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "utilisateurId",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Mot de passe provisoire, rendu une fois ; sessions révoquées. L'appel est au journal de l'organisation.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "mot_de_passe_temporaire"
                  ],
                  "properties": {
                    "mot_de_passe_temporaire": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle `editeur_support` ou `editeur_admin` requis (`role_editeur_requis`), ou compte hors de l'organisation (`compte_hors_organisation`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation ou compte inconnu (`organisation_inconnue`, `utilisateur_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible (`identite_indisponible`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/organisations/{id}/modules": {
      "get": {
        "operationId": "listerModulesOrganisationEditeur",
        "summary": "Modules d'une organisation cliente avec leur état, en lecture (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Tous les modules, noyau compris, dans l'ordre du catalogue.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "modules"
                  ],
                  "properties": {
                    "modules": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle_fr",
                          "libelle_en",
                          "toujours_actif",
                          "etat",
                          "requis",
                          "propose_par",
                          "propose",
                          "dernier_changement"
                        ],
                        "properties": {
                          "code": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "toujours_actif": {
                            "type": "boolean"
                          },
                          "etat": {
                            "anyOf": [
                              {
                                "const": "actif",
                                "type": "string"
                              },
                              {
                                "const": "inactif",
                                "type": "string"
                              }
                            ]
                          },
                          "requis": {
                            "type": "array",
                            "items": {
                              "pattern": "^[a-z][a-z0-9_]*$",
                              "type": "string"
                            }
                          },
                          "propose_par": {
                            "type": "array",
                            "items": {
                              "pattern": "^[a-z][a-z0-9_]*$",
                              "type": "string"
                            }
                          },
                          "propose": {
                            "type": "boolean"
                          },
                          "dernier_changement": {
                            "anyOf": [
                              {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "motif",
                                  "auteur",
                                  "cree_le"
                                ],
                                "properties": {
                                  "motif": {
                                    "type": "string"
                                  },
                                  "auteur": {
                                    "additionalProperties": false,
                                    "type": "object",
                                    "required": [
                                      "id",
                                      "nom_affiche"
                                    ],
                                    "properties": {
                                      "id": {
                                        "format": "uuid",
                                        "type": "string"
                                      },
                                      "nom_affiche": {
                                        "type": "string"
                                      }
                                    }
                                  },
                                  "cree_le": {
                                    "format": "date-time",
                                    "type": "string"
                                  }
                                }
                              },
                              {
                                "type": "null"
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation inconnue (`organisation_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/organisations/{id}/journal": {
      "get": {
        "operationId": "lireJournalOrganisationEditeur",
        "summary": "Journal d'administration d'une organisation cliente, en lecture (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les 200 appels d'administration les plus récents.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "appels"
                  ],
                  "properties": {
                    "appels": {
                      "description": "Les 200 appels d'administration les plus récents, du plus récent au plus ancien.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "action",
                          "resultat",
                          "auteur_sub",
                          "cree_le",
                          "details"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "action": {
                            "description": "Ex. `organisation.creer`, `organisation.suspendre`, `utilisateur.desactiver`.",
                            "type": "string"
                          },
                          "resultat": {
                            "anyOf": [
                              {
                                "const": "reussi",
                                "type": "string"
                              },
                              {
                                "const": "refuse",
                                "type": "string"
                              },
                              {
                                "const": "echec",
                                "type": "string"
                              }
                            ]
                          },
                          "auteur_sub": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "details": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation inconnue (`organisation_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/catalogue": {
      "get": {
        "operationId": "lireCatalogueEditeur",
        "summary": "Catalogue fonctionnel : modules et activités, avec ce que chaque module apporte (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Modules, dans l'ordre du catalogue, et activités des trois niveaux.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "modules",
                    "activites"
                  ],
                  "properties": {
                    "modules": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle_fr",
                          "libelle_en",
                          "toujours_actif",
                          "ordre",
                          "requis",
                          "propose_par",
                          "permissions",
                          "commandes",
                          "routes",
                          "ecrans",
                          "accroches",
                          "variables",
                          "types_mouvement",
                          "modeles_documents"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "toujours_actif": {
                            "description": "Vrai pour le noyau : il ne s'active ni ne se désactive.",
                            "type": "boolean"
                          },
                          "ordre": {
                            "type": "integer"
                          },
                          "requis": {
                            "description": "Modules requis pour l'activer.",
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "propose_par": {
                            "description": "Activités de premier niveau qui proposent le module.",
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "permissions": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "commandes": {
                            "description": "Types de commande hors ligne.",
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "routes": {
                            "description": "Identifiants des routes d'API du module.",
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "ecrans": {
                            "description": "Chemins des écrans du back-office.",
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "accroches": {
                            "description": "Points d'accroche du moteur de règles.",
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "variables": {
                            "description": "Variables que le module ajoute au dictionnaire des règles.",
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "types_mouvement": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "modeles_documents": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "activites": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "niveau",
                          "parent_code",
                          "regroupement",
                          "libelle_fr",
                          "libelle_en",
                          "provisoire",
                          "ordre"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "niveau": {
                            "minimum": 1,
                            "maximum": 3,
                            "type": "integer"
                          },
                          "parent_code": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "regroupement": {
                            "type": "string"
                          },
                          "libelle_fr": {
                            "type": "string"
                          },
                          "libelle_en": {
                            "type": "string"
                          },
                          "provisoire": {
                            "type": "boolean"
                          },
                          "ordre": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/packs": {
      "get": {
        "operationId": "listerPacksEditeur",
        "summary": "Packs de filière et de référentiel avec leurs versions (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Packs par code, versions de la plus récente à la plus ancienne.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "packs"
                  ],
                  "properties": {
                    "packs": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "libelle",
                          "type",
                          "versions"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "libelle": {
                            "type": "string"
                          },
                          "type": {
                            "anyOf": [
                              {
                                "const": "filiere",
                                "type": "string"
                              },
                              {
                                "const": "referentiel",
                                "type": "string"
                              }
                            ]
                          },
                          "versions": {
                            "description": "De la plus récente à la plus ancienne.",
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "version",
                                "statut",
                                "calibre",
                                "publie_le",
                                "noeuds",
                                "produits"
                              ],
                              "properties": {
                                "version": {
                                  "type": "string"
                                },
                                "statut": {
                                  "anyOf": [
                                    {
                                      "const": "brouillon",
                                      "type": "string"
                                    },
                                    {
                                      "const": "publie",
                                      "type": "string"
                                    },
                                    {
                                      "const": "retire",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "calibre": {
                                  "description": "Paramètres calibrés (EC-007) : faux tant qu'une valeur reste à fournir.",
                                  "type": "boolean"
                                },
                                "publie_le": {
                                  "anyOf": [
                                    {
                                      "format": "date-time",
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "noeuds": {
                                  "minimum": 0,
                                  "description": "Nœuds de l'arbre d'activités de la version.",
                                  "type": "integer"
                                },
                                "produits": {
                                  "minimum": 0,
                                  "type": "integer"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "publierPackEditeur",
        "summary": "Publier un pack : la version est figée (rôle `editeur_parametrage` ou `editeur_admin`, ADR 0045)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": true,
                "description": "Contenu JSON d'un pack, tel qu'il est versionné dans `packs/` : filière (`ContenuPack`) ou référentiel (`type: \"referentiel\"`).",
                "type": "object",
                "properties": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Version déjà publiée avec la même empreinte : rien n'est écrit (idempotent).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "pack_version_id",
                    "sha256",
                    "deja_publiee"
                  ],
                  "properties": {
                    "pack_version_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "sha256": {
                      "type": "string"
                    },
                    "deja_publiee": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Version publiée, auteur conservé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "pack_version_id",
                    "sha256",
                    "deja_publiee"
                  ],
                  "properties": {
                    "pack_version_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "sha256": {
                      "type": "string"
                    },
                    "deja_publiee": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Version déjà publiée avec un autre contenu (`version_existante`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "422": {
            "description": "Pack refusé (`pack_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "503": {
            "description": "Aucune connexion de publication configurée (`publication_indisponible`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/packs/{code}/versions/{version}": {
      "get": {
        "operationId": "lirePackVersionEditeur",
        "summary": "Une version de pack : produits et arbre d'activités avec le contrat de chaque nœud (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^[a-z0-9_]+$",
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Version de pack, en lecture.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "code",
                    "libelle",
                    "type",
                    "version",
                    "statut",
                    "calibre",
                    "publie_le",
                    "publie_par",
                    "sha256",
                    "produits",
                    "arbre"
                  ],
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "libelle": {
                      "type": "string"
                    },
                    "type": {
                      "anyOf": [
                        {
                          "const": "filiere",
                          "type": "string"
                        },
                        {
                          "const": "referentiel",
                          "type": "string"
                        }
                      ]
                    },
                    "version": {
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "publie",
                          "type": "string"
                        },
                        {
                          "const": "retire",
                          "type": "string"
                        }
                      ]
                    },
                    "calibre": {
                      "type": "boolean"
                    },
                    "publie_le": {
                      "anyOf": [
                        {
                          "format": "date-time",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "publie_par": {
                      "description": "Sujet Keycloak de l'auteur de la publication depuis le cockpit ; nul avant CP-5.",
                      "anyOf": [
                        {
                          "format": "uuid",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "sha256": {
                      "type": "string"
                    },
                    "produits": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code",
                          "nom",
                          "unite",
                          "est_matiere_premiere"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "nom": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "fr",
                              "en"
                            ],
                            "properties": {
                              "fr": {
                                "type": "string"
                              },
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "unite": {
                            "type": "string"
                          },
                          "est_matiere_premiere": {
                            "type": "boolean"
                          }
                        }
                      }
                    },
                    "arbre": {
                      "description": "Vide pour un référentiel et pour les versions publiées avant l'arbre d'activités (1.0.0).",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "description": "Boîte d'activité d'un pack : ses entrées, ses sorties typées, ses mesures et ses paramètres (EC-118).",
                        "type": "object",
                        "required": [
                          "chemin",
                          "type",
                          "libelle",
                          "obligatoire",
                          "critique",
                          "sous_traitable",
                          "ordre",
                          "entrees",
                          "sorties",
                          "mesures",
                          "parametres"
                        ],
                        "properties": {
                          "chemin": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string"
                          },
                          "libelle": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "fr",
                              "en"
                            ],
                            "properties": {
                              "fr": {
                                "type": "string"
                              },
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "obligatoire": {
                            "type": "boolean"
                          },
                          "critique": {
                            "type": "boolean"
                          },
                          "sous_traitable": {
                            "type": "boolean"
                          },
                          "ordre": {
                            "type": "integer"
                          },
                          "entrees": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "sorties": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "produit",
                                "nature"
                              ],
                              "properties": {
                                "produit": {
                                  "type": "string"
                                },
                                "nature": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "mesures": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "code",
                                "libelle",
                                "unite",
                                "type"
                              ],
                              "properties": {
                                "code": {
                                  "type": "string"
                                },
                                "libelle": {
                                  "additionalProperties": false,
                                  "type": "object",
                                  "required": [
                                    "fr",
                                    "en"
                                  ],
                                  "properties": {
                                    "fr": {
                                      "type": "string"
                                    },
                                    "en": {
                                      "type": "string"
                                    }
                                  }
                                },
                                "unite": {
                                  "type": "string"
                                },
                                "type": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "parametres": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Pack ou version inconnus (`pack_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/packs/controle": {
      "post": {
        "operationId": "controlerPackEditeur",
        "summary": "Contrôler un pack sans le publier : mêmes vérifications que la publication (cockpit, ADR 0045)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": true,
                "description": "Contenu JSON d'un pack, tel qu'il est versionné dans `packs/` : filière (`ContenuPack`) ou référentiel (`type: \"referentiel\"`).",
                "type": "object",
                "properties": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pack valide : ce qu'il publierait, avec l'empreinte de la version.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "type",
                    "code",
                    "version",
                    "sha256",
                    "deja_publiee",
                    "noeuds",
                    "produits",
                    "regles",
                    "points_controle"
                  ],
                  "properties": {
                    "type": {
                      "anyOf": [
                        {
                          "const": "filiere",
                          "type": "string"
                        },
                        {
                          "const": "referentiel",
                          "type": "string"
                        }
                      ]
                    },
                    "code": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "sha256": {
                      "description": "Empreinte du contenu canonique : celle qu'aura la version publiée.",
                      "type": "string"
                    },
                    "deja_publiee": {
                      "description": "Vrai si cette version existe déjà avec la même empreinte : publier ne changerait rien.",
                      "type": "boolean"
                    },
                    "noeuds": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "produits": {
                      "minimum": 0,
                      "type": "integer"
                    },
                    "regles": {
                      "minimum": 0,
                      "description": "Lignes de décision (référentiel).",
                      "type": "integer"
                    },
                    "points_controle": {
                      "minimum": 0,
                      "description": "Points de la grille de conformité (référentiel).",
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Version déjà publiée avec un autre contenu (`version_existante`) : une version publiée est figée.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "422": {
            "description": "Pack refusé (`pack_invalide`, `details.raison` et le détail du contrôle).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/vision": {
      "get": {
        "operationId": "lireVisionEditeur",
        "summary": "Vision 360 : organisations, licences, versions de packs, rejets de synchronisation (cockpit, EC-131)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Synthèse au jour de l'appel, lue dans la base : rien n'est stocké.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "aujourdhui",
                    "organisations",
                    "licences",
                    "packs",
                    "rejets"
                  ],
                  "properties": {
                    "aujourdhui": {
                      "format": "date",
                      "description": "Jour civil AAAA-MM-JJ.",
                      "type": "string"
                    },
                    "organisations": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "total",
                        "actives",
                        "suspendues"
                      ],
                      "properties": {
                        "total": {
                          "minimum": 0,
                          "type": "integer"
                        },
                        "actives": {
                          "minimum": 0,
                          "type": "integer"
                        },
                        "suspendues": {
                          "minimum": 0,
                          "type": "integer"
                        }
                      }
                    },
                    "licences": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "en_cours",
                        "a_venir",
                        "echues",
                        "aucune",
                        "horizon_jours",
                        "a_echeance",
                        "factures_en_retard"
                      ],
                      "properties": {
                        "en_cours": {
                          "minimum": 0,
                          "type": "integer"
                        },
                        "a_venir": {
                          "minimum": 0,
                          "type": "integer"
                        },
                        "echues": {
                          "minimum": 0,
                          "type": "integer"
                        },
                        "aucune": {
                          "minimum": 0,
                          "type": "integer"
                        },
                        "horizon_jours": {
                          "description": "Filtre d'affichage des échéances proches, pas un seuil métier (EC-131).",
                          "type": "integer"
                        },
                        "a_echeance": {
                          "description": "Licences en cours dont le dernier jour tombe dans l'horizon, les plus proches d'abord.",
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "organisation",
                              "fin",
                              "jours_restants"
                            ],
                            "properties": {
                              "organisation": {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "id",
                                  "code",
                                  "nom"
                                ],
                                "properties": {
                                  "id": {
                                    "format": "uuid",
                                    "type": "string"
                                  },
                                  "code": {
                                    "type": "string"
                                  },
                                  "nom": {
                                    "type": "string"
                                  }
                                }
                              },
                              "fin": {
                                "format": "date",
                                "description": "Jour civil AAAA-MM-JJ.",
                                "type": "string"
                              },
                              "jours_restants": {
                                "minimum": 0,
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "factures_en_retard": {
                          "minimum": 0,
                          "description": "Factures émises, non payées, échues, toutes organisations.",
                          "type": "integer"
                        }
                      }
                    },
                    "packs": {
                      "description": "Par pack, la version la plus récente d'abord.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "pack",
                          "libelle",
                          "version",
                          "statut",
                          "publie_le",
                          "organisations",
                          "campagnes"
                        ],
                        "properties": {
                          "pack": {
                            "type": "string"
                          },
                          "libelle": {
                            "type": "string"
                          },
                          "version": {
                            "type": "string"
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "publie",
                                "type": "string"
                              },
                              {
                                "const": "retire",
                                "type": "string"
                              }
                            ]
                          },
                          "publie_le": {
                            "anyOf": [
                              {
                                "format": "date-time",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "organisations": {
                            "minimum": 0,
                            "description": "Organisations qui ont au moins une campagne sur cette version.",
                            "type": "integer"
                          },
                          "campagnes": {
                            "minimum": 0,
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "rejets": {
                      "additionalProperties": false,
                      "description": "Rejets de sécurité de la synchronisation des 7 derniers jours : le seul indicateur d'erreur de synchronisation (EC-131).",
                      "type": "object",
                      "required": [
                        "depuis",
                        "total",
                        "lignes"
                      ],
                      "properties": {
                        "depuis": {
                          "format": "date-time",
                          "type": "string"
                        },
                        "total": {
                          "minimum": 0,
                          "type": "integer"
                        },
                        "lignes": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "organisation",
                              "rejet",
                              "total",
                              "dernier"
                            ],
                            "properties": {
                              "organisation": {
                                "additionalProperties": false,
                                "type": "object",
                                "required": [
                                  "id",
                                  "code",
                                  "nom"
                                ],
                                "properties": {
                                  "id": {
                                    "format": "uuid",
                                    "type": "string"
                                  },
                                  "code": {
                                    "type": "string"
                                  },
                                  "nom": {
                                    "type": "string"
                                  }
                                }
                              },
                              "rejet": {
                                "description": "`identite_incoherente`, `identifiant_reutilise` ou `sequence_reutilisee` (EC-043).",
                                "type": "string"
                              },
                              "total": {
                                "minimum": 1,
                                "type": "integer"
                              },
                              "dernier": {
                                "format": "date-time",
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/journal": {
      "get": {
        "operationId": "lireJournalEditeur",
        "summary": "Journal des actions de l'équipe de l'éditeur, chez les clients et sur l'équipe (cockpit, EC-131)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les 200 actions les plus récentes.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "actions"
                  ],
                  "properties": {
                    "actions": {
                      "description": "Les 200 plus récentes d'abord.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "cree_le",
                          "auteur_sub",
                          "action",
                          "organisation_code",
                          "sujet",
                          "resultat"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "auteur_sub": {
                            "type": "string"
                          },
                          "action": {
                            "description": "Ex. `organisation.creer`, `licence.creer`, `equipe.creer`.",
                            "type": "string"
                          },
                          "organisation_code": {
                            "description": "Code de l'organisation concernée ; nul pour une action sur l'équipe.",
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "sujet": {
                            "description": "Compte de l'équipe concerné ; nul pour une action sur une organisation.",
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "resultat": {
                            "anyOf": [
                              {
                                "const": "reussi",
                                "type": "string"
                              },
                              {
                                "const": "refuse",
                                "type": "string"
                              },
                              {
                                "const": "echec",
                                "type": "string"
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/equipe": {
      "get": {
        "operationId": "listerEquipeEditeur",
        "summary": "Comptes de l'équipe BioTrace : identifiant, rôle, état (cockpit, EC-130)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les comptes Keycloak portant un rôle `editeur_*`.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "membres"
                  ],
                  "properties": {
                    "membres": {
                      "description": "Triés par identifiant de connexion.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "sub",
                          "identifiant_connexion",
                          "nom_affiche",
                          "role",
                          "actif"
                        ],
                        "properties": {
                          "sub": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "identifiant_connexion": {
                            "description": "`equipe.{identifiant}` pour les comptes créés par le cockpit.",
                            "type": "string"
                          },
                          "nom_affiche": {
                            "type": "string"
                          },
                          "role": {
                            "anyOf": [
                              {
                                "const": "editeur_admin",
                                "type": "string"
                              },
                              {
                                "const": "editeur_parametrage",
                                "type": "string"
                              },
                              {
                                "const": "editeur_support",
                                "type": "string"
                              }
                            ]
                          },
                          "actif": {
                            "description": "Un compte désactivé ne peut plus se connecter ; ses sessions sont révoquées.",
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible (`identite_indisponible`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "creerMembreEquipeEditeur",
        "summary": "Créer le compte d'un membre de l'équipe BioTrace avec un mot de passe temporaire (`editeur_admin`, EC-130)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "identifiant",
                  "nom_affiche",
                  "role"
                ],
                "properties": {
                  "identifiant": {
                    "pattern": "^[a-z0-9][a-z0-9_.-]{2,31}$",
                    "description": "Identifiant local ; l'identifiant de connexion est `equipe.{identifiant}`.",
                    "type": "string"
                  },
                  "nom_affiche": {
                    "minLength": 1,
                    "maxLength": 200,
                    "type": "string"
                  },
                  "role": {
                    "anyOf": [
                      {
                        "const": "editeur_admin",
                        "type": "string"
                      },
                      {
                        "const": "editeur_parametrage",
                        "type": "string"
                      },
                      {
                        "const": "editeur_support",
                        "type": "string"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Compte créé, second facteur imposé. Le mot de passe temporaire n'est rendu qu'une fois.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "membre",
                    "mot_de_passe_temporaire"
                  ],
                  "properties": {
                    "membre": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "sub",
                        "identifiant_connexion",
                        "nom_affiche",
                        "role",
                        "actif"
                      ],
                      "properties": {
                        "sub": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "identifiant_connexion": {
                          "description": "`equipe.{identifiant}` pour les comptes créés par le cockpit.",
                          "type": "string"
                        },
                        "nom_affiche": {
                          "type": "string"
                        },
                        "role": {
                          "anyOf": [
                            {
                              "const": "editeur_admin",
                              "type": "string"
                            },
                            {
                              "const": "editeur_parametrage",
                              "type": "string"
                            },
                            {
                              "const": "editeur_support",
                              "type": "string"
                            }
                          ]
                        },
                        "actif": {
                          "description": "Un compte désactivé ne peut plus se connecter ; ses sessions sont révoquées.",
                          "type": "boolean"
                        }
                      }
                    },
                    "mot_de_passe_temporaire": {
                      "description": "Rendu une seule fois ; à changer à la première connexion.",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle `editeur_admin` requis (`role_editeur_requis`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Identifiant déjà utilisé (`identifiant_deja_utilise`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible (`identite_indisponible`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/equipe/{id}": {
      "patch": {
        "operationId": "changerMembreEquipeEditeur",
        "summary": "Changer le rôle ou l'état d'un membre de l'équipe (`editeur_admin`, EC-130)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "minProperties": 1,
                "description": "Changer le rôle, l'état, ou les deux.",
                "type": "object",
                "properties": {
                  "role": {
                    "anyOf": [
                      {
                        "const": "editeur_admin",
                        "type": "string"
                      },
                      {
                        "const": "editeur_parametrage",
                        "type": "string"
                      },
                      {
                        "const": "editeur_support",
                        "type": "string"
                      }
                    ]
                  },
                  "actif": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Membre après changement. Idempotent : redemander l'état courant n'écrit rien.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "sub",
                    "identifiant_connexion",
                    "nom_affiche",
                    "role",
                    "actif"
                  ],
                  "properties": {
                    "sub": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "identifiant_connexion": {
                      "description": "`equipe.{identifiant}` pour les comptes créés par le cockpit.",
                      "type": "string"
                    },
                    "nom_affiche": {
                      "type": "string"
                    },
                    "role": {
                      "anyOf": [
                        {
                          "const": "editeur_admin",
                          "type": "string"
                        },
                        {
                          "const": "editeur_parametrage",
                          "type": "string"
                        },
                        {
                          "const": "editeur_support",
                          "type": "string"
                        }
                      ]
                    },
                    "actif": {
                      "description": "Un compte désactivé ne peut plus se connecter ; ses sessions sont révoquées.",
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle `editeur_admin` requis (`role_editeur_requis`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Compte inconnu ou qui n'est pas de l'équipe (`equipe_membre_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Auto-désactivation ou auto-rétrogradation (`auto_desactivation_refusee`), dernier super administrateur actif (`dernier_administrateur`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible (`identite_indisponible`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/equipe/{id}/mot-de-passe": {
      "post": {
        "operationId": "reinitialiserMotDePasseMembreEquipeEditeur",
        "summary": "Réinitialiser le mot de passe d'un membre de l'équipe (`editeur_admin`, EC-130)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Mot de passe provisoire, rendu une fois ; sessions révoquées.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "mot_de_passe_temporaire"
                  ],
                  "properties": {
                    "mot_de_passe_temporaire": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle `editeur_admin` requis (`role_editeur_requis`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Compte inconnu ou qui n'est pas de l'équipe (`equipe_membre_inconnu`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "502": {
            "description": "Keycloak indisponible (`identite_indisponible`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/equipe/journal": {
      "get": {
        "operationId": "lireJournalEquipeEditeur",
        "summary": "Journal des actions sur les comptes de l'équipe (cockpit, EC-130)",
        "tags": [
          "Cockpit"
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les 200 actions les plus récentes.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "actions"
                  ],
                  "properties": {
                    "actions": {
                      "description": "Les 200 plus récentes d'abord.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "cree_le",
                          "auteur_sub",
                          "action",
                          "sujet_sub",
                          "sujet_identifiant",
                          "details"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "auteur_sub": {
                            "type": "string"
                          },
                          "action": {
                            "anyOf": [
                              {
                                "const": "equipe.creer",
                                "type": "string"
                              },
                              {
                                "const": "equipe.changer_role",
                                "type": "string"
                              },
                              {
                                "const": "equipe.desactiver",
                                "type": "string"
                              },
                              {
                                "const": "equipe.reactiver",
                                "type": "string"
                              },
                              {
                                "const": "equipe.reinitialiser",
                                "type": "string"
                              }
                            ]
                          },
                          "sujet_sub": {
                            "type": "string"
                          },
                          "sujet_identifiant": {
                            "type": "string"
                          },
                          "details": {
                            "description": "Rôle attribué, ancien rôle. Jamais de mot de passe.",
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/licences": {
      "get": {
        "operationId": "listerLicencesEditeur",
        "summary": "Licences de toutes les organisations : état, échéance, factures en retard (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Une ligne par organisation, échéance la plus proche d'abord.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "aujourdhui",
                    "lignes"
                  ],
                  "properties": {
                    "aujourdhui": {
                      "format": "date",
                      "description": "Jour civil AAAA-MM-JJ.",
                      "type": "string"
                    },
                    "lignes": {
                      "description": "Échéance la plus proche d'abord ; les licences échues en tête, les organisations sans licence en dernier.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "organisation",
                          "debut",
                          "fin",
                          "modules",
                          "etat",
                          "jours_restants",
                          "factures_en_retard"
                        ],
                        "properties": {
                          "organisation": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "code",
                              "nom",
                              "statut"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "code": {
                                "type": "string"
                              },
                              "nom": {
                                "type": "string"
                              },
                              "statut": {
                                "description": "`suspendue` : la garde d'authentification refuse l'organisation (`organisation_suspendue`) ; données et comptes conservés.",
                                "anyOf": [
                                  {
                                    "const": "active",
                                    "type": "string"
                                  },
                                  {
                                    "const": "suspendue",
                                    "type": "string"
                                  }
                                ]
                              }
                            }
                          },
                          "debut": {
                            "anyOf": [
                              {
                                "format": "date",
                                "description": "Jour civil AAAA-MM-JJ.",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "fin": {
                            "anyOf": [
                              {
                                "format": "date",
                                "description": "Jour civil AAAA-MM-JJ.",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "modules": {
                            "minimum": 0,
                            "type": "integer"
                          },
                          "etat": {
                            "description": "Calculé à partir des dates et du jour : jamais stocké.",
                            "anyOf": [
                              {
                                "const": "aucune",
                                "type": "string"
                              },
                              {
                                "const": "a_venir",
                                "type": "string"
                              },
                              {
                                "const": "en_cours",
                                "type": "string"
                              },
                              {
                                "const": "echue",
                                "type": "string"
                              }
                            ]
                          },
                          "jours_restants": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "factures_en_retard": {
                            "minimum": 0,
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/organisations/{id}/licence": {
      "get": {
        "operationId": "lireLicenceOrganisationEditeur",
        "summary": "Licence d'une organisation : courante, historique, écart avec les modules actifs (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Licence la plus récente, son état au jour de l'appel, l'historique et l'écart avec les modules activés.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "aujourdhui",
                    "courante",
                    "etat",
                    "jours_restants",
                    "historique",
                    "ecart_modules"
                  ],
                  "properties": {
                    "aujourdhui": {
                      "format": "date",
                      "description": "Jour civil AAAA-MM-JJ.",
                      "type": "string"
                    },
                    "courante": {
                      "description": "La plus récemment saisie.",
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "id",
                            "debut",
                            "fin",
                            "modules",
                            "motif",
                            "cree_par",
                            "cree_le"
                          ],
                          "properties": {
                            "id": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "debut": {
                              "format": "date",
                              "description": "Jour civil AAAA-MM-JJ.",
                              "type": "string"
                            },
                            "fin": {
                              "format": "date",
                              "description": "Jour civil AAAA-MM-JJ.",
                              "type": "string"
                            },
                            "modules": {
                              "type": "array",
                              "items": {
                                "pattern": "^[a-z][a-z0-9_]*$",
                                "type": "string"
                              }
                            },
                            "motif": {
                              "type": "string"
                            },
                            "cree_par": {
                              "format": "uuid",
                              "type": "string"
                            },
                            "cree_le": {
                              "format": "date-time",
                              "type": "string"
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "etat": {
                      "description": "Calculé à partir des dates et du jour : jamais stocké.",
                      "anyOf": [
                        {
                          "const": "aucune",
                          "type": "string"
                        },
                        {
                          "const": "a_venir",
                          "type": "string"
                        },
                        {
                          "const": "en_cours",
                          "type": "string"
                        },
                        {
                          "const": "echue",
                          "type": "string"
                        }
                      ]
                    },
                    "jours_restants": {
                      "description": "Jusqu'au dernier jour inclus : 0 ce jour-là, négatif une fois échue.",
                      "anyOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "historique": {
                      "description": "Toutes les licences saisies, de la plus récente à la plus ancienne.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "debut",
                          "fin",
                          "modules",
                          "motif",
                          "cree_par",
                          "cree_le"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "debut": {
                            "format": "date",
                            "description": "Jour civil AAAA-MM-JJ.",
                            "type": "string"
                          },
                          "fin": {
                            "format": "date",
                            "description": "Jour civil AAAA-MM-JJ.",
                            "type": "string"
                          },
                          "modules": {
                            "type": "array",
                            "items": {
                              "pattern": "^[a-z][a-z0-9_]*$",
                              "type": "string"
                            }
                          },
                          "motif": {
                            "type": "string"
                          },
                          "cree_par": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    },
                    "ecart_modules": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "licencies_inactifs",
                        "actifs_non_licencies"
                      ],
                      "properties": {
                        "licencies_inactifs": {
                          "description": "Licenciés mais pas activés par l'organisation.",
                          "type": "array",
                          "items": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          }
                        },
                        "actifs_non_licencies": {
                          "description": "Activés par l'organisation mais pas licenciés. Informatif : rien n'est bloqué.",
                          "type": "array",
                          "items": {
                            "pattern": "^[a-z][a-z0-9_]*$",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation inconnue (`organisation_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/organisations/{id}/licences": {
      "post": {
        "operationId": "creerLicenceEditeur",
        "summary": "Saisir une licence : modules ouverts pour une période (`editeur_admin`, EC-129)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "debut",
                  "fin",
                  "modules",
                  "motif"
                ],
                "properties": {
                  "debut": {
                    "format": "date",
                    "description": "Jour civil AAAA-MM-JJ.",
                    "type": "string"
                  },
                  "fin": {
                    "format": "date",
                    "description": "Jour civil AAAA-MM-JJ.",
                    "type": "string"
                  },
                  "modules": {
                    "description": "Modules ouverts, hors noyau, sans doublon.",
                    "type": "array",
                    "items": {
                      "pattern": "^[a-z][a-z0-9_]*$",
                      "type": "string"
                    }
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Licence saisie ; elle devient la licence courante. L'ancienne reste dans l'historique.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "debut",
                    "fin",
                    "modules",
                    "motif",
                    "cree_par",
                    "cree_le"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "debut": {
                      "format": "date",
                      "description": "Jour civil AAAA-MM-JJ.",
                      "type": "string"
                    },
                    "fin": {
                      "format": "date",
                      "description": "Jour civil AAAA-MM-JJ.",
                      "type": "string"
                    },
                    "modules": {
                      "type": "array",
                      "items": {
                        "pattern": "^[a-z][a-z0-9_]*$",
                        "type": "string"
                      }
                    },
                    "motif": {
                      "type": "string"
                    },
                    "cree_par": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Période invalide (`corps_invalide`), module inconnu ou noyau (`module_inconnu`), doublon (`module_en_double`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle `editeur_admin` requis (`role_editeur_requis`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation inconnue (`organisation_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Un module licencié requiert un module non licencié (`licence_dependance_manquante`, `details.manquantes`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/organisations/{id}/factures": {
      "get": {
        "operationId": "listerFacturesOrganisationEditeur",
        "summary": "Références de facturation d'une organisation (cockpit)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Factures, avec leur retard calculé au jour de l'appel.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "factures"
                  ],
                  "properties": {
                    "factures": {
                      "description": "De la plus récemment émise à la plus ancienne.",
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "numero",
                          "montant",
                          "devise",
                          "emise_le",
                          "echeance_le",
                          "statut",
                          "payee_le",
                          "en_retard",
                          "cree_le"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "numero": {
                            "type": "string"
                          },
                          "montant": {
                            "type": "integer"
                          },
                          "devise": {
                            "type": "string"
                          },
                          "emise_le": {
                            "format": "date",
                            "description": "Jour civil AAAA-MM-JJ.",
                            "type": "string"
                          },
                          "echeance_le": {
                            "format": "date",
                            "description": "Jour civil AAAA-MM-JJ.",
                            "type": "string"
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "emise",
                                "type": "string"
                              },
                              {
                                "const": "payee",
                                "type": "string"
                              },
                              {
                                "const": "annulee",
                                "type": "string"
                              }
                            ]
                          },
                          "payee_le": {
                            "anyOf": [
                              {
                                "format": "date",
                                "description": "Jour civil AAAA-MM-JJ.",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "en_retard": {
                            "description": "Émise, non payée, échéance dépassée : calculé au jour de la lecture.",
                            "type": "boolean"
                          },
                          "cree_le": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle de l'éditeur requis (`role_editeur_requis`, `details.roles`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation inconnue (`organisation_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "creerFactureEditeur",
        "summary": "Saisir la référence d'une facture émise par l'outil externe (`editeur_admin`, EC-129)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "numero",
                  "montant",
                  "devise",
                  "emise_le",
                  "echeance_le"
                ],
                "properties": {
                  "numero": {
                    "minLength": 1,
                    "maxLength": 80,
                    "description": "Numéro dans l'outil de facturation externe.",
                    "type": "string"
                  },
                  "montant": {
                    "minimum": 1,
                    "description": "Unités mineures de la devise.",
                    "type": "integer"
                  },
                  "devise": {
                    "pattern": "^[A-Z]{3}$",
                    "type": "string"
                  },
                  "emise_le": {
                    "format": "date",
                    "description": "Jour civil AAAA-MM-JJ.",
                    "type": "string"
                  },
                  "echeance_le": {
                    "format": "date",
                    "description": "Jour civil AAAA-MM-JJ.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Référence saisie, à l'état `emise`.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "numero",
                    "montant",
                    "devise",
                    "emise_le",
                    "echeance_le",
                    "statut",
                    "payee_le",
                    "en_retard",
                    "cree_le"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "numero": {
                      "type": "string"
                    },
                    "montant": {
                      "type": "integer"
                    },
                    "devise": {
                      "type": "string"
                    },
                    "emise_le": {
                      "format": "date",
                      "description": "Jour civil AAAA-MM-JJ.",
                      "type": "string"
                    },
                    "echeance_le": {
                      "format": "date",
                      "description": "Jour civil AAAA-MM-JJ.",
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "emise",
                          "type": "string"
                        },
                        {
                          "const": "payee",
                          "type": "string"
                        },
                        {
                          "const": "annulee",
                          "type": "string"
                        }
                      ]
                    },
                    "payee_le": {
                      "anyOf": [
                        {
                          "format": "date",
                          "description": "Jour civil AAAA-MM-JJ.",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "en_retard": {
                      "description": "Émise, non payée, échéance dépassée : calculé au jour de la lecture.",
                      "type": "boolean"
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dates incohérentes (`corps_invalide`) ou devise inconnue (`devise_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle `editeur_admin` requis (`role_editeur_requis`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation inconnue (`organisation_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Numéro déjà saisi pour cette organisation (`facture_existante`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/editeur/organisations/{id}/factures/{factureId}": {
      "patch": {
        "operationId": "changerStatutFactureEditeur",
        "summary": "Marquer une facture payée ou annulée, une seule fois (`editeur_admin`, EC-129)",
        "tags": [
          "Cockpit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "factureId",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "description": "`payee_le` : jour du paiement, par défaut le jour de l'appel ; refusé pour `annulee`.",
                "type": "object",
                "required": [
                  "statut"
                ],
                "properties": {
                  "statut": {
                    "anyOf": [
                      {
                        "const": "payee",
                        "type": "string"
                      },
                      {
                        "const": "annulee",
                        "type": "string"
                      }
                    ]
                  },
                  "payee_le": {
                    "format": "date",
                    "description": "Jour civil AAAA-MM-JJ.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Facture après changement.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "numero",
                    "montant",
                    "devise",
                    "emise_le",
                    "echeance_le",
                    "statut",
                    "payee_le",
                    "en_retard",
                    "cree_le"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "numero": {
                      "type": "string"
                    },
                    "montant": {
                      "type": "integer"
                    },
                    "devise": {
                      "type": "string"
                    },
                    "emise_le": {
                      "format": "date",
                      "description": "Jour civil AAAA-MM-JJ.",
                      "type": "string"
                    },
                    "echeance_le": {
                      "format": "date",
                      "description": "Jour civil AAAA-MM-JJ.",
                      "type": "string"
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "emise",
                          "type": "string"
                        },
                        {
                          "const": "payee",
                          "type": "string"
                        },
                        {
                          "const": "annulee",
                          "type": "string"
                        }
                      ]
                    },
                    "payee_le": {
                      "anyOf": [
                        {
                          "format": "date",
                          "description": "Jour civil AAAA-MM-JJ.",
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "en_retard": {
                      "description": "Émise, non payée, échéance dépassée : calculé au jour de la lecture.",
                      "type": "boolean"
                    },
                    "cree_le": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Date de paiement avant l'émission, ou donnée pour une annulation (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Rôle `editeur_admin` requis (`role_editeur_requis`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Organisation ou facture inconnue (`organisation_inconnue`, `facture_inconnue`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Facture déjà payée ou annulée (`facture_close`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ordres-transformation": {
      "get": {
        "operationId": "listerOrdresTransformation",
        "summary": "Ordres de transformation de l'organisation, du plus récent au plus ancien",
        "tags": [
          "Transformation"
        ],
        "parameters": [
          {
            "name": "campagne",
            "in": "query",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "statut",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Les ordres, avec leur procédé et leur niveau de suivi.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "ordres"
                  ],
                  "properties": {
                    "ordres": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "campagne_id",
                          "site_id",
                          "procede",
                          "niveau_suivi",
                          "statut",
                          "date_operation"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "campagne_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "site_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "procede": {
                            "type": "string"
                          },
                          "niveau_suivi": {
                            "anyOf": [
                              {
                                "const": "global",
                                "type": "string"
                              },
                              {
                                "const": "detaille",
                                "type": "string"
                              }
                            ]
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "brouillon",
                                "type": "string"
                              },
                              {
                                "const": "en_cours",
                                "type": "string"
                              },
                              {
                                "const": "termine",
                                "type": "string"
                              },
                              {
                                "const": "annule",
                                "type": "string"
                              }
                            ]
                          },
                          "date_operation": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Filtre invalide (`parametre_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "creerOrdreTransformation",
        "summary": "Créer un ordre de transformation (`transformation.manage`) sur un procédé actif ; le niveau de suivi vient du réglage de l'organisation",
        "tags": [
          "Transformation"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "campagne_id",
                  "site_id",
                  "procede"
                ],
                "properties": {
                  "campagne_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "site_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "procede": {
                    "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){0,2}$",
                    "description": "Chemin pointé d'un nœud de l'arbre d'activités.",
                    "type": "string"
                  },
                  "date_operation": {
                    "format": "date-time",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "L'ordre créé, en brouillon.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "campagne_id",
                    "site_id",
                    "procede",
                    "niveau_suivi",
                    "statut",
                    "date_operation",
                    "etapes"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "site_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "procede": {
                      "type": "string"
                    },
                    "niveau_suivi": {
                      "anyOf": [
                        {
                          "const": "global",
                          "type": "string"
                        },
                        {
                          "const": "detaille",
                          "type": "string"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "en_cours",
                          "type": "string"
                        },
                        {
                          "const": "termine",
                          "type": "string"
                        },
                        {
                          "const": "annule",
                          "type": "string"
                        }
                      ]
                    },
                    "date_operation": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "etapes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "etape",
                          "statut",
                          "mesures",
                          "bilan",
                          "sorties"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "etape": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "a_faire",
                                "type": "string"
                              },
                              {
                                "const": "en_cours",
                                "type": "string"
                              },
                              {
                                "const": "realisee",
                                "type": "string"
                              },
                              {
                                "const": "validee",
                                "type": "string"
                              }
                            ]
                          },
                          "mesures": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          },
                          "bilan": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "entrees_matiere_g",
                              "intrants_g",
                              "sorties_lots_g",
                              "rebuts_g",
                              "pertes_g",
                              "pertes_declarees_g",
                              "ecart_inexplique_g",
                              "ecart_relatif_cp"
                            ],
                            "properties": {
                              "entrees_matiere_g": {
                                "type": "integer"
                              },
                              "intrants_g": {
                                "type": "integer"
                              },
                              "sorties_lots_g": {
                                "type": "integer"
                              },
                              "rebuts_g": {
                                "type": "integer"
                              },
                              "pertes_g": {
                                "type": "integer"
                              },
                              "pertes_declarees_g": {
                                "type": "integer"
                              },
                              "ecart_inexplique_g": {
                                "type": "integer"
                              },
                              "ecart_relatif_cp": {
                                "type": "integer"
                              }
                            }
                          },
                          "sorties": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "id",
                                "nature",
                                "produit_id",
                                "quantite_g",
                                "lot_id",
                                "destination",
                                "motif",
                                "reintegre_flux_bio"
                              ],
                              "properties": {
                                "id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "nature": {
                                  "anyOf": [
                                    {
                                      "const": "produit_principal",
                                      "type": "string"
                                    },
                                    {
                                      "const": "coproduit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "sous_produit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "rebut",
                                      "type": "string"
                                    },
                                    {
                                      "const": "perte",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "produit_id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "quantite_g": {
                                  "type": "integer"
                                },
                                "lot_id": {
                                  "anyOf": [
                                    {
                                      "format": "uuid",
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "destination": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "motif": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "reintegre_flux_bio": {
                                  "type": "boolean"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Procédé inconnu (`procede_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Refus : `noeud_pas_un_procede`, `procede_inactif`, `reglage_invalide` ; module en lecture seule (`module_lecture_seule`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ordres-transformation/{id}": {
      "get": {
        "operationId": "lireOrdreTransformation",
        "summary": "Un ordre de transformation : ses étapes, leurs sorties typées et leur bilan matière (EC-015)",
        "tags": [
          "Transformation"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "L'ordre et ses étapes, avec le bilan lu dans la partie double.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "campagne_id",
                    "site_id",
                    "procede",
                    "niveau_suivi",
                    "statut",
                    "date_operation",
                    "etapes"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "site_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "procede": {
                      "type": "string"
                    },
                    "niveau_suivi": {
                      "anyOf": [
                        {
                          "const": "global",
                          "type": "string"
                        },
                        {
                          "const": "detaille",
                          "type": "string"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "en_cours",
                          "type": "string"
                        },
                        {
                          "const": "termine",
                          "type": "string"
                        },
                        {
                          "const": "annule",
                          "type": "string"
                        }
                      ]
                    },
                    "date_operation": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "etapes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "etape",
                          "statut",
                          "mesures",
                          "bilan",
                          "sorties"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "etape": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "a_faire",
                                "type": "string"
                              },
                              {
                                "const": "en_cours",
                                "type": "string"
                              },
                              {
                                "const": "realisee",
                                "type": "string"
                              },
                              {
                                "const": "validee",
                                "type": "string"
                              }
                            ]
                          },
                          "mesures": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          },
                          "bilan": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "entrees_matiere_g",
                              "intrants_g",
                              "sorties_lots_g",
                              "rebuts_g",
                              "pertes_g",
                              "pertes_declarees_g",
                              "ecart_inexplique_g",
                              "ecart_relatif_cp"
                            ],
                            "properties": {
                              "entrees_matiere_g": {
                                "type": "integer"
                              },
                              "intrants_g": {
                                "type": "integer"
                              },
                              "sorties_lots_g": {
                                "type": "integer"
                              },
                              "rebuts_g": {
                                "type": "integer"
                              },
                              "pertes_g": {
                                "type": "integer"
                              },
                              "pertes_declarees_g": {
                                "type": "integer"
                              },
                              "ecart_inexplique_g": {
                                "type": "integer"
                              },
                              "ecart_relatif_cp": {
                                "type": "integer"
                              }
                            }
                          },
                          "sorties": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "id",
                                "nature",
                                "produit_id",
                                "quantite_g",
                                "lot_id",
                                "destination",
                                "motif",
                                "reintegre_flux_bio"
                              ],
                              "properties": {
                                "id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "nature": {
                                  "anyOf": [
                                    {
                                      "const": "produit_principal",
                                      "type": "string"
                                    },
                                    {
                                      "const": "coproduit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "sous_produit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "rebut",
                                      "type": "string"
                                    },
                                    {
                                      "const": "perte",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "produit_id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "quantite_g": {
                                  "type": "integer"
                                },
                                "lot_id": {
                                  "anyOf": [
                                    {
                                      "format": "uuid",
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "destination": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "motif": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "reintegre_flux_bio": {
                                  "type": "boolean"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Ordre inconnu dans l'organisation active (`ordre_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ordres-transformation/{id}/fiche": {
      "get": {
        "operationId": "lireFicheTransformation",
        "summary": "Fiche de transformation : rendement par étape et global, destination des rebuts et sous-produits (AM-12)",
        "tags": [
          "Transformation"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "Rendements et destinations ; les quantités qui passent d'une étape à la suivante ne comptent ni en entrée ni en sortie du procédé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "ordre_id",
                    "procede",
                    "par_etape",
                    "entrees_externes_g",
                    "sorties_finales_g",
                    "rendement_global_cp",
                    "destinations"
                  ],
                  "properties": {
                    "ordre_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "procede": {
                      "type": "string"
                    },
                    "par_etape": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "etape",
                          "rendement_cp"
                        ],
                        "properties": {
                          "etape": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "rendement_cp": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "entrees_externes_g": {
                      "type": "integer"
                    },
                    "sorties_finales_g": {
                      "type": "integer"
                    },
                    "rendement_global_cp": {
                      "type": "integer"
                    },
                    "destinations": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "etape",
                          "nature",
                          "destination",
                          "quantite_g"
                        ],
                        "properties": {
                          "etape": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "nature": {
                            "anyOf": [
                              {
                                "const": "produit_principal",
                                "type": "string"
                              },
                              {
                                "const": "coproduit",
                                "type": "string"
                              },
                              {
                                "const": "sous_produit",
                                "type": "string"
                              },
                              {
                                "const": "rebut",
                                "type": "string"
                              },
                              {
                                "const": "perte",
                                "type": "string"
                              }
                            ]
                          },
                          "destination": {
                            "type": "string"
                          },
                          "quantite_g": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Ordre inconnu (`ordre_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Ordre sans matière entrée (`procede_sans_entree`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/reglages/{cle}": {
      "put": {
        "operationId": "ecrireReglage",
        "summary": "Écrire une nouvelle version d'un réglage de l'organisation (`settings.manage`) : niveau de suivi d'un procédé, tolérance de bilan, mode du certificat et seuils de réception ; aucune valeur par défaut n'est fournie (EC-117)",
        "tags": [
          "Réglages"
        ],
        "parameters": [
          {
            "name": "cle",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^[a-z0-9_]+(\\.[a-z0-9_]+)*$",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "valeur",
                  "motif"
                ],
                "properties": {
                  "valeur": {
                    "type": "object",
                    "patternProperties": {
                      "^(.*)$": {}
                    }
                  },
                  "motif": {
                    "minLength": 1,
                    "maxLength": 500,
                    "type": "string"
                  },
                  "applicable_du": {
                    "format": "date-time",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "La nouvelle version du réglage, appliquée à partir de `applicable_du`.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "cle",
                    "version",
                    "valeur",
                    "motif",
                    "applicable_du"
                  ],
                  "properties": {
                    "cle": {
                      "type": "string"
                    },
                    "version": {
                      "minimum": 1,
                      "type": "integer"
                    },
                    "valeur": {
                      "type": "object",
                      "patternProperties": {
                        "^(.*)$": {}
                      }
                    },
                    "motif": {
                      "type": "string"
                    },
                    "applicable_du": {
                      "format": "date-time",
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`) : valeur qui ne respecte pas le schéma de la clé, motif absent.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Clé inconnue de l'organisation (`reglage_inconnu`) : procédé ou produit absent, clé hors catalogue.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Refus : `reglage_date_anterieure` (la date précède celle de la version précédente), `reglage_concurrent` (une autre version vient d'être écrite).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ordres-transformation/{id}/etapes": {
      "post": {
        "operationId": "ajouterEtapeRealisee",
        "summary": "Ajouter une étape à faire à un ordre (`transformation.manage`) : une étape du procédé, ou la saisie qui couvre tout le procédé en suivi global",
        "tags": [
          "Transformation"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "properties": {
                  "etape": {
                    "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){0,2}$",
                    "description": "Chemin pointé d'un nœud de l'arbre d'activités.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "L'ordre avec sa nouvelle étape.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "campagne_id",
                    "site_id",
                    "procede",
                    "niveau_suivi",
                    "statut",
                    "date_operation",
                    "etapes"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "site_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "procede": {
                      "type": "string"
                    },
                    "niveau_suivi": {
                      "anyOf": [
                        {
                          "const": "global",
                          "type": "string"
                        },
                        {
                          "const": "detaille",
                          "type": "string"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "en_cours",
                          "type": "string"
                        },
                        {
                          "const": "termine",
                          "type": "string"
                        },
                        {
                          "const": "annule",
                          "type": "string"
                        }
                      ]
                    },
                    "date_operation": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "etapes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "etape",
                          "statut",
                          "mesures",
                          "bilan",
                          "sorties"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "etape": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "a_faire",
                                "type": "string"
                              },
                              {
                                "const": "en_cours",
                                "type": "string"
                              },
                              {
                                "const": "realisee",
                                "type": "string"
                              },
                              {
                                "const": "validee",
                                "type": "string"
                              }
                            ]
                          },
                          "mesures": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          },
                          "bilan": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "entrees_matiere_g",
                              "intrants_g",
                              "sorties_lots_g",
                              "rebuts_g",
                              "pertes_g",
                              "pertes_declarees_g",
                              "ecart_inexplique_g",
                              "ecart_relatif_cp"
                            ],
                            "properties": {
                              "entrees_matiere_g": {
                                "type": "integer"
                              },
                              "intrants_g": {
                                "type": "integer"
                              },
                              "sorties_lots_g": {
                                "type": "integer"
                              },
                              "rebuts_g": {
                                "type": "integer"
                              },
                              "pertes_g": {
                                "type": "integer"
                              },
                              "pertes_declarees_g": {
                                "type": "integer"
                              },
                              "ecart_inexplique_g": {
                                "type": "integer"
                              },
                              "ecart_relatif_cp": {
                                "type": "integer"
                              }
                            }
                          },
                          "sorties": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "id",
                                "nature",
                                "produit_id",
                                "quantite_g",
                                "lot_id",
                                "destination",
                                "motif",
                                "reintegre_flux_bio"
                              ],
                              "properties": {
                                "id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "nature": {
                                  "anyOf": [
                                    {
                                      "const": "produit_principal",
                                      "type": "string"
                                    },
                                    {
                                      "const": "coproduit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "sous_produit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "rebut",
                                      "type": "string"
                                    },
                                    {
                                      "const": "perte",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "produit_id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "quantite_g": {
                                  "type": "integer"
                                },
                                "lot_id": {
                                  "anyOf": [
                                    {
                                      "format": "uuid",
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "destination": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "motif": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "reintegre_flux_bio": {
                                  "type": "boolean"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Ordre ou étape inconnus (`ordre_introuvable`, `etape_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Refus : `etape_obligatoire`, `etape_hors_procede`, `etape_inactive`, `etape_non_critique_en_suivi_global`, `ordre_clos` ; une étape déjà saisie (`etape_deja_saisie`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/etapes-realisees/{id}/demarrer": {
      "post": {
        "operationId": "demarrerEtapeRealisee",
        "summary": "Démarrer une étape (`transformation.manage`) : elle passe en cours et l'ordre aussi",
        "tags": [
          "Transformation"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "L'ordre avec l'étape en cours.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "campagne_id",
                    "site_id",
                    "procede",
                    "niveau_suivi",
                    "statut",
                    "date_operation",
                    "etapes"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "site_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "procede": {
                      "type": "string"
                    },
                    "niveau_suivi": {
                      "anyOf": [
                        {
                          "const": "global",
                          "type": "string"
                        },
                        {
                          "const": "detaille",
                          "type": "string"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "en_cours",
                          "type": "string"
                        },
                        {
                          "const": "termine",
                          "type": "string"
                        },
                        {
                          "const": "annule",
                          "type": "string"
                        }
                      ]
                    },
                    "date_operation": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "etapes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "etape",
                          "statut",
                          "mesures",
                          "bilan",
                          "sorties"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "etape": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "a_faire",
                                "type": "string"
                              },
                              {
                                "const": "en_cours",
                                "type": "string"
                              },
                              {
                                "const": "realisee",
                                "type": "string"
                              },
                              {
                                "const": "validee",
                                "type": "string"
                              }
                            ]
                          },
                          "mesures": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          },
                          "bilan": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "entrees_matiere_g",
                              "intrants_g",
                              "sorties_lots_g",
                              "rebuts_g",
                              "pertes_g",
                              "pertes_declarees_g",
                              "ecart_inexplique_g",
                              "ecart_relatif_cp"
                            ],
                            "properties": {
                              "entrees_matiere_g": {
                                "type": "integer"
                              },
                              "intrants_g": {
                                "type": "integer"
                              },
                              "sorties_lots_g": {
                                "type": "integer"
                              },
                              "rebuts_g": {
                                "type": "integer"
                              },
                              "pertes_g": {
                                "type": "integer"
                              },
                              "pertes_declarees_g": {
                                "type": "integer"
                              },
                              "ecart_inexplique_g": {
                                "type": "integer"
                              },
                              "ecart_relatif_cp": {
                                "type": "integer"
                              }
                            }
                          },
                          "sorties": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "id",
                                "nature",
                                "produit_id",
                                "quantite_g",
                                "lot_id",
                                "destination",
                                "motif",
                                "reintegre_flux_bio"
                              ],
                              "properties": {
                                "id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "nature": {
                                  "anyOf": [
                                    {
                                      "const": "produit_principal",
                                      "type": "string"
                                    },
                                    {
                                      "const": "coproduit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "sous_produit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "rebut",
                                      "type": "string"
                                    },
                                    {
                                      "const": "perte",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "produit_id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "quantite_g": {
                                  "type": "integer"
                                },
                                "lot_id": {
                                  "anyOf": [
                                    {
                                      "format": "uuid",
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "destination": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "motif": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "reintegre_flux_bio": {
                                  "type": "boolean"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Étape inconnue (`etape_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Transition interdite (`transition_statut_interdite`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/etapes-realisees/{id}/transformer": {
      "post": {
        "operationId": "transformerEtapeRealisee",
        "summary": "Enregistrer la transformation d'une étape en cours (`transformation.manage`) : lots consommés, sorties typées, lots créés (I4) et bilan (EC-015)",
        "tags": [
          "Transformation"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "entrees",
                  "sorties"
                ],
                "properties": {
                  "entrees": {
                    "minItems": 1,
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "lot_id",
                        "quantite_g"
                      ],
                      "properties": {
                        "lot_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "quantite_g": {
                          "minimum": 1,
                          "description": "Grammes prélevés sur le lot.",
                          "type": "integer"
                        }
                      }
                    }
                  },
                  "sorties": {
                    "minItems": 1,
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "nature",
                        "produit_id",
                        "quantite_g"
                      ],
                      "properties": {
                        "nature": {
                          "anyOf": [
                            {
                              "const": "produit_principal",
                              "type": "string"
                            },
                            {
                              "const": "coproduit",
                              "type": "string"
                            },
                            {
                              "const": "sous_produit",
                              "type": "string"
                            },
                            {
                              "const": "rebut",
                              "type": "string"
                            },
                            {
                              "const": "perte",
                              "type": "string"
                            }
                          ]
                        },
                        "produit_id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "quantite_g": {
                          "minimum": 1,
                          "type": "integer"
                        },
                        "nature_lot": {
                          "description": "Nature du numéro : matière première, réception, nettoyage, produit fini. « Vente » n'existe plus (avenant n°1). Codes à confirmer, EC-068.",
                          "anyOf": [
                            {
                              "const": "MP",
                              "type": "string"
                            },
                            {
                              "const": "REC",
                              "type": "string"
                            },
                            {
                              "const": "NET",
                              "type": "string"
                            },
                            {
                              "const": "PF",
                              "type": "string"
                            }
                          ]
                        },
                        "qualite": {
                          "minLength": 1,
                          "maxLength": 100,
                          "type": "string"
                        },
                        "reintegre_flux_bio": {
                          "type": "boolean"
                        },
                        "destination": {
                          "minLength": 1,
                          "maxLength": 200,
                          "type": "string"
                        },
                        "motif": {
                          "minLength": 1,
                          "maxLength": 200,
                          "type": "string"
                        }
                      }
                    }
                  },
                  "mesures": {
                    "type": "object",
                    "patternProperties": {
                      "^(.*)$": {}
                    }
                  },
                  "confirmer_declassement": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "L'étape avec son bilan, les lots créés (en attente) et les alertes du bilan.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "etape",
                    "declassement",
                    "lots",
                    "alertes"
                  ],
                  "properties": {
                    "etape": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "etape",
                        "statut",
                        "mesures",
                        "bilan",
                        "sorties"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "etape": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "a_faire",
                              "type": "string"
                            },
                            {
                              "const": "en_cours",
                              "type": "string"
                            },
                            {
                              "const": "realisee",
                              "type": "string"
                            },
                            {
                              "const": "validee",
                              "type": "string"
                            }
                          ]
                        },
                        "mesures": {
                          "type": "object",
                          "patternProperties": {
                            "^(.*)$": {}
                          }
                        },
                        "bilan": {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "entrees_matiere_g",
                            "intrants_g",
                            "sorties_lots_g",
                            "rebuts_g",
                            "pertes_g",
                            "pertes_declarees_g",
                            "ecart_inexplique_g",
                            "ecart_relatif_cp"
                          ],
                          "properties": {
                            "entrees_matiere_g": {
                              "type": "integer"
                            },
                            "intrants_g": {
                              "type": "integer"
                            },
                            "sorties_lots_g": {
                              "type": "integer"
                            },
                            "rebuts_g": {
                              "type": "integer"
                            },
                            "pertes_g": {
                              "type": "integer"
                            },
                            "pertes_declarees_g": {
                              "type": "integer"
                            },
                            "ecart_inexplique_g": {
                              "type": "integer"
                            },
                            "ecart_relatif_cp": {
                              "type": "integer"
                            }
                          }
                        },
                        "sorties": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "nature",
                              "produit_id",
                              "quantite_g",
                              "lot_id",
                              "destination",
                              "motif",
                              "reintegre_flux_bio"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "nature": {
                                "anyOf": [
                                  {
                                    "const": "produit_principal",
                                    "type": "string"
                                  },
                                  {
                                    "const": "coproduit",
                                    "type": "string"
                                  },
                                  {
                                    "const": "sous_produit",
                                    "type": "string"
                                  },
                                  {
                                    "const": "rebut",
                                    "type": "string"
                                  },
                                  {
                                    "const": "perte",
                                    "type": "string"
                                  }
                                ]
                              },
                              "produit_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "quantite_g": {
                                "type": "integer"
                              },
                              "lot_id": {
                                "anyOf": [
                                  {
                                    "format": "uuid",
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "destination": {
                                "anyOf": [
                                  {
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "motif": {
                                "anyOf": [
                                  {
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "reintegre_flux_bio": {
                                "type": "boolean"
                              }
                            }
                          }
                        }
                      }
                    },
                    "declassement": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "referentiels",
                        "categorie"
                      ],
                      "properties": {
                        "referentiels": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "referentiel",
                              "avant",
                              "apres"
                            ],
                            "properties": {
                              "referentiel": {
                                "type": "string"
                              },
                              "avant": {
                                "type": "string"
                              },
                              "apres": {
                                "anyOf": [
                                  {
                                    "description": "Vide si le résultat ne peut plus se réclamer du référentiel.",
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              }
                            }
                          }
                        },
                        "categorie": {
                          "anyOf": [
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "avant",
                                "apres"
                              ],
                              "properties": {
                                "avant": {
                                  "anyOf": [
                                    {
                                      "const": "bio",
                                      "type": "string"
                                    },
                                    {
                                      "const": "conversion",
                                      "type": "string"
                                    },
                                    {
                                      "const": "conventionnel",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "apres": {
                                  "anyOf": [
                                    {
                                      "const": "bio",
                                      "type": "string"
                                    },
                                    {
                                      "const": "conversion",
                                      "type": "string"
                                    },
                                    {
                                      "const": "conventionnel",
                                      "type": "string"
                                    }
                                  ]
                                }
                              }
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    },
                    "lots": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "reference_provisoire",
                          "numero",
                          "nature",
                          "produit_id",
                          "produit_code",
                          "qualite",
                          "qualites",
                          "statut",
                          "campagne_id",
                          "quantite_totale_g",
                          "quantite_disponible_g",
                          "emplacement_id",
                          "mouvement_creation_id",
                          "date_operation"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "reference_provisoire": {
                            "type": "string"
                          },
                          "numero": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "nature": {
                            "type": "string"
                          },
                          "produit_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "produit_code": {
                            "type": "string"
                          },
                          "qualite": {
                            "type": "string"
                          },
                          "qualites": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {
                                "type": "string"
                              }
                            }
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "brouillon",
                                "type": "string"
                              },
                              {
                                "const": "en_attente",
                                "type": "string"
                              },
                              {
                                "const": "valide",
                                "type": "string"
                              },
                              {
                                "const": "rejete",
                                "type": "string"
                              },
                              {
                                "const": "annule",
                                "type": "string"
                              },
                              {
                                "const": "consomme",
                                "type": "string"
                              },
                              {
                                "const": "quarantaine",
                                "type": "string"
                              },
                              {
                                "const": "archive",
                                "type": "string"
                              }
                            ]
                          },
                          "campagne_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "quantite_totale_g": {
                            "type": "integer"
                          },
                          "quantite_disponible_g": {
                            "type": "integer"
                          },
                          "emplacement_id": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "mouvement_creation_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "date_operation": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    },
                    "alertes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "details": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps invalide (`corps_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Étape ou lot inconnus (`etape_introuvable`, `lot_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Refus : `etape_pas_en_cours`, `transformation_deja_saisie`, `sortie_sans_destination`, `perte_sans_motif`, `reintegration_reservee_au_rebut`, `nature_lot_requise` (EC-120), `declassement_a_confirmer` (RG-153, avec le détail du déclassement), `referentiel_sans_etats`, `lot_non_disponible`, `quantite_superieure_au_stock`, `sortie_superieure_aux_entrees`, `pertes_declarees_superieures_aux_pertes`, `lot_en_quarantaine`, `hors_contrat` (étape critique, EC-118).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/etapes-realisees/{id}/valider": {
      "post": {
        "operationId": "validerEtapeRealisee",
        "summary": "Valider une étape (`transformation.manage`) : bilan vérifié, lots créés validés avec leur numéro officiel (I3), étape figée (I2)",
        "tags": [
          "Transformation"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "L'étape validée, ses lots numérotés et les alertes du bilan.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "etape",
                    "declassement",
                    "lots",
                    "alertes"
                  ],
                  "properties": {
                    "etape": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "id",
                        "etape",
                        "statut",
                        "mesures",
                        "bilan",
                        "sorties"
                      ],
                      "properties": {
                        "id": {
                          "format": "uuid",
                          "type": "string"
                        },
                        "etape": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "statut": {
                          "anyOf": [
                            {
                              "const": "a_faire",
                              "type": "string"
                            },
                            {
                              "const": "en_cours",
                              "type": "string"
                            },
                            {
                              "const": "realisee",
                              "type": "string"
                            },
                            {
                              "const": "validee",
                              "type": "string"
                            }
                          ]
                        },
                        "mesures": {
                          "type": "object",
                          "patternProperties": {
                            "^(.*)$": {}
                          }
                        },
                        "bilan": {
                          "additionalProperties": false,
                          "type": "object",
                          "required": [
                            "entrees_matiere_g",
                            "intrants_g",
                            "sorties_lots_g",
                            "rebuts_g",
                            "pertes_g",
                            "pertes_declarees_g",
                            "ecart_inexplique_g",
                            "ecart_relatif_cp"
                          ],
                          "properties": {
                            "entrees_matiere_g": {
                              "type": "integer"
                            },
                            "intrants_g": {
                              "type": "integer"
                            },
                            "sorties_lots_g": {
                              "type": "integer"
                            },
                            "rebuts_g": {
                              "type": "integer"
                            },
                            "pertes_g": {
                              "type": "integer"
                            },
                            "pertes_declarees_g": {
                              "type": "integer"
                            },
                            "ecart_inexplique_g": {
                              "type": "integer"
                            },
                            "ecart_relatif_cp": {
                              "type": "integer"
                            }
                          }
                        },
                        "sorties": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "id",
                              "nature",
                              "produit_id",
                              "quantite_g",
                              "lot_id",
                              "destination",
                              "motif",
                              "reintegre_flux_bio"
                            ],
                            "properties": {
                              "id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "nature": {
                                "anyOf": [
                                  {
                                    "const": "produit_principal",
                                    "type": "string"
                                  },
                                  {
                                    "const": "coproduit",
                                    "type": "string"
                                  },
                                  {
                                    "const": "sous_produit",
                                    "type": "string"
                                  },
                                  {
                                    "const": "rebut",
                                    "type": "string"
                                  },
                                  {
                                    "const": "perte",
                                    "type": "string"
                                  }
                                ]
                              },
                              "produit_id": {
                                "format": "uuid",
                                "type": "string"
                              },
                              "quantite_g": {
                                "type": "integer"
                              },
                              "lot_id": {
                                "anyOf": [
                                  {
                                    "format": "uuid",
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "destination": {
                                "anyOf": [
                                  {
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "motif": {
                                "anyOf": [
                                  {
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "reintegre_flux_bio": {
                                "type": "boolean"
                              }
                            }
                          }
                        }
                      }
                    },
                    "declassement": {
                      "additionalProperties": false,
                      "type": "object",
                      "required": [
                        "referentiels",
                        "categorie"
                      ],
                      "properties": {
                        "referentiels": {
                          "type": "array",
                          "items": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "referentiel",
                              "avant",
                              "apres"
                            ],
                            "properties": {
                              "referentiel": {
                                "type": "string"
                              },
                              "avant": {
                                "type": "string"
                              },
                              "apres": {
                                "anyOf": [
                                  {
                                    "description": "Vide si le résultat ne peut plus se réclamer du référentiel.",
                                    "type": "string"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              }
                            }
                          }
                        },
                        "categorie": {
                          "anyOf": [
                            {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "avant",
                                "apres"
                              ],
                              "properties": {
                                "avant": {
                                  "anyOf": [
                                    {
                                      "const": "bio",
                                      "type": "string"
                                    },
                                    {
                                      "const": "conversion",
                                      "type": "string"
                                    },
                                    {
                                      "const": "conventionnel",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "apres": {
                                  "anyOf": [
                                    {
                                      "const": "bio",
                                      "type": "string"
                                    },
                                    {
                                      "const": "conversion",
                                      "type": "string"
                                    },
                                    {
                                      "const": "conventionnel",
                                      "type": "string"
                                    }
                                  ]
                                }
                              }
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    },
                    "lots": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "reference_provisoire",
                          "numero",
                          "nature",
                          "produit_id",
                          "produit_code",
                          "qualite",
                          "qualites",
                          "statut",
                          "campagne_id",
                          "quantite_totale_g",
                          "quantite_disponible_g",
                          "emplacement_id",
                          "mouvement_creation_id",
                          "date_operation"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "reference_provisoire": {
                            "type": "string"
                          },
                          "numero": {
                            "anyOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "nature": {
                            "type": "string"
                          },
                          "produit_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "produit_code": {
                            "type": "string"
                          },
                          "qualite": {
                            "type": "string"
                          },
                          "qualites": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {
                                "type": "string"
                              }
                            }
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "brouillon",
                                "type": "string"
                              },
                              {
                                "const": "en_attente",
                                "type": "string"
                              },
                              {
                                "const": "valide",
                                "type": "string"
                              },
                              {
                                "const": "rejete",
                                "type": "string"
                              },
                              {
                                "const": "annule",
                                "type": "string"
                              },
                              {
                                "const": "consomme",
                                "type": "string"
                              },
                              {
                                "const": "quarantaine",
                                "type": "string"
                              },
                              {
                                "const": "archive",
                                "type": "string"
                              }
                            ]
                          },
                          "campagne_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "quantite_totale_g": {
                            "type": "integer"
                          },
                          "quantite_disponible_g": {
                            "type": "integer"
                          },
                          "emplacement_id": {
                            "anyOf": [
                              {
                                "format": "uuid",
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "mouvement_creation_id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "date_operation": {
                            "format": "date-time",
                            "type": "string"
                          }
                        }
                      }
                    },
                    "alertes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "code"
                        ],
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "details": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Étape inconnue (`etape_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Refus : `transition_statut_interdite`, `etape_sans_entree`, `bilan_sorties_lots`, `bilan_rebuts`, `bilan_pertes_declarees`, `etape_bloquee` (une ligne de la norme, point d'accroche `etape.avant_validation`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/ordres-transformation/{id}/terminer": {
      "post": {
        "operationId": "terminerOrdreTransformation",
        "summary": "Terminer un ordre (`transformation.manage`) : toutes les étapes sont validées",
        "tags": [
          "Transformation"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/EnteteOrganisation"
          }
        ],
        "security": [
          {
            "jetonKeycloak": []
          }
        ],
        "responses": {
          "200": {
            "description": "L'ordre terminé.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "id",
                    "campagne_id",
                    "site_id",
                    "procede",
                    "niveau_suivi",
                    "statut",
                    "date_operation",
                    "etapes"
                  ],
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "campagne_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "site_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "procede": {
                      "type": "string"
                    },
                    "niveau_suivi": {
                      "anyOf": [
                        {
                          "const": "global",
                          "type": "string"
                        },
                        {
                          "const": "detaille",
                          "type": "string"
                        }
                      ]
                    },
                    "statut": {
                      "anyOf": [
                        {
                          "const": "brouillon",
                          "type": "string"
                        },
                        {
                          "const": "en_cours",
                          "type": "string"
                        },
                        {
                          "const": "termine",
                          "type": "string"
                        },
                        {
                          "const": "annule",
                          "type": "string"
                        }
                      ]
                    },
                    "date_operation": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "etapes": {
                      "type": "array",
                      "items": {
                        "additionalProperties": false,
                        "type": "object",
                        "required": [
                          "id",
                          "etape",
                          "statut",
                          "mesures",
                          "bilan",
                          "sorties"
                        ],
                        "properties": {
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "etape": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "statut": {
                            "anyOf": [
                              {
                                "const": "a_faire",
                                "type": "string"
                              },
                              {
                                "const": "en_cours",
                                "type": "string"
                              },
                              {
                                "const": "realisee",
                                "type": "string"
                              },
                              {
                                "const": "validee",
                                "type": "string"
                              }
                            ]
                          },
                          "mesures": {
                            "type": "object",
                            "patternProperties": {
                              "^(.*)$": {}
                            }
                          },
                          "bilan": {
                            "additionalProperties": false,
                            "type": "object",
                            "required": [
                              "entrees_matiere_g",
                              "intrants_g",
                              "sorties_lots_g",
                              "rebuts_g",
                              "pertes_g",
                              "pertes_declarees_g",
                              "ecart_inexplique_g",
                              "ecart_relatif_cp"
                            ],
                            "properties": {
                              "entrees_matiere_g": {
                                "type": "integer"
                              },
                              "intrants_g": {
                                "type": "integer"
                              },
                              "sorties_lots_g": {
                                "type": "integer"
                              },
                              "rebuts_g": {
                                "type": "integer"
                              },
                              "pertes_g": {
                                "type": "integer"
                              },
                              "pertes_declarees_g": {
                                "type": "integer"
                              },
                              "ecart_inexplique_g": {
                                "type": "integer"
                              },
                              "ecart_relatif_cp": {
                                "type": "integer"
                              }
                            }
                          },
                          "sorties": {
                            "type": "array",
                            "items": {
                              "additionalProperties": false,
                              "type": "object",
                              "required": [
                                "id",
                                "nature",
                                "produit_id",
                                "quantite_g",
                                "lot_id",
                                "destination",
                                "motif",
                                "reintegre_flux_bio"
                              ],
                              "properties": {
                                "id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "nature": {
                                  "anyOf": [
                                    {
                                      "const": "produit_principal",
                                      "type": "string"
                                    },
                                    {
                                      "const": "coproduit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "sous_produit",
                                      "type": "string"
                                    },
                                    {
                                      "const": "rebut",
                                      "type": "string"
                                    },
                                    {
                                      "const": "perte",
                                      "type": "string"
                                    }
                                  ]
                                },
                                "produit_id": {
                                  "format": "uuid",
                                  "type": "string"
                                },
                                "quantite_g": {
                                  "type": "integer"
                                },
                                "lot_id": {
                                  "anyOf": [
                                    {
                                      "format": "uuid",
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "destination": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "motif": {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "reintegre_flux_bio": {
                                  "type": "boolean"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Jeton absent ou invalide (`jeton_absent`, `jeton_invalide`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "403": {
            "description": "Organisation absente, inconnue, non autorisée ou à préciser, ou droit manquant.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Ordre inconnu (`ordre_introuvable`).",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          },
          "409": {
            "description": "Refus : `etape_manquante` (le détail liste les saisies que le niveau de suivi demande et qui manquent), `etapes_non_validees`, `transition_statut_interdite`.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": false,
                  "type": "object",
                  "required": [
                    "erreur"
                  ],
                  "properties": {
                    "erreur": {
                      "description": "Code d'erreur stable, ex. `jeton_invalide`.",
                      "type": "string"
                    },
                    "details": {}
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "jetonKeycloak": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Jeton d'accès Keycloak, audience `biotrace-api`."
      }
    },
    "parameters": {
      "EnteteOrganisation": {
        "name": "X-Organisation",
        "in": "header",
        "required": false,
        "description": "Code de l'organisation active. Obligatoire pour un compte rattaché à plusieurs organisations ; jamais de choix par défaut.",
        "schema": {
          "type": "string"
        }
      }
    }
  }
}
