From 656b42e6c4e2bf498e2924f97aec323ff338e27e Mon Sep 17 00:00:00 2001 From: Hermann_Kitio Date: Tue, 21 Apr 2026 04:54:09 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20FTD-21=20r=C3=A9solu=20partiellement=20?= =?UTF-8?q?pour=20/simulation/ee?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/CHANGELOG.md | 21 +++++++++++++++++++++ docs/TECH_DEBT.md | 38 ++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 7508030..741daaf 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -37,6 +37,27 @@ Chaque entrée suit ce format : - Code source de `src/entities/user/access.ts` et `lib.ts` avec tests +## 2026-04-21 — FTD-21 — Persistance session `/simulation/ee` + +### Added +- `useAutosave(simulationId, contenu, enabled)` : autosave debounce 30 s + flush sur `beforeunload`, dedup par dernier contenu sauvegardé (6 tests). +- `SimulationFlowProvider` hydrate la session au montage depuis `localStorage` (`expria_simulation_id`) → `GET /simulations/:id` → restaure `step='task-selected'` + `production` + `sujet` si `rapport=null` ; nettoie la clé sinon (3 tests resume). +- Types `SimulationState`, `SimulationRapport` + API `getSimulationState`, `autosaveContenu`, `updateSujet` dans `entities/production`. +- Indicateur "Sauvegardé à HH:MM" sous la textarea `SimulationForm` (text-xs, `aria-live="polite"`). + +### Changed +- `getReport` délègue désormais à `getSimulationState` et lève `REPORT_NOT_READY` si `rapport=null`. `RapportPage` catche cette erreur et redirige vers `/simulation/ee` avec message discret "Votre simulation est en cours.". +- `SimulationForm` accepte `simulationId`, `initialContenu`, `step` et persiste `expria_simulation_id` dans `localStorage` tant que la simulation est active ; nettoie la clé quand `step='done'`. +- `changeSubject` persiste le changement côté backend via `PATCH /simulations/:id/sujet` (best-effort, silencieux si échec). + +### Security +- localStorage ne stocke que `simulation_id` (UUID non-sensible) — conforme SECURITY.md §2.6. + +### Notes +- FTD-21 reste ouvert pour `/simulation/eo` (Sprint 4) et `/examen` (Sprint 7). + +--- + ## 2026-04-21 — Tâche G5 — Suggestions d'idées DeepSeek ### Ajouté diff --git a/docs/TECH_DEBT.md b/docs/TECH_DEBT.md index 48372cf..91a0d11 100644 --- a/docs/TECH_DEBT.md +++ b/docs/TECH_DEBT.md @@ -270,42 +270,47 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s ### FTD-21 — Persistance session simulation **Priorité :** 🔴 Critique -**Statut :** Partiellement résolu — `/simulation/ee` en cours +**Statut :** Partiellement résolu — `/simulation/ee` ✅ (2026-04-21) **Pages concernées par ordre de priorité :** -🔴 **`/simulation/ee`** (cette session) -- Autosave contenu toutes les 30 s +✅ **`/simulation/ee`** (résolu 2026-04-21) +- Autosave contenu toutes les 30 s (`useAutosave`) - Save on `beforeunload` -- Reprise au refresh via `localStorage` + `GET /simulations/:id` +- Reprise au refresh via `localStorage` (`expria_simulation_id`) + `GET /simulations/:id` +- `PATCH /simulations/:id/contenu` + `PATCH /simulations/:id/sujet` (Option C) +- `getById` tolère `rapport=null` (Option A) +- `RapportPage` redirige vers `/simulation/ee` si simulation en cours -🟡 **`/simulation/eo`** (Sprint 4) +🟡 **`/simulation/eo`** (Sprint 4 — ouvert) - Identique EE + état audio/enregistrement -🟡 **`/examen`** (Sprint 7) +🟡 **`/examen`** (Sprint 7 — ouvert) - Autosave critique — timer inarrêtable + 3 tâches - Crash pendant examen = perte totale -🟢 **`/sujets`** (inclus dans cette session) +🟢 **`/sujets`** (inclus dans la résolution EE) - `localStorage simulation_id` suffit - Pas d'autosave (pas de données saisies) ❌ **Pas nécessaire :** `/dashboard`, `/rapport/:id`, `/historique`, `/progression` -**À faire pour `/simulation/ee` :** +**Résolution EE livrée (2026-04-21) :** Backend : -- Migration Supabase : ajouter `sujet_id uuid REFERENCES sujets(id)` dans `productions` -- `simulationController` : stocker `sujet_id` à la création -- `GET /simulations/:id` : retourner sujet associé -- Nouveau endpoint `PATCH /simulations/:id/contenu` pour autosave +- `simulationController.create` persiste `sujet_id` à la création +- `getById` retourne `SimulationState` (tolère `rapport=null` pour resume) +- `autosaveContenu` + `updateSujet` controllers (refuse si `rapport !== null`) +- Routes `PATCH /simulations/:id/contenu` + `PATCH /simulations/:id/sujet` +- CORS : `allowMethods` étendu à PATCH/PUT/DELETE Frontend : -- `localStorage` : stocker/lire `simulation_id` courant -- `SimulationForm` : autosave debounce 30 s + save on `beforeunload` -- `SimulationFlowProvider` : au chargement, détecter simulation en cours via `localStorage` → `GET /simulations/:id` → restaurer state +- `useAutosave` : debounce 30 s + `beforeunload` flush + dedup par contenu +- `SimulationForm` : hydrate `initialContenu`, affiche "Sauvegardé à HH:MM" +- `SimulationFlowProvider` : hydratation au montage depuis `localStorage` → restaure step `task-selected` si rapport null, nettoie sinon +- `getReport` délègue à `getSimulationState` et throw `REPORT_NOT_READY` si rapport null -**Condition de résolution :** session dédiée après G1-G5 (EE d'abord, EO + examen ultérieurement). +**Condition de résolution complète :** intégration EO (Sprint 4) + examen (Sprint 7). --- @@ -378,3 +383,4 @@ Frontend : | 1.7 | 2026-04-20 | Ajout FTD-20 🔴 (GET /simulations/:id manquant backend — bloque RapportPage Sprint 3 étape 15) | | 1.8 | 2026-04-20 | Ajout FTD-21 🔴 (persistance session simulation — prod + sujet perdus au refresh, session dédiée après G1-G5) | | 1.9 | 2026-04-21 | FTD-22 résolu partiellement (nettoyage code orphelin refonte `/sujets` — `SujetSelector` + `selectSujet` supprimés ; `choosing-subject` + `goToSubjectPicker` conservés) | +| 1.10 | 2026-04-21 | FTD-21 résolu partiellement pour `/simulation/ee` (autosave 30 s + `beforeunload` + reprise via `localStorage` + `PATCH /:id/contenu` + `PATCH /:id/sujet` + `getById` tolère `rapport=null`) ; EO + examen restent ouverts |