# Sprint 6 — Engagement export (Markdown + CSV + PDF) > Branch : `sprint/6-export` · Worktree : `.claude/worktrees/sprint-6-export` · Base : `main` @ `678ee8f` ## §0 — Binding decisions (locked with the user 2026-06-07) 1. **Scope du sprint** : export d'un engagement (header + toutes ses simulations RT + SOC) vers Markdown, CSV et PDF — clôt la boucle « remplace l'utilisation d'un fichier excel plat partagé entre la redteam et les analystes SOC en fin de mission ». 2. **Formats livrés** : Markdown, CSV, PDF (3 formats). JSON exclu (redondant avec l'API existante). 3. **RBAC** : `admin` + `redteam` peuvent exporter. **SOC = pas d'accès** (pas de bouton dans l'UI, endpoint `/api/engagements//export` → 403). Cohérent avec le pattern templates sprint 5 (livrable RedTeam). 4. **Contenu de l'export** : Engagement header (name, description, dates, status, created_by, created_at) + **toutes** les simulations de l'engagement, avec leurs champs RT (name, techniques, tactics, description, commands, prerequisites, executed_at, execution_result, status) ET SOC (log_source, logs, soc_comment, incident_number). Ordre des simulations : `id ASC` (ordre de création). 5. **Déclenchement UI** : un bouton **split-button dropdown** sur `EngagementDetailPage` libellé `[Export ▼]`, qui ouvre un menu `Markdown / CSV / PDF`. Click → download direct (Blob + `URL.createObjectURL`). Pas de modal de configuration. Pattern réutilisé du dropdown sprint 5 (`SimulationList`). ### Décisions techniques arrêtées par le team-lead (à challenger par spec-reviewer) 6. **Endpoint backend** : **un seul** endpoint `GET /api/engagements//export?format=md|csv|pdf` plutôt que 3 endpoints distincts. Une seule route à protéger (RBAC), un seul test d'intégration RBAC, switch sur `format` en interne. Format inconnu → **400** `{error: "format must be one of: md, csv, pdf"}`. Format manquant → **400** (pas de défaut implicite — évite l'ambiguïté). 7. **Markdown** : généré via string templating Python (pas de lib externe). Simple, déterministe, testable par assertion de sous-chaînes. 8. **CSV** : généré via `csv.writer` (stdlib). Une ligne d'en-tête + N lignes simulations. Colonnes : `id, name, status, techniques (joined "|"), tactics (joined "|"), description, commands, prerequisites, executed_at, execution_result, log_source, logs, soc_comment, incident_number, created_at, updated_at`. **Pas de header engagement dans le CSV** (format machine-readable strict) ; l'engagement context sort dans le filename. 9. **PDF** : généré via **WeasyPrint** (Python HTML→PDF, lib mature, qualité de rendu pro, dépendances système cairo/pango/gdk-pixbuf à ajouter au `python:3.12-slim` du Dockerfile). Pipeline : on génère **le même HTML** que pour le Markdown (mais wrappé en `...