From 01434c04a759800241eef0e73f5b4c4d694fd673 Mon Sep 17 00:00:00 2001 From: Knacky Date: Sun, 7 Jun 2026 18:29:59 +0200 Subject: [PATCH] =?UTF-8?q?docs(plan):=20sprint=206=20=E2=80=94=20engageme?= =?UTF-8?q?nt=20export=20(md/csv/pdf)=20plan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 3 user stories scoped (US-29 export formats, US-30 SOC zero access, US-31 format/engagement robustness). Backend extends engagements_bp with GET /api/engagements//export?format=md|csv|pdf returning the rendered file, no DB schema change. Frontend adds an ExportEngagementButton split-button dropdown on EngagementDetailPage, gated to admin+redteam. Binding decisions locked with the user: 3 formats Markdown/CSV/PDF, RBAC admin+redteam, engagement + all simulations RT+SOC, single endpoint with format query param. WeasyPrint chosen for PDF (Python HTML→PDF, ~50MB cairo/pango deps to add to Dockerfile, accepted). Plan ready for spec-reviewer Pass 1. --- tasks/todo.md | 463 +++++++++++++++++++++++--------------------------- 1 file changed, 212 insertions(+), 251 deletions(-) diff --git a/tasks/todo.md b/tasks/todo.md index 1ef89fd..c842216 100644 --- a/tasks/todo.md +++ b/tasks/todo.md @@ -1,300 +1,261 @@ -# Sprint 5 — Simulation templates +# Sprint 6 — Engagement export (Markdown + CSV + PDF) -**Branche** : `sprint/5-templates` -**Statut** : 🟢 SPRINT COMPLET — backend 226/226 + frontend 121/121 + e2e 201/201, PR prête -**Base** : `main` @ `9873c53` (PR #7 sprint 4 mergé) -**Objectif** : permettre à un admin/redteam de créer des **templates de simulations** pré-remplies (RT-side : name, description, commands, prerequisites, techniques, tactics). Instancier un template dans un engagement crée une nouvelle simulation décorrélée (copie indépendante — éditer l'instance ne touche pas le template et vice-versa). User QA item 8 sprint 3. +> 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 `...