{
  "info": {
    "name": "BC & Suivi — Fleet (Full)",
    "description": "**BC & Suivi module — complete API surface for the FE team.**\n\nEvery request is annotated with the FE screen and UI element it powers (see each request's Description tab). Reference prototype: https://dadycarpolicy-gkxqfqje.manus.space/suivi\n\nScreens covered:\n1. **/suivi** — BC list page (KPIs, filters, table, header actions)\n2. **/suivi/{bcId}** — BC detail (header info, delay banner, timeline, documents, EDL cards)\n3. **Timeline de production** modal (Modifier jalon + history)\n4. **Documents véhicule** panel — Livraison + Restitution tabs, per-doc actions\n5. **EDL summary card** + Contre-signature loueur card\n6. **MAD checklist** (Confirmer la livraison precondition)\n7. **/edl/{bc}/{kind}** — 9-step EDL wizard (8 photo zones + Compteurs/Signatures)\n8. **/contestation/{bc}** — Dispute page (Lignes de facturation, Générer la lettre)\n9. **/bc/nouveau** — Nouveau BC manuel form (BC depuis AO and BC sans AO)\n\nBase URL: {{base_url}}. Set {{token}} and the resource IDs ({{bc_id}}, {{milestone_id}}, etc.) per env.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [{ "key": "token", "value": "{{token}}", "type": "string" }]
  },
  "variable": [
    { "key": "base_url",     "value": "https://api.fleet.dadycar.fr" },
    { "key": "token",        "value": "" },
    { "key": "bc_id",        "value": "1" },
    { "key": "milestone_id", "value": "1" },
    { "key": "document_id",  "value": "1" },
    { "key": "edl_id",       "value": "1" },
    { "key": "edl_kind",     "value": "livraison" },
    { "key": "photo_id",     "value": "1" },
    { "key": "damage_id",    "value": "1" },
    { "key": "dispute_id",   "value": "1" },
    { "key": "line_id",      "value": "1" }
  ],
  "item": [
    {
      "name": "Screen 1 — /suivi (BC list page)",
      "description": "BC list landing page. Header KPI cards, filter chips, search, table with rows per BC, and 3 header CTAs (Exporter / Nouveau BC / Nouvelle commande).",
      "item": [
        {
          "name": "List — table rows + pagination",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": {
              "raw": "{{base_url}}/api/v1/fleet/bc/list?per_page=10&sort_by=delivery_planned_at&sort_dir=asc",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "fleet", "bc", "list"],
              "query": [
                { "key": "per_page",      "value": "10" },
                { "key": "sort_by",       "value": "delivery_planned_at" },
                { "key": "sort_dir",      "value": "asc" },
                { "key": "status_filter", "value": "en_production", "disabled": true, "description": "Filter chip: Tous | En production | Prêt à livrer | Livré | En utilisation | Restitution" },
                { "key": "search_query",  "value": "Tesla",         "disabled": true, "description": "Free-text search on reference / vehicle / collaborator" }
              ]
            },
            "description": "**Screen:** /suivi\n**Element:** Main table (columns: Commande, Véhicule, Collaborateur, Loueur, Statut, Progression, Documents, Retard).\nResponse includes the paginated `bons_de_commande[]` collection + the `kpis` object — so this single call powers both the KPI cards and the table."
          }
        },
        {
          "name": "KPIs — 5 header cards",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/kpis",
            "description": "**Screen:** /suivi\n**Element:** 5 KPI cards above the table — En production, Prêt à livrer, EDL en attente, En restitution, **Docs manquants** (NEW).\n\n`docs_manquants` = delivered BCs with ≥1 required livraison doc still missing (and not cancelled)."
          }
        },
        {
          "name": "Export CSV",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/export",
            "description": "**Screen:** /suivi\n**Element:** Header button **Exporter**. Returns `{ url }` for download."
          }
        }
      ]
    },
    {
      "name": "Screen 2 — /suivi/{bcId} (BC detail header)",
      "description": "BC detail page. Header (reference + status badge + 3 CTAs), info cards (Véhicule / Collaborateur / Loueur / BC émis le), delay banner.",
      "item": [
        {
          "name": "Show — full BC payload",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/show/{{bc_id}}",
            "description": "**Screen:** /suivi/{bcId}\n**Element:** Whole page. Returns header info cards, delay banner, nested `milestones[]`, `documents[]` (flat) + `documents_by_kind { livraison, restitution }`, `edl_livraison`, `edl_restitution` (each with countersign block), and the `contract`/`lessor_snapshot` blocks for the prefill modal."
          }
        },
        {
          "name": "History — BC timeline (drawer)",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/history",
            "description": "**Screen:** /suivi/{bcId}\n**Element:** Activity drawer (chronological log of every event: bc_created, status_changed, milestone_updated, document_updated, edl_started/signed, dispute_opened/sent/resolved, request_point_loueur)."
          }
        },
        {
          "name": "Header action — Demander un point au loueur",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"note\": \"Pouvez-vous confirmer la date de mise en production ?\"\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/request-point-loueur",
            "description": "**Screen:** /suivi/{bcId}\n**Element:** Header button **Demander un point au loueur** (toast: 'Messagerie loueur ouverte — pré-remplie pour un point de suivi')."
          }
        },
        {
          "name": "Header action — Exporter dossier (BC PDF)",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/pdf",
            "description": "**Screen:** /suivi/{bcId}\n**Element:** Header button **Exporter dossier**. Returns `{ url }`."
          }
        },
        {
          "name": "Header action — Confirmer la livraison",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/close",
            "description": "**Screen:** /suivi/{bcId}\n**Element:** Header button **Confirmer la livraison** (only enabled when MAD checklist has no blocking items)."
          }
        },
        {
          "name": "Header action — Annuler le BC",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"reason\": \"Annulé à la demande du collaborateur\"\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/cancel",
            "description": "**Screen:** /suivi/{bcId}\n**Element:** Action menu (kebab) → **Annuler**."
          }
        },
        {
          "name": "Delete BC (admin)",
          "request": {
            "method": "DELETE", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/delete/{{bc_id}}",
            "description": "**Screen:** /suivi list row context menu (admin only — requires delete_bc)."
          }
        }
      ]
    },
    {
      "name": "Screen 3 — Timeline de production",
      "description": "6-jalon timeline + Modifier modal (Date prévue / Date réelle / Notes + Historique des modifications).",
      "item": [
        {
          "name": "Update milestone (Modifier modal — Enregistrer)",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"actual_date\": \"2026-06-15\",\n  \"notes\": \"Retard de 5 jours — problème d'approvisionnement batterie.\"\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/milestones/{{milestone_id}}/update",
            "description": "**Screen:** /suivi/{bcId} — Timeline de production\n**Element:** Per-jalon **Modifier** button → modal with Date réelle + Notes + **Enregistrer**.\n\nSide effects: when key=`livre` and actual_date set, BC status flips to `livre` + `delivered_at` stamped. When key=`pret_a_livrer` and BC is `en_production`, status flips to `pret_a_livrer`."
          }
        },
        {
          "name": "Milestone history (Historique des modifications panel)",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/milestones/{{milestone_id}}/history",
            "description": "**Screen:** /suivi/{bcId} — Modifier modal\n**Element:** **Historique des modifications** panel inside the milestone modal (rows like 'Marie Dupont (FM) · 10/06/2026 — Loueur a signalé un retard de 5 jours.')."
          }
        }
      ]
    },
    {
      "name": "Screen 4 — Documents véhicule (Livraison + Restitution tabs)",
      "description": "**MAJOR CHANGE:** Documents are now split by `kind`. The FE renders 2 tabs (Livraison X/10 · Restitution Y/4). Each row has per-doc actions: Reçu/Manquant/Photo + Email (Relance loueur) + X (Annuler) + clock badge (history popover).",
      "item": [
        {
          "name": "Ajouter un document reçu (add free-form document) — NEW",
          "request": {
            "method": "POST",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "body": {
              "mode": "formdata",
              "formdata": [
                { "key": "label",       "value": "Attestation d'assurance complémentaire", "type": "text", "description": "required (max 150)" },
                { "key": "description", "value": "Document complémentaire fourni par le loueur", "type": "text" },
                { "key": "kind",        "value": "livraison", "type": "text", "description": "livraison | restitution (active tab; default livraison)" },
                { "key": "is_required", "value": "false", "type": "text", "description": "the \"Marquer comme document obligatoire\" toggle" },
                { "key": "file",        "type": "file", "src": [], "description": "optional — pdf/png/jpg, max 10 Mo. Uploading implies status=recu." }
              ]
            },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/documents",
            "description": "**Screen:** /suivi/{bcId} — Documents véhicule\n**Element:** **+ Ajouter un document reçu** modal. Creates a free-form document (one not in the seeded checklist) under the chosen tab. A unique `custom_*` doc_key is generated server-side. With a file → status=recu (+ file_uploaded event); without → non_recu. Returns the new BcDocument resource. Permission: edit_bc."
          }
        },
        {
          "name": "Update document — toggle status / upload file",
          "request": {
            "method": "POST",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "body": {
              "mode": "formdata",
              "formdata": [
                { "key": "status", "value": "recu",         "type": "text", "description": "non_recu | recu | conforme | non_conforme | cancelled" },
                { "key": "notes",  "value": "Carte grise reçue ce matin", "type": "text" },
                { "key": "file",   "type": "file", "src": [] }
              ]
            },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/documents/{{document_id}}/update",
            "description": "**Screen:** /suivi/{bcId} — Documents véhicule\n**Element:** Per-row buttons **Reçu / Manquant / Photo** (file upload). Uploading a file auto-stamps status=recu unless overridden. Each call logs a `status_changed` and/or `file_uploaded` event (clock badge counter)."
          }
        },
        {
          "name": "Relancer loueur (per-doc email reminder)  — NEW",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"note\": \"Carte grise toujours en attente — merci de transmettre dès que possible\"\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/documents/{{document_id}}/relance",
            "description": "**Screen:** /suivi/{bcId} — Documents véhicule\n**Element:** Orange **Relancer loueur** button (visible on rows with status=manquant/non_recu). Increments the clock badge counter, logs a `relance_sent` event."
          }
        },
        {
          "name": "Annuler document (mark as not applicable) — NEW",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"reason\": \"Véhicule thermique — câble de recharge non applicable\"\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/documents/{{document_id}}/cancel",
            "description": "**Screen:** /suivi/{bcId} — Documents véhicule\n**Element:** **X Annuler** button (per row). Doc stays in the checklist but no longer counts in `docs_manquants` KPI."
          }
        },
        {
          "name": "Document history (clock badge popover) — NEW",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/documents/{{document_id}}/history",
            "description": "**Screen:** /suivi/{bcId} — Documents véhicule\n**Element:** Clock-icon badge next to each row (shows event count + last event date). Click opens a popover with the full event log (status changes, relances, file uploads, notes)."
          }
        },
        {
          "name": "Télécharger tout (ZIP of all document files) — NEW",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": {
              "raw": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/documents/download-all?kind=livraison",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "fleet", "bc", "{{bc_id}}", "documents", "download-all"],
              "query": [{ "key": "kind", "value": "livraison", "disabled": true, "description": "optional: livraison | restitution. Omit for all received docs." }]
            },
            "description": "**Screen:** /suivi/{bcId} — Documents véhicule\n**Element:** **Télécharger tout** button. Bundles every document that has a stored file into a ZIP (foldered livraison/ + restitution/); docs still 'manquant' (no file) are skipped. Returns `{ url, count }`. 422 if there's nothing to download. Permission: view_bc."
          }
        }
      ]
    },
    {
      "name": "Screen 5 — EDL summary card + Contre-signature loueur",
      "description": "EDL summary card on the BC detail page: KPIs (mileage / fuel / photos / damages) + Voir l'EDL + PDF buttons + the dedicated **Contre-signature loueur** block.",
      "item": [
        {
          "name": "Read EDL by kind (resume wizard state)",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/{{edl_kind}}",
            "description": "**Screen:** /suivi/{bcId} — EDL summary card\n**Element:** Loads the EDL summary card + powers the wizard `/edl/{bc}/{kind}` when user clicks **Voir l'EDL**. Returns `current_step`, all `zones` (8 photos + 9th Compteurs), `photos`, `damages`, `signatures`, and the `countersign` block.\n\nReplace `{{edl_kind}}` with `livraison` or `restitution`."
          }
        },
        {
          "name": "EDL PDF (dossier download) — NEW",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/{{edl_id}}/pdf",
            "description": "**Screen:** /suivi/{bcId} — EDL summary card\n**Element:** **PDF** button next to the EDL row. Returns `{ url }` with the generated EDL dossier (header + damages table + signatures)."
          }
        },
        {
          "name": "Contre-signature loueur — Relancer — NEW",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"note\": \"19 jours sans retour, merci de transmettre la contre-signature\"\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/{{edl_id}}/countersign/relance",
            "description": "**Screen:** /suivi/{bcId} — Contre-signature loueur card\n**Element:** Blue **Relancer {Lessor}** button. Allowed only when `countersign.status = pending` and EDL is signed. Bumps `relances_count` + sets `last_relance_at`."
          }
        },
        {
          "name": "Contre-signature loueur — Marquer reçu — NEW",
          "request": {
            "method": "POST",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "body": {
              "mode": "formdata",
              "formdata": [
                { "key": "file", "type": "file", "src": [], "description": "Optional PDF/PNG/JPG of the lessor's countersigned copy" }
              ]
            },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/{{edl_id}}/countersign/received",
            "description": "**Screen:** /suivi/{bcId} — Contre-signature loueur card\n**Element:** Green **Marquer reçu** button. Flips `countersign.status` to `received`, stamps `received_at`, stores the uploaded PDF if provided."
          }
        }
      ]
    },
    {
      "name": "Screen 6 — MAD checklist (Confirmer la livraison)",
      "description": "One-shot readiness aggregator for the 'Confirmer la livraison' precondition. Used to enable/disable the header CTA and render the checklist tooltip.",
      "item": [
        {
          "name": "Mise À Disposition — checklist",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/mad-checklist",
            "description": "**Screen:** /suivi/{bcId}\n**Element:** **Confirmer la livraison** header CTA — disabled if `items[]` contains any `severity=blocking` row. Also rendered as a checklist tooltip listing what's missing (required docs, EDL livraison signature, production progress)."
          }
        }
      ]
    },
    {
      "name": "Screen 7 — /edl/{bc}/{kind} (EDL wizard)",
      "description": "**REWORKED:** 9-step wizard — 8 photo zones (Face avant, Face arrière, Côté conducteur, Côté passager, Toit, Intérieur conducteur, Intérieur arrière, Coffre) + **9th 'Compteurs & signatures' step** (km / fuel-or-charge / signatures). Previous backend ZONES (cote_gauche, moteur, pneus, kilometrage) were replaced to match the prototype.",
      "item": [
        {
          "name": "Start EDL (Démarrer)",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"kind\": \"livraison\",\n  \"location_lat\":  48.8566,\n  \"location_long\": 2.3522\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/start",
            "description": "**Screen:** /edl/{bc}/{kind}\n**Element:** Initial load when no EDL row exists. Captures GPS at start (the green 'GPS actif' header chip). For `kind=restitution`, also seeds the restitution document checklist (4 docs) and flips BC status → `restitution`."
          }
        },
        {
          "name": "Submit full EDL — one-shot (all steps in one call) — NEW",
          "request": {
            "method": "POST",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "body": {
              "mode": "formdata",
              "formdata": [
                { "key": "kind", "value": "livraison", "type": "text", "description": "livraison | restitution" },
                { "key": "location_lat", "value": "48.8566", "type": "text" },
                { "key": "location_long", "value": "2.3522", "type": "text" },
                { "key": "mileage_km", "value": "12", "type": "text" },
                { "key": "fuel_or_charge_pct", "value": "100", "type": "text" },
                { "key": "energy_kind", "value": "carburant", "type": "text", "description": "carburant | charge" },
                { "key": "overall_notes", "value": "Véhicule propre, RAS", "type": "text" },
                { "key": "photos[0][zone_key]", "value": "face_avant", "type": "text", "description": "one entry per photo; zone_key in the 8 EDL zones" },
                { "key": "photos[0][file]", "type": "file", "src": [] },
                { "key": "photos[1][zone_key]", "value": "face_arriere", "type": "text" },
                { "key": "photos[1][file]", "type": "file", "src": [] },
                { "key": "damages[0][zone_key]", "value": "cote_passager", "type": "text" },
                { "key": "damages[0][description]", "value": "Rayure légère portière passager", "type": "text" },
                { "key": "damages[0][severity]", "value": "mineur", "type": "text", "description": "mineur | modere | majeur" },
                { "key": "damages[0][photo]", "type": "file", "src": [], "description": "optional" },
                { "key": "signatures[0][role]", "value": "collaborateur", "type": "text", "description": "collaborateur | loueur | fleet_manager" },
                { "key": "signatures[0][name]", "value": "Marie Dupont", "type": "text" },
                { "key": "signatures[0][signature]", "type": "file", "src": [] }
              ]
            },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/submit",
            "description": "**Screen:** /edl/{bc}/{kind}\n**Element:** Replaces the whole step-by-step wizard with ONE call. Creates/resumes the EDL for `kind`, saves the compteurs snapshot, stores every photo + damage, and **signs** it when `signatures[]` are present (else saves a draft, status stays in_progress). Signing a livraison EDL flips its docs to `recu` + moves the BC to `en_utilisation`, exactly like the per-step /sign. The per-step routes below stay available for incremental capture. Permission: edit_bc."
          }
        },
        {
          "name": "Save step (auto-save on next/prev)",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"current_step\": 5,\n  \"mileage_km\": 12,\n  \"fuel_or_charge_pct\": 100,\n  \"energy_kind\": \"carburant\",\n  \"overall_notes\": \"Véhicule propre, RAS\"\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/{{edl_id}}/save-step",
            "description": "**Screen:** /edl/{bc}/{kind}\n**Element:** Auto-save when the user clicks **Étape suivante**, **Étape précédente**, or **Passer aux compteurs**. `current_step` accepts 1..9 (8 photo zones + 1 compteurs)."
          }
        },
        {
          "name": "Upload photo (Prendre une photo)",
          "request": {
            "method": "POST", "header": [{ "key": "Accept", "value": "application/json" }],
            "body": {
              "mode": "formdata",
              "formdata": [
                { "key": "zone_key", "value": "face_avant", "type": "text", "description": "One of: face_avant, face_arriere, cote_conducteur, cote_passager, toit, interieur_conducteur, interieur_arriere, coffre" },
                { "key": "file",     "type": "file",        "src": [] }
              ]
            },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/{{edl_id}}/photos",
            "description": "**Screen:** /edl/{bc}/{kind} — any photo zone step\n**Element:** **Prendre une photo** button. ≥1 photo required per zone before 'Passer aux compteurs' becomes enabled."
          }
        },
        {
          "name": "Delete photo",
          "request": {
            "method": "DELETE", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/{{edl_id}}/photos/{{photo_id}}",
            "description": "**Screen:** /edl/{bc}/{kind}\n**Element:** × on a photo thumbnail."
          }
        },
        {
          "name": "Add damage (Signaler un dommage)",
          "request": {
            "method": "POST", "header": [{ "key": "Accept", "value": "application/json" }],
            "body": {
              "mode": "formdata",
              "formdata": [
                { "key": "zone_key",    "value": "cote_conducteur", "type": "text" },
                { "key": "description", "value": "Rayure légère portière conducteur", "type": "text" },
                { "key": "severity",    "value": "mineur", "type": "text", "description": "mineur | modere | majeur" },
                { "key": "photo",       "type": "file",   "src": [] }
              ]
            },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/{{edl_id}}/damages",
            "description": "**Screen:** /edl/{bc}/{kind} — Dommages signalés section per zone\n**Element:** **+ Signaler un dommage** → inline form (Description + Mineur/Modéré/Majeur chip selector + optional photo) + **Enregistrer**.\n\nLivraison damages are flagged `is_new=false` (pre-existing); restitution damages are `is_new=true` (the lessor will bill these)."
          }
        },
        {
          "name": "Delete damage",
          "request": {
            "method": "DELETE", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/{{edl_id}}/damages/{{damage_id}}",
            "description": "**Screen:** /edl/{bc}/{kind}\n**Element:** × on a damage row."
          }
        },
        {
          "name": "Sign EDL (Finaliser & signer)",
          "request": {
            "method": "POST", "header": [{ "key": "Accept", "value": "application/json" }],
            "body": {
              "mode": "formdata",
              "formdata": [
                { "key": "signatures[0][role]",      "value": "collaborateur", "type": "text" },
                { "key": "signatures[0][name]",      "value": "Marie Dupont",  "type": "text" },
                { "key": "signatures[0][signature]", "type": "file",            "src": [] },
                { "key": "signatures[1][role]",      "value": "loueur",        "type": "text", "description": "Optional — if present, countersign auto-flips to received" },
                { "key": "signatures[1][name]",      "value": "Jean Loueur",    "type": "text" },
                { "key": "signatures[1][signature]", "type": "file",            "src": [] },
                { "key": "mileage_km",         "value": "12",  "type": "text" },
                { "key": "fuel_or_charge_pct", "value": "100", "type": "text" },
                { "key": "overall_notes",      "value": "RAS — véhicule conforme", "type": "text" }
              ]
            },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/edl/{{edl_id}}/sign",
            "description": "**Screen:** /edl/{bc}/{kind} — step 9 (Compteurs & signatures)\n**Element:** **Finaliser & signer** button. Captures 1..N signatures (each with role + name + PNG/JPG/SVG canvas image).\n\n**Side effects** for `kind=livraison`: flips all non_recu livraison docs to `recu`, marks BC status `en_utilisation`, and flips countersign to `pending` (or `received` if a loueur signer was in the captured signatures)."
          }
        }
      ]
    },
    {
      "name": "Screen 8 — /contestation/{bc} (Dispute page)",
      "description": "Restitution invoice dispute page. Header cards (Véhicule / Loueur / Fin de contrat), summary banner ('X lignes extraites · Total facturé : Y €'), Lignes de facturation list, Contestation status card, Générer la lettre CTA.",
      "item": [
        {
          "name": "Read dispute (whole page)",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/dispute",
            "description": "**Screen:** /contestation/{bc}\n**Element:** Whole page. Returns `lines[]` + `totals { invoiced, contested, savings, potential_savings }` + `status` + `letter_url` once sent.\n\n`potential_savings` is the **'Économies potentielles : jusqu'à X €'** card value — equals `contested` while draft/envoyee, then `savings` once resolved."
          }
        },
        {
          "name": "Init dispute (lignes de facturation)",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"lines\": [\n    { \"label\": \"Rayure porte avant gauche\", \"amount\": 450, \"category\": \"dommage\" },\n    { \"label\": \"Sur-kilométrage (79 450 km / 80 000 km contrat)\", \"amount\": 0, \"category\": \"sur_kilometrage\" },\n    { \"label\": \"Remise à niveau carburant (45%)\", \"amount\": 38, \"category\": \"remise_a_niveau\" }\n  ]\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/dispute/init",
            "description": "**Screen:** /contestation/{bc} (initial load)\n**Element:** Triggered when the operator first opens the dispute page on a BC that doesn't have a dispute yet. Lines come pre-extracted from the lessor's invoice (manual entry today; future invoice OCR will post the same shape)."
          }
        },
        {
          "name": "Contest a line (check + reason)",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"reason\": \"Niveau documenté dans l'EDL restitution à 45% — conforme au contrat\",\n  \"proof_damage_ids\": [{{damage_id}}]\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/dispute/lines/{{line_id}}/contest",
            "description": "**Screen:** /contestation/{bc}\n**Element:** Operator checks a line + types reason + picks EDL damages as proof (shown as '1 preuve(s) EDL ajoutée(s)' chip). Recomputes `total_contested`."
          }
        },
        {
          "name": "Uncontest a line",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/dispute/lines/{{line_id}}/uncontest",
            "description": "**Screen:** /contestation/{bc}\n**Element:** Uncheck a previously contested line."
          }
        },
        {
          "name": "Send dispute (Générer la lettre de contestation)",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/dispute/{{dispute_id}}/send",
            "description": "**Screen:** /contestation/{bc}\n**Element:** Big blue **Générer la lettre de contestation** button at the bottom. Requires ≥1 contested line. Generates the letter PDF (SnappyPdf) and flips status → `envoyee`."
          }
        },
        {
          "name": "Letter download",
          "request": {
            "method": "GET", "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/dispute/{{dispute_id}}/letter",
            "description": "**Screen:** /contestation/{bc}\n**Element:** Download / view of the generated letter PDF (after Send)."
          }
        },
        {
          "name": "Resolve dispute (record lessor response)",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"status\": \"partiellement_acceptee\",\n  \"lessor_response\": \"Accord pour annuler la ligne carburant. Rayure portière maintenue.\"\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/{{bc_id}}/dispute/{{dispute_id}}/resolve",
            "description": "**Screen:** /contestation/{bc} (post-envoyee modal)\n**Element:** Modal to record the lessor's reply. Status must be one of: acceptee | partiellement_acceptee | rejetee. Updates `savings_amount` (collapses `potential_savings`)."
          }
        }
      ]
    },
    {
      "name": "Screen 9 — /bc/nouveau (Manual BC creation)",
      "description": "**Nouveau BC manuel** form. 4 sections: Loueur / Véhicule & Contrat / Livraison / Notes internes. Header badge flips: 'BC depuis AO' (when source IDs supplied) vs 'BC sans AO'.",
      "item": [
        {
          "name": "Create BC (Vérifier et émettre le BC)",
          "request": {
            "method": "POST", "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"appel_offre_id\":       null,\n  \"selected_cotation_id\": null,\n  \"commande_id\":          null,\n  \"vendor_id\":            null,\n\n  \"lessor_name\":          \"Arval\",\n  \"lessor_email\":         \"cotations@arval.fr\",\n  \"lessor_bc_reference\":  \"LLD-2026-00123\",\n\n  \"vehicle_label\":        \"Tesla Model 3 Long Range\",\n  \"collaborator_id\":      null,\n  \"beneficiary_name\":     \"Thomas Bernard\",\n  \"loyer_mensuel_ht\":     748,\n  \"duree_contrat_mois\":   48,\n  \"kilometrage_annuel\":   25000,\n  \"delai_livraison_jours\": 45,\n\n  \"delivery_site_id\":     null,\n  \"delivery_site_label\":  \"Siège Paris 8e\",\n  \"contract_start_date\":  null,\n\n  \"notes_internal\":       \"Configuration TM3 LR — peinture Noir Étoilé\"\n}" },
            "url": "{{base_url}}/api/v1/fleet/bc/store",
            "description": "**Screen:** /bc/nouveau\n**Element:** Footer **Vérifier et émettre le BC** button.\n\nHandles **both modes** in one endpoint:\n- 'BC depuis AO': caller supplies `appel_offre_id` + `selected_cotation_id` + `commande_id` from the AO comparator — financial fields prefill from cotation but operator can override.\n- 'BC sans AO': no source links; operator fills everything by hand."
          }
        }
      ]
    },
    {
      "name": "Options / vocabulary endpoints",
      "description": "Static enums + decorated labels/colors/icons. Most are read once and cached on the FE.",
      "item": [
        { "name": "statuses (filter chips)", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/statuses",
            "description": "**Screen:** /suivi — filter chip row." } },
        { "name": "sorts (list sort dropdown)", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/sorts",
            "description": "**Screen:** /suivi — sort selector (implicit, drives the API param)." } },
        { "name": "milestone-keys (timeline icons)", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/milestone-keys",
            "description": "**Screen:** /suivi/{bcId} — Timeline de production icon/label/color per jalon." } },
        { "name": "document-kinds (Livraison/Restitution tabs) — NEW", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/document-kinds",
            "description": "**Screen:** /suivi/{bcId} — Documents véhicule tab labels." } },
        { "name": "document-keys (?kind=livraison|restitution)", "request": { "method": "GET", "header": [],
            "url": { "raw": "{{base_url}}/api/v1/fleet/bc/options/document-keys?kind=livraison", "host": ["{{base_url}}"], "path": ["api","v1","fleet","bc","options","document-keys"], "query": [{ "key": "kind", "value": "livraison", "description": "livraison (10 docs) | restitution (4 docs)" }] },
            "description": "**Screen:** /suivi/{bcId} — Documents véhicule labels per tab. Default kind=livraison." } },
        { "name": "document-event-types (clock badge events) — NEW", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/document-event-types",
            "description": "**Screen:** /suivi/{bcId} — Documents véhicule, clock-icon popover. Labels for relance_sent / status_changed / file_uploaded / marked_cancelled / note_added." } },
        { "name": "edl-kinds", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/edl-kinds",
            "description": "**Screen:** /suivi/{bcId} — EDL summary card title (Livraison | Restitution)." } },
        { "name": "edl-zones (8 wizard zones)", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/edl-zones",
            "description": "**Screen:** /edl/{bc}/{kind} — wizard step indicator (steps 1..8). Vocabulary: face_avant, face_arriere, cote_conducteur, cote_passager, toit, interieur_conducteur, interieur_arriere, coffre." } },
        { "name": "edl-countersign-statuses — NEW", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/edl-countersign-statuses",
            "description": "**Screen:** /suivi/{bcId} — Contre-signature loueur badge colors." } },
        { "name": "damage-severities", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/damage-severities",
            "description": "**Screen:** /edl/{bc}/{kind} — damage form chip selector (Mineur/Modéré/Majeur)." } },
        { "name": "signer-roles", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/signer-roles",
            "description": "**Screen:** /edl/{bc}/{kind} — step 9 signature panel role selector." } },
        { "name": "dispute-statuses", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/dispute-statuses",
            "description": "**Screen:** /contestation/{bc} — Contestation envoyée status card color." } },
        { "name": "dispute-line-categories", "request": { "method": "GET", "header": [], "url": "{{base_url}}/api/v1/fleet/bc/options/dispute-line-categories",
            "description": "**Screen:** /contestation/{bc} — optional category chips on dispute lines." } }
      ]
    }
  ]
}
