feat(eo): complete EO simulation flow (T1 + T3) with Gemini transcription
- Gemini batch transcription (no Deepgram live)
- blobToBase64 helper (shared/lib/audio.ts)
- AudioRecorder: remove onChunk, add maxSeconds/onMaxReached auto-submit
- Timer stops at maxSeconds and triggers auto-submission
- EnregistrementEOPage: audioBase64 to backend, fix race condition step=done
- SimulationFlowProvider: submitEoAudio(audioBase64, mimeType, nclcCible)
- MIME normalization (strip codec params)
- Split CORRECTION_EE_TIMEOUT_MS (60s) / CORRECTION_EO_TIMEOUT_MS (120s)
- PresentationGenereeT1Page: localStorage persistence
Typecheck: OK · Tests: 159/159 ✅
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
71c1ad3018
commit
d1c8b548bb
34 changed files with 3255 additions and 70 deletions
|
|
@ -24,10 +24,12 @@ Pour éviter que ce document devienne un cimetière de dette ignorée (le piège
|
|||
## 1. Dettes héritées de l'audit backend (2026-04-17)
|
||||
|
||||
### FTD-01 — Inconsistance des codes de validation côté backend
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Ouvert — dépend du backend
|
||||
**Estimation de session :** 2h (backend uniquement)
|
||||
**Description :** Le backend utilise deux codes d'erreur pour la même classe (corps de requête invalide) :
|
||||
|
||||
- `VALIDATION_ERROR` dans `routes/simulations.ts` et `routes/corrections.ts`
|
||||
- `INVALID_BODY` dans `routes/plans.ts` et `routes/stripe.ts`
|
||||
|
||||
|
|
@ -41,6 +43,7 @@ Le frontend gère les deux de la même manière (voir `ARCHITECTURE.md` §5), ma
|
|||
---
|
||||
|
||||
### FTD-02 — Header `X-API-Version` envoyé mais non vérifié
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Ouvert
|
||||
**Estimation de session :** 1h (backend) + 30min (frontend)
|
||||
|
|
@ -49,6 +52,7 @@ Le frontend gère les deux de la même manière (voir `ARCHITECTURE.md` §5), ma
|
|||
**Impact :** si le backend évolue de façon breaking (ex : format de réponse de `/plans/status` modifié), le frontend peut recevoir un payload incompatible sans message d'erreur clair. Symptôme : bugs silencieux en production après un déploiement backend.
|
||||
|
||||
**À faire :**
|
||||
|
||||
- Backend : ajouter un middleware qui lit `X-API-Version`, le log, et retourne `HTTP 426 Upgrade Required` avec code `API_VERSION_MISMATCH` si breaking change
|
||||
- Frontend : gérer `API_VERSION_MISMATCH` dans `api-client.ts` → afficher un message "Une nouvelle version est disponible, veuillez rafraîchir la page"
|
||||
|
||||
|
|
@ -57,13 +61,16 @@ Le frontend gère les deux de la même manière (voir `ARCHITECTURE.md` §5), ma
|
|||
---
|
||||
|
||||
### FTD-03 — Quirk `status` dans le body des erreurs de simulations/corrections
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Ouvert — dépend du backend
|
||||
**Estimation de session :** 1h (backend uniquement)
|
||||
**Description :** Les routes `POST /simulations` et `POST /corrections/ee,eo` renvoient un champ `status` dans le body JSON d'erreur, qui duplique le code HTTP :
|
||||
|
||||
```json
|
||||
{ "error": true, "code": "QUOTA_REACHED", "message": "...", "status": 403 }
|
||||
```
|
||||
|
||||
Vient du pattern `c.json(result, result.status)` où `result` contient déjà `status`. C'est ignorable côté frontend (on ne lit pas ce champ), mais c'est du bruit.
|
||||
|
||||
**À faire côté backend :** nettoyer les objets d'erreur retournés par `simulationController` et `correctionController` pour ne pas contenir de champ `status`. Tracé dans **TD-16** à créer dans `expria-backend/docs/TECH_DEBT.md`.
|
||||
|
|
@ -75,6 +82,7 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s
|
|||
## 2. Dettes frontend propres
|
||||
|
||||
### FTD-10 — Semgrep non intégré en CI
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Reporté — après MVP
|
||||
**Estimation de session :** 2h
|
||||
|
|
@ -83,6 +91,7 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s
|
|||
**Impact actuel :** `npm audit` couvre les vulnérabilités des dépendances npm, mais aucune analyse statique de sécurité (SAST) n'est faite sur le code custom du projet. Des patterns dangereux (`eval`, `innerHTML` sans DOMPurify, secrets en dur, etc.) passeraient inaperçus en CI.
|
||||
|
||||
**À faire :**
|
||||
|
||||
- Ajouter un step Semgrep au workflow `.github/workflows/ci.yml`
|
||||
- Utiliser les rulesets `auto` + `r2c-security-audit` + `r2c-ci`
|
||||
- Configurer la sortie pour bloquer sur sévérité ERROR uniquement
|
||||
|
|
@ -93,6 +102,7 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s
|
|||
---
|
||||
|
||||
### FTD-14 — Anti-FOUC thème : script inline manquant dans `<head>`
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Ouvert — à faire avant déploiement production
|
||||
**Estimation de session :** 30 min
|
||||
|
|
@ -102,9 +112,11 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s
|
|||
|
||||
```html
|
||||
<script>
|
||||
(function(){var t=localStorage.getItem('expria-theme');
|
||||
if(t==='dark'||(t!=='light'&&matchMedia('(prefers-color-scheme:dark)').matches))
|
||||
document.documentElement.classList.add('dark')})()
|
||||
;(function () {
|
||||
var t = localStorage.getItem('expria-theme')
|
||||
if (t === 'dark' || (t !== 'light' && matchMedia('(prefers-color-scheme:dark)').matches))
|
||||
document.documentElement.classList.add('dark')
|
||||
})()
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
@ -118,7 +130,97 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s
|
|||
|
||||
---
|
||||
|
||||
### FTD-30 — Rotation token Deepgram sans grace period
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Gelé — Sprint 4c-3 (Deepgram live mis en pause au profit de Gemini batch backend)
|
||||
**Estimation de session :** 0,5 jour
|
||||
**Description :** `useDeepgramLive` redemande un token à T-60 s avant expiration et hot-swap la WebSocket. Si la nouvelle échoue à s'ouvrir avant l'expiration, des chunks peuvent être perdus. **Code dormant depuis le Sprint 4c-3** — à ré-évaluer si Deepgram live est réactivé (cf. FTD-37).
|
||||
**À faire :** retry policy explicite + maintien de l'ancienne connexion tant que la nouvelle n'a pas reçu son premier message. Hors scope tant que le hook reste dormant.
|
||||
|
||||
---
|
||||
|
||||
### FTD-31 — Page `EnregistrementEOPage` non resumable au refresh
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Ouvert — introduit au Sprint 4c-1
|
||||
**Estimation de session :** 0,5 jour
|
||||
**Description :** Si l'utilisateur ferme l'onglet ou recharge la page pendant l'enregistrement, le transcript live et l'audio sont perdus. La simulation côté backend reste avec `rapport=null` mais sans contenu textuel : au resume, le provider redirige vers `/simulation/eo/pre-enregistrement` et l'utilisateur doit recommencer.
|
||||
**À faire :** persister un buffer du transcript final dans `localStorage` à chaque `is_final=true`, restaurer au resume comme point de départ. Décider si on autorise la reprise « par-dessus » ou si on impose un nouveau départ.
|
||||
**Condition de résolution :** session dédiée autosave EO post-MVP.
|
||||
|
||||
---
|
||||
|
||||
### FTD-32 — `useAudioRecorder` non testé sur Safari iOS
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Ouvert — introduit au Sprint 4c-1
|
||||
**Estimation de session :** 0,5 jour
|
||||
**Description :** `pickMimeType()` propose un fallback `audio/mp4` pour Safari, mais aucun test manuel n'a été réalisé. Le bouton « Télécharger l'audio » nomme toujours le fichier `.webm` même quand le mime réel est `audio/mp4`.
|
||||
**À faire :** validation manuelle iOS, adapter l'extension du fichier téléchargé au mime réel via `audioMimeType`.
|
||||
**Condition de résolution :** une fois la version iPhone validée par un testeur réel.
|
||||
|
||||
---
|
||||
|
||||
### FTD-34 — Présentation T1 stockée en clair dans `localStorage`
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Ouvert — introduit au Sprint 4c-2
|
||||
**Estimation de session :** 0,5 jour
|
||||
**Description :** `expria_eo_t1_presentation` contient le texte de la présentation personnelle de l'utilisateur (prénom, âge, ville, parcours, situation familiale, projet d'immigration). Stocké en clair, accessible à tout script tiers exécuté dans le contexte du domaine. Acceptable au MVP : aucune donnée sensible au sens RGPD strict (pas de mot de passe ni numéro fiscal), mais le contenu reste personnel.
|
||||
**À faire :** chiffrement AES-GCM avec clé dérivée du JWT Supabase, ou bascule vers IndexedDB chiffré (libs : `idb-keyval` + `Web Crypto API`). Étendre à toute persistance sensible si on en ajoute (transcripts, audio, etc.).
|
||||
**Condition de résolution :** quand on stocke un jour des contenus plus sensibles via le même mécanisme.
|
||||
|
||||
---
|
||||
|
||||
### FTD-35 — `PresentationGenereeT1Page` : refresh sans simulation active
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Ouvert — introduit au Sprint 4c-2
|
||||
**Estimation de session :** 0,5 jour
|
||||
**Description :** Le hydrate du provider lit `expria_simulation_id` et `expria_eo_t1_presentation` indépendamment. Si l'ID a expiré côté backend (`getSimulationState` rejette en 404) mais que la présentation reste en localStorage, l'utilisateur est redirigé vers `/simulation/eo` au mount du provider, puis la page `PresentationGenereeT1Page` peut être atteinte via reload direct sans `production` valide → la garde `shouldRedirect` envoie vers `/simulation/eo/t1/mode`, qui à son tour redirige vers `/simulation/eo`. Le résultat est correct mais l'utilisateur n'a pas de feedback explicite (« votre simulation a expiré »).
|
||||
**À faire :** afficher un toast / bandeau dédié quand la résolution `getSimulationState` échoue avec une présentation localStorage présente, et proposer un bouton « Recommencer » qui efface la présentation également.
|
||||
**Condition de résolution :** Sprint 4c-3 ou clean post-MVP.
|
||||
|
||||
---
|
||||
|
||||
### FTD-36 — Upload audio base64 in-memory sans indicateur de progression
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Ouvert — introduit au Sprint 4c-3
|
||||
**Estimation de session :** 1 jour
|
||||
**Description :** `EnregistrementEOPage` encode le Blob audio en base64 via `FileReader.readAsDataURL` puis envoie le résultat dans le body JSON de `POST /corrections/eo`. Pour 6 minutes d'audio webm/Opus à 32 kbps ≈ 1,5 Mo binaire ≈ 2 Mo base64. Reste sous le cap 14 Mo backend, mais : (a) tout est chargé en mémoire navigateur, (b) aucun indicateur de progression d'upload (le banner « Transcription et correction en cours » couvre les ~30-60 s totales sans distinguer upload/Gemini/DeepSeek), (c) retry impossible côté navigateur si la connexion mobile coupe en cours d'upload.
|
||||
**À faire :** passer à `multipart/form-data` avec `XMLHttpRequest.upload.onprogress` ou `fetch` + `ReadableStream` ; afficher une barre de progression upload distincte de l'état serveur.
|
||||
**Condition de résolution :** observer un cas réel de plantage mobile/edge OU avant ouverture publique.
|
||||
|
||||
---
|
||||
|
||||
### FTD-37 — Code Deepgram live dormant à trancher
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Ouvert — introduit au Sprint 4c-3
|
||||
**Estimation de session :** 1 jour (réactivation) ou 0,5 jour (suppression)
|
||||
**Description :** Sprint 4c-3 a basculé la transcription EO sur Gemini batch côté backend. Les artefacts Deepgram live restent en place mais sans consommateur :
|
||||
|
||||
- Frontend : `useDeepgramLive`, `TranscriptionDisplay`, `entities/transcription/api.ts` + tests associés
|
||||
- Backend : route `POST /transcriptions/token`, `lib/deepgram.ts` + tests associés
|
||||
**Décision de garde :** conservés 30 jours après la mise en prod du Sprint 4c-3 puis on tranche. Soit (a) réactivation pour réduire la latence perçue (transcription live pendant l'enregistrement vs attente serveur après stop), soit (b) suppression définitive si le retour utilisateur sur la latence Gemini est acceptable.
|
||||
**À faire :** trancher au plus tard 30 jours après la première mise en prod de cette session.
|
||||
|
||||
---
|
||||
|
||||
### FTD-33 — Carte EO_T2_LIVE verrouillée en dur (pas via `hasAccess`)
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Ouvert — introduit au Sprint 4c-1
|
||||
**Estimation de session :** 0,5 jour
|
||||
**Description :** Dans `TaskSelector`, la carte EO_T2_LIVE a `tache: null` ce qui la rend inactive pour tous les plans, indépendamment de `hasAccess(plan, 'oral_t2_live')`. C'est volontaire tant que T2 Live n'est pas livré (Sprint 6) — un utilisateur Premium ne doit pas accéder à une feature non implémentée. À nettoyer dès que T2 Live est wired pour respecter strictement la Règle D (pas de logique de plan en dur).
|
||||
**Condition de résolution :** lancement de T2 Live (Sprint 6).
|
||||
|
||||
---
|
||||
|
||||
### FTD-24 — Pas de polling automatique pour exercices / modèle `pending`
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Résolu — 2026-04-23
|
||||
**Estimation de session :** 2h
|
||||
|
|
@ -127,6 +229,7 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s
|
|||
**Impact UX :** l'utilisateur voit le rapport principal immédiatement, mais doit recharger pour voir ses exercices + production modèle. Expérience acceptable en MVP mais sous-optimale.
|
||||
|
||||
**À faire :**
|
||||
|
||||
- Hook `useRapport` : déclencher un polling automatique via TanStack Query `refetchInterval: 3000` si `exercices_status === 'pending' || modele_status === 'pending'`.
|
||||
- Arrêt du polling dès que les deux statuts sortent de `'pending'` (ready ou error).
|
||||
- Afficher un indicateur visuel discret pendant le polling actif (petit spinner dans JobStatusFallback).
|
||||
|
|
@ -139,12 +242,14 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s
|
|||
---
|
||||
|
||||
### FTD-23 — `useAutosave` continue après correction → 400 VALIDATION_ERROR
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Résolu — 2026-04-23
|
||||
**Estimation de session :** 30 min
|
||||
**Description :** Le hook `useAutosave` (cf. `src/features/simulations/hooks/useAutosave.ts`) peut déclencher un `PATCH /simulations/:id/contenu` après que la correction a été persistée (colonne `rapport !== null`). Le backend refuse alors avec `400 VALIDATION_ERROR` message « Cette simulation a déjà été corrigée. » (cf. `simulationController.autosaveContenu` backend lignes 248-255).
|
||||
|
||||
**Scénario déclencheur :**
|
||||
|
||||
1. L'utilisateur soumet sa production → `rapport` persisté côté backend.
|
||||
2. `SimulationForm` passe `step` à `'done'`, mais :
|
||||
- Le timer d'autosave debouncé (30 s) peut encore fire après cette transition si le debounce n'est pas clear.
|
||||
|
|
@ -152,6 +257,7 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s
|
|||
3. `useAutosave.enabled` est calculé comme `!isSubmitting` dans `SimulationForm` — il redevient `true` après la correction (quand `isSubmitting` repasse à `false`).
|
||||
|
||||
**À faire :**
|
||||
|
||||
- Propager `enabled = !isSubmitting && step !== 'done' && step !== 'correcting'` depuis `SimulationForm`
|
||||
- OU : au montage, quand `rapport` devient non null après correction, clear le timeout debouncé et retirer le handler `beforeunload` immédiatement.
|
||||
- Ajouter un test regression dans `useAutosave.test.ts` qui vérifie qu'aucun `autosaveContenu` n'est appelé après `step='done'`.
|
||||
|
|
@ -163,12 +269,14 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s
|
|||
---
|
||||
|
||||
### FTD-25 — Mise à jour ARCHITECTURE.md §3 (arborescence réelle)
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Ouvert
|
||||
**Estimation de session :** 1h
|
||||
**Description :** ARCHITECTURE.md §3 ne liste pas `entities/patterns`, `features/historique`, `features/progression`, `features/design-system` (ajoutés aux Sprints 3.6c et 3.7). Les composants layout (`AppLayout`, `Sidebar`, `MobileHeader`, `BottomNav`, `MaintenancePage`) sont dans `app/` alors que §3 ne prévoit que `providers`, `router`, `main` dans ce dossier.
|
||||
|
||||
**À faire :**
|
||||
|
||||
- Mettre à jour ARCHITECTURE.md §3 pour refléter l'arborescence réelle.
|
||||
- Formaliser `app/` comme contenant entry points + composants layout de la coquille OU déplacer vers `shared/components/layout/`.
|
||||
|
||||
|
|
@ -177,10 +285,12 @@ Vient du pattern `c.json(result, result.status)` où `result` contient déjà `s
|
|||
---
|
||||
|
||||
### FTD-26 — Clarifier cohabitation `shared/ui/` vs `shared/components/ui/`
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Ouvert
|
||||
**Estimation de session :** 2h
|
||||
**Description :** Deux conventions UI cohabitent sans documentation :
|
||||
|
||||
- `src/shared/ui/{Button,Card,Badge}.tsx` (PascalCase) — wrappers Expria, 40+ imports dans les features.
|
||||
- `src/shared/components/ui/{button,dialog,input,…}.tsx` (kebab-case) — primitives shadcn/ui, 7 fichiers consommateurs.
|
||||
|
||||
|
|
@ -195,12 +305,14 @@ Risque : confusion pour un futur dev sur quel composant utiliser.
|
|||
## 3. Fonctionnalités reportées
|
||||
|
||||
### FTD-07 — Sentry non intégré
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Planifié — après MVP
|
||||
**Estimation de session :** 3h
|
||||
**Description :** Le monitoring frontend (erreurs JS, performances, sessions) n'est pas encore en place. Sans Sentry (ou équivalent), les bugs en production ne remontent pas — on les découvre uniquement si un utilisateur prend la peine de les signaler.
|
||||
|
||||
**À faire :**
|
||||
|
||||
- Créer un compte Sentry (tier gratuit suffit pour démarrer)
|
||||
- Ajouter `@sentry/react` au projet
|
||||
- Intégrer dans `src/app/providers.tsx`
|
||||
|
|
@ -213,12 +325,14 @@ Risque : confusion pour un futur dev sur quel composant utiliser.
|
|||
---
|
||||
|
||||
### FTD-21 — Persistance session simulation
|
||||
|
||||
**Priorité :** 🔴 Critique
|
||||
**Statut :** Partiellement résolu — `/simulation/ee` ✅ (2026-04-21)
|
||||
|
||||
**Pages concernées par ordre de priorité :**
|
||||
|
||||
✅ **`/simulation/ee`** (résolu 2026-04-21)
|
||||
|
||||
- Autosave contenu toutes les 30 s (`useAutosave`)
|
||||
- Save on `beforeunload`
|
||||
- Reprise au refresh via `localStorage` (`expria_simulation_id`) + `GET /simulations/:id`
|
||||
|
|
@ -227,13 +341,16 @@ Risque : confusion pour un futur dev sur quel composant utiliser.
|
|||
- `RapportPage` redirige vers `/simulation/ee` si simulation en cours
|
||||
|
||||
🟡 **`/simulation/eo`** (Sprint 4 — ouvert)
|
||||
|
||||
- Identique EE + état audio/enregistrement
|
||||
|
||||
🟡 **`/examen`** (Sprint 7 — ouvert)
|
||||
|
||||
- Autosave critique — timer inarrêtable + 3 tâches
|
||||
- Crash pendant examen = perte totale
|
||||
|
||||
🟢 **`/sujets`** (inclus dans la résolution EE)
|
||||
|
||||
- `localStorage simulation_id` suffit
|
||||
- Pas d'autosave (pas de données saisies)
|
||||
|
||||
|
|
@ -242,6 +359,7 @@ Risque : confusion pour un futur dev sur quel composant utiliser.
|
|||
**Résolution EE livrée (2026-04-21) :**
|
||||
|
||||
Backend :
|
||||
|
||||
- `simulationController.create` persiste `sujet_id` à la création
|
||||
- `getById` retourne `SimulationState` (tolère `rapport=null` pour resume)
|
||||
- `autosaveContenu` + `updateSujet` controllers (refuse si `rapport !== null`)
|
||||
|
|
@ -249,6 +367,7 @@ Backend :
|
|||
- CORS : `allowMethods` étendu à PATCH/PUT/DELETE
|
||||
|
||||
Frontend :
|
||||
|
||||
- `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
|
||||
|
|
@ -263,6 +382,7 @@ Frontend :
|
|||
> Ces FTDs sont volontairement gelées : elles concernent des fonctionnalités non encore livrées (T2 Live, tests E2E) ou du confort utilisateur non bloquant (option `'system'` thème). Elles **ne comptent pas dans le cap de 15 FTD actives** et seront réactivées quand leur sprint arrive ou quand la condition de déblocage (post-MVP) est atteinte.
|
||||
|
||||
### FTD-06 — AudioWorklet au lieu de ScriptProcessorNode (T2 Live)
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Gelé — post-MVP (T2 Live non encore implémenté)
|
||||
**Estimation de session :** 1 jour
|
||||
|
|
@ -277,6 +397,7 @@ Frontend :
|
|||
---
|
||||
|
||||
### FTD-08 — Tests E2E non implémentés
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Gelé — post-MVP (accepté par design)
|
||||
**Estimation de session :** 2 jours (Playwright setup)
|
||||
|
|
@ -289,12 +410,14 @@ Frontend :
|
|||
---
|
||||
|
||||
### FTD-15 — Option `'system'` manquante dans ThemeProvider
|
||||
|
||||
**Priorité :** 🟢 Mineur
|
||||
**Statut :** Gelé — post-MVP
|
||||
**Estimation de session :** 2h
|
||||
**Description :** Le `ThemeProvider` est bi-state (`'light' | 'dark'`). L'option `'system'` (qui suit `prefers-color-scheme` en temps réel via `MediaQueryList.addEventListener`) a été volontairement différée (décision Sprint 0.5).
|
||||
|
||||
**À faire :**
|
||||
|
||||
- Étendre le type `Theme` à `'light' | 'dark' | 'system'`
|
||||
- Dans `ThemeProvider`, si `theme === 'system'` : écouter `matchMedia('(prefers-color-scheme: dark)')` et appliquer/retirer `.dark` dynamiquement
|
||||
- `ThemeToggle` : cycle light → dark → system (ou un sélecteur 3 états)
|
||||
|
|
@ -307,13 +430,15 @@ Frontend :
|
|||
## 4. Tests à renforcer
|
||||
|
||||
### FTD-09 — Tests de la state machine T2 Live non implémentés
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Planifié — à créer au Sprint 2.5
|
||||
**Estimation de session :** 3h
|
||||
**Description :** La state machine T2 Live (`src/features/t2-live/state/t2-machine.ts`) n'existe pas encore. Quand elle sera créée, elle devra être testée de manière exhaustive (6+ tests couvrant les transitions d'états et les cas d'erreur).
|
||||
|
||||
**À faire au Sprint 2.5 (spike T2 Live) :**
|
||||
- Créer `t2-machine.test.ts` avec tests des transitions : idle → connecting, connecting → listening, listening ↔ speaking, * → error, * → ended
|
||||
|
||||
- Créer `t2-machine.test.ts` avec tests des transitions : idle → connecting, connecting → listening, listening ↔ speaking, _ → error, _ → ended
|
||||
- Tests des messages d'erreur (close code 4001, 4003, autre)
|
||||
|
||||
**Condition de résolution :** fin Sprint 2.5.
|
||||
|
|
@ -321,6 +446,7 @@ Frontend :
|
|||
---
|
||||
|
||||
### FTD-12 — Tests automatisés manquants pour `api-client.ts`
|
||||
|
||||
**Priorité :** 🟡 Important
|
||||
**Statut :** Ouvert — à faire avant intégration des features critiques
|
||||
**Estimation de session :** 3h
|
||||
|
|
@ -329,6 +455,7 @@ Frontend :
|
|||
**Impact actuel :** toute régression sur ce fichier (oubli d'un header, mauvais parsing d'une erreur, boucle de retry infinie sur un edge case) passera inaperçue jusqu'aux tests manuels ou à un bug en production.
|
||||
|
||||
**À faire :**
|
||||
|
||||
- Créer `src/shared/lib/__tests__/api-client.test.ts`
|
||||
- Mocker globalement `fetch` via `vi.fn()`
|
||||
- Couvrir :
|
||||
|
|
@ -350,47 +477,50 @@ Frontend :
|
|||
|
||||
## 5. Historique des résolutions
|
||||
|
||||
| ID | Description | Résolu le | Comment |
|
||||
|---|---|---|---|
|
||||
| FTD-11 | `@theme` Tailwind 4 non défini — palette et typographie absentes | 2026-04-18 | Résolu au Sprint 0.5 (design system). Palette Direction H complète (canvas/surface/ink/expria/deep/semantic) + typo Plus Jakarta Sans définis dans `src/index.css` via `@theme {}` et `.dark {}`. shadcn/ui remappé sur ces tokens. Règle L ajoutée dans `DEVELOPMENT_PRINCIPLES.md` pour garantir l'usage exclusif des tokens. |
|
||||
| FTD-13 | Incompatibilité Vitest 3 / Vite 8 (conflit de types `Plugin<any>` entre le Vite 8 top-level avec Rolldown et le Vite 7 pinné de Vitest 3.2.4 ; `npm run build` cassé) | 2026-04-17 | Résolu par upgrade Vitest `3.2.4 → 4.1.4` (et `@vitest/coverage-v8` idem) à l'étape 12-bis du Sprint 0. Vitest 4.x supporte nativement Vite 8 Rolldown. Correctif complémentaire : script `typecheck` passé de `tsc --noEmit -p tsconfig.app.json` à `tsc -b --noEmit` pour couvrir aussi `tsconfig.node.json` (d'où `vite.config.ts`) et éviter qu'un bug similaire échappe à la CI. |
|
||||
| FTD-16 | `VITE_MAINTENANCE_MODE` non lu dans le code — la variable d'env était dans `env.ts` mais jamais consommée | 2026-04-18 | Résolu au Sprint 1 étape 6. Ajout de `isMaintenanceMode` dans `src/shared/config/env.ts` et garde dans `src/app/main.tsx` : `isMaintenanceMode ? <MaintenancePage /> : <Providers />`. `MaintenancePage` est statique (aucun provider requis), tokens Direction H exclusivement. |
|
||||
| FTD-22 | Code orphelin suite à la refonte UX `/sujets` (2026-04-21) — composant `SujetSelector` et helper `selectSujet` plus référencés après bascule dropdown → page dédiée | 2026-04-23 | Résolution complète. `SujetSelector` + `selectSujet` supprimés. Éléments conservés (`choosing-subject`, `goToSubjectPicker`) sont activement utilisés par `SimulationFlowProvider` et `SimulationForm` — ce n'est plus de la dette. |
|
||||
| FTD-20 | `GET /simulations/:id` manquant dans le backend | 2026-04-22 | Implémenté au Sprint 3.6a (backend) — route complète avec auth, owner check, `REPORT_NOT_READY`. Consommé par `RapportPage` et `useAutosave`. |
|
||||
| FTD-04 | Documents miroir sans automatisation de synchronisation | 2026-04-23 | Risque accepté par design (ADR 004). Mitigation en place (Règle G, commentaire `SOURCE OF TRUTH`, tests de parité). Condition de ré-ouverture : si une divergence silencieuse cause 2+ bugs en production. |
|
||||
| FTD-05 | Ancien scaffold frontend possiblement caduc | 2026-04-23 | Audit Claude Code complet — aucun résidu scaffold Vite, aucun fichier orphelin, règles critiques (D, E, F, G, J + ADR 003/005) respectées. Désalignements documentaires traités via FTD-25 et FTD-26. |
|
||||
| FTD-29 | `.github/dependabot.yml` dans les 2 dépôts | 2026-04-23 | Fichier créé dans expria-frontend et expria-backend. Ecosystem npm, weekly, limit 10 PRs. Dependabot alerts + security updates activés via UI GitHub. |
|
||||
| FTD-27 | CI GitHub Actions pour expria-backend | 2026-04-23 | Workflow créé : npm ci → test → audit. Node 22, trigger push/PR sur main. CI verte au premier run (21s). Observations : typecheck absent (O1), ESLint absent (O2), engines.node absent (O3) — à traiter en FTDs séparées. |
|
||||
| FTD-28 | Semgrep dans CI frontend + backend | 2026-04-23 | Step `semgrep scan --config=auto --error --severity=ERROR` ajouté aux deux workflows CI. Backend vert au 1er run. Frontend vert après correction de 4 erreurs ESLint préexistantes + fix Prettier + ajout env vars CI. |
|
||||
| FTD-17 | Clé `['plan']` dupliquée entre features (`usePlan`, `SimulationPage`, `RapportPage`) | 2026-04-22 | Résolu au Sprint 3.5. Création de `src/entities/user/query-keys.ts` (constantes pures, aucun import runtime) exportant `PLAN_QUERY_KEY = ['plan'] as const`. `features/dashboard/hooks/usePlan.ts` l'importe et le re-exporte pour conserver la rétro-compatibilité de l'import `PLAN_QUERY_KEY`. `SimulationPage.tsx` et `RapportPage.tsx` remplacent leur `useQuery` inline par le hook `usePlan()` — dédup totale de la clé et de la config staleTime. |
|
||||
| FTD-18 | SimulationForm utilise encore le shadcn Button au lieu de la primitive `@/shared/ui/Button` | 2026-04-22 | Résolu au Sprint 3.5. Remplacement de l'import `@/shared/components/ui/button` par `@/shared/ui/Button` dans `SimulationForm.tsx`. Aucun variant à adapter (usage du Button sans prop `variant` → `primary` par défaut dans les deux implémentations). Les 7 autres consommateurs shadcn (`Login/RegisterPage`, `PaywallBanner`, `DesignSystemPage`, `ThemeToggle`, `dialog.tsx`) restent hors scope de cette FTD. |
|
||||
| FTD-23 | `useAutosave` continue après correction → 400 VALIDATION_ERROR | 2026-04-23 | `enabled` corrigé dans `SimulationForm` (`!isSubmitting && step !== 'done' && step !== 'correcting'`). Le `beforeunload` handler et le debounce lisent `enabled` via `latestRef` — tous deux neutralisés dès que `step` transite. 2 tests de régression ajoutés dans `useAutosave.test.ts` : (a) `enabled` true→false annule le debounce en cours, (b) `enabled=false` + `beforeunload` = aucun appel. |
|
||||
| FTD-24 | Pas de polling automatique pour exercices / modèle `pending` | 2026-04-23 | Polling conditionnel dans `useRapport` via `refetchInterval: 3000` tant que `exercices_status === 'pending' \|\| modele_status === 'pending'`. Arrêt automatique dès que les deux sortent de pending (ready ou error). Timeout global 2 min → `hasTimedOut = true` + bouton « Réessayer » dans `JobStatusFallback` (primitive `@/shared/ui/Button`). `refetch()` réinitialise le flag et relance le polling. `staleTime: Infinity` conservé. 5 tests nouveaux dans `useRapport.test.tsx`. |
|
||||
| FTD-19 | Token `--shadow-focus` absent de `src/index.css` | 2026-04-22 | Résolu au Sprint 3.5. Ajout de `--shadow-focus: 0 0 0 3px rgba(27, 79, 216, 0.18)` dans `@theme {}` (valeur conforme à `DESIGN_SYSTEM.md §2`) et `--shadow-focus: 0 0 0 3px rgba(91, 127, 255, 0.32)` dans `.dark {}` (recalculé sur la teinte expria dark `#5B7FFF`). Tailwind 4 génère automatiquement l'utility `shadow-focus`. Migration de 5 occurrences `ring-2 ring-expria/20` → `shadow-focus` dans `Button.tsx`, `Card.tsx`, `SimulationForm.tsx` (×3), `SpecialCharsKeyboard.tsx`. Factorisation bonus : className dupliquée des boutons secondaires de `SimulationForm` extraite en const `secondaryActionBtn`. |
|
||||
| ID | Description | Résolu le | Comment |
|
||||
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| FTD-11 | `@theme` Tailwind 4 non défini — palette et typographie absentes | 2026-04-18 | Résolu au Sprint 0.5 (design system). Palette Direction H complète (canvas/surface/ink/expria/deep/semantic) + typo Plus Jakarta Sans définis dans `src/index.css` via `@theme {}` et `.dark {}`. shadcn/ui remappé sur ces tokens. Règle L ajoutée dans `DEVELOPMENT_PRINCIPLES.md` pour garantir l'usage exclusif des tokens. |
|
||||
| FTD-13 | Incompatibilité Vitest 3 / Vite 8 (conflit de types `Plugin<any>` entre le Vite 8 top-level avec Rolldown et le Vite 7 pinné de Vitest 3.2.4 ; `npm run build` cassé) | 2026-04-17 | Résolu par upgrade Vitest `3.2.4 → 4.1.4` (et `@vitest/coverage-v8` idem) à l'étape 12-bis du Sprint 0. Vitest 4.x supporte nativement Vite 8 Rolldown. Correctif complémentaire : script `typecheck` passé de `tsc --noEmit -p tsconfig.app.json` à `tsc -b --noEmit` pour couvrir aussi `tsconfig.node.json` (d'où `vite.config.ts`) et éviter qu'un bug similaire échappe à la CI. |
|
||||
| FTD-16 | `VITE_MAINTENANCE_MODE` non lu dans le code — la variable d'env était dans `env.ts` mais jamais consommée | 2026-04-18 | Résolu au Sprint 1 étape 6. Ajout de `isMaintenanceMode` dans `src/shared/config/env.ts` et garde dans `src/app/main.tsx` : `isMaintenanceMode ? <MaintenancePage /> : <Providers />`. `MaintenancePage` est statique (aucun provider requis), tokens Direction H exclusivement. |
|
||||
| FTD-22 | Code orphelin suite à la refonte UX `/sujets` (2026-04-21) — composant `SujetSelector` et helper `selectSujet` plus référencés après bascule dropdown → page dédiée | 2026-04-23 | Résolution complète. `SujetSelector` + `selectSujet` supprimés. Éléments conservés (`choosing-subject`, `goToSubjectPicker`) sont activement utilisés par `SimulationFlowProvider` et `SimulationForm` — ce n'est plus de la dette. |
|
||||
| FTD-20 | `GET /simulations/:id` manquant dans le backend | 2026-04-22 | Implémenté au Sprint 3.6a (backend) — route complète avec auth, owner check, `REPORT_NOT_READY`. Consommé par `RapportPage` et `useAutosave`. |
|
||||
| FTD-04 | Documents miroir sans automatisation de synchronisation | 2026-04-23 | Risque accepté par design (ADR 004). Mitigation en place (Règle G, commentaire `SOURCE OF TRUTH`, tests de parité). Condition de ré-ouverture : si une divergence silencieuse cause 2+ bugs en production. |
|
||||
| FTD-05 | Ancien scaffold frontend possiblement caduc | 2026-04-23 | Audit Claude Code complet — aucun résidu scaffold Vite, aucun fichier orphelin, règles critiques (D, E, F, G, J + ADR 003/005) respectées. Désalignements documentaires traités via FTD-25 et FTD-26. |
|
||||
| FTD-29 | `.github/dependabot.yml` dans les 2 dépôts | 2026-04-23 | Fichier créé dans expria-frontend et expria-backend. Ecosystem npm, weekly, limit 10 PRs. Dependabot alerts + security updates activés via UI GitHub. |
|
||||
| FTD-27 | CI GitHub Actions pour expria-backend | 2026-04-23 | Workflow créé : npm ci → test → audit. Node 22, trigger push/PR sur main. CI verte au premier run (21s). Observations : typecheck absent (O1), ESLint absent (O2), engines.node absent (O3) — à traiter en FTDs séparées. |
|
||||
| FTD-28 | Semgrep dans CI frontend + backend | 2026-04-23 | Step `semgrep scan --config=auto --error --severity=ERROR` ajouté aux deux workflows CI. Backend vert au 1er run. Frontend vert après correction de 4 erreurs ESLint préexistantes + fix Prettier + ajout env vars CI. |
|
||||
| FTD-17 | Clé `['plan']` dupliquée entre features (`usePlan`, `SimulationPage`, `RapportPage`) | 2026-04-22 | Résolu au Sprint 3.5. Création de `src/entities/user/query-keys.ts` (constantes pures, aucun import runtime) exportant `PLAN_QUERY_KEY = ['plan'] as const`. `features/dashboard/hooks/usePlan.ts` l'importe et le re-exporte pour conserver la rétro-compatibilité de l'import `PLAN_QUERY_KEY`. `SimulationPage.tsx` et `RapportPage.tsx` remplacent leur `useQuery` inline par le hook `usePlan()` — dédup totale de la clé et de la config staleTime. |
|
||||
| FTD-18 | SimulationForm utilise encore le shadcn Button au lieu de la primitive `@/shared/ui/Button` | 2026-04-22 | Résolu au Sprint 3.5. Remplacement de l'import `@/shared/components/ui/button` par `@/shared/ui/Button` dans `SimulationForm.tsx`. Aucun variant à adapter (usage du Button sans prop `variant` → `primary` par défaut dans les deux implémentations). Les 7 autres consommateurs shadcn (`Login/RegisterPage`, `PaywallBanner`, `DesignSystemPage`, `ThemeToggle`, `dialog.tsx`) restent hors scope de cette FTD. |
|
||||
| FTD-23 | `useAutosave` continue après correction → 400 VALIDATION_ERROR | 2026-04-23 | `enabled` corrigé dans `SimulationForm` (`!isSubmitting && step !== 'done' && step !== 'correcting'`). Le `beforeunload` handler et le debounce lisent `enabled` via `latestRef` — tous deux neutralisés dès que `step` transite. 2 tests de régression ajoutés dans `useAutosave.test.ts` : (a) `enabled` true→false annule le debounce en cours, (b) `enabled=false` + `beforeunload` = aucun appel. |
|
||||
| FTD-24 | Pas de polling automatique pour exercices / modèle `pending` | 2026-04-23 | Polling conditionnel dans `useRapport` via `refetchInterval: 3000` tant que `exercices_status === 'pending' \|\| modele_status === 'pending'`. Arrêt automatique dès que les deux sortent de pending (ready ou error). Timeout global 2 min → `hasTimedOut = true` + bouton « Réessayer » dans `JobStatusFallback` (primitive `@/shared/ui/Button`). `refetch()` réinitialise le flag et relance le polling. `staleTime: Infinity` conservé. 5 tests nouveaux dans `useRapport.test.tsx`. |
|
||||
| FTD-19 | Token `--shadow-focus` absent de `src/index.css` | 2026-04-22 | Résolu au Sprint 3.5. Ajout de `--shadow-focus: 0 0 0 3px rgba(27, 79, 216, 0.18)` dans `@theme {}` (valeur conforme à `DESIGN_SYSTEM.md §2`) et `--shadow-focus: 0 0 0 3px rgba(91, 127, 255, 0.32)` dans `.dark {}` (recalculé sur la teinte expria dark `#5B7FFF`). Tailwind 4 génère automatiquement l'utility `shadow-focus`. Migration de 5 occurrences `ring-2 ring-expria/20` → `shadow-focus` dans `Button.tsx`, `Card.tsx`, `SimulationForm.tsx` (×3), `SpecialCharsKeyboard.tsx`. Factorisation bonus : className dupliquée des boutons secondaires de `SimulationForm` extraite en const `secondaryActionBtn`. |
|
||||
|
||||
---
|
||||
|
||||
## 6. Historique de ce document
|
||||
|
||||
| Version | Date | Changements |
|
||||
|---|---|---|
|
||||
| 1.0 | 2026-04-17 | Création initiale avec 9 FTD identifiées depuis l'audit backend et les décisions d'architecture |
|
||||
| 1.1 | 2026-04-17 | Ajout FTD-10 (Semgrep CI), FTD-11 (`@theme` Tailwind 4), FTD-12 (tests `api-client`) suite à l'étape 11 du Sprint 0 |
|
||||
| 1.2 | 2026-04-17 | Ajout FTD-13 résolu (incompatibilité Vitest 3 / Vite 8) suite à l'étape 12-bis du Sprint 0 |
|
||||
| 1.3 | 2026-04-18 | FTD-11 résolu (design system Sprint 0.5) ; ajout FTD-14 (anti-FOUC), FTD-15 (option 'system' thème) |
|
||||
| 1.4 | 2026-04-18 | FTD-16 résolu (VITE_MAINTENANCE_MODE implémenté — Sprint 1 étape 6) |
|
||||
| 1.5 | 2026-04-19 | Ajout FTD-17 (clé ['plan'] dupliquée entre features — Sprint 3 étape 14) |
|
||||
| 1.6 | 2026-04-20 | Ajout FTD-18 (SimulationForm shadcn Button — Sprint 0.5 bis D2) ; ajout FTD-19 (token --shadow-focus manquant — Sprint 0.5 bis D2) |
|
||||
| 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 |
|
||||
| 1.11 | 2026-04-22 | Sprint 3.5 Clean — FTD-17, FTD-18, FTD-19 résolus. 15 FTD actives restantes (cap de 15 respecté) |
|
||||
| 1.12 | 2026-04-22 | Sprint 3.6a — Ajout FTD-23 🟡 (useAutosave fire après correction). 16 FTD actives → cap de 15 dépassé temporairement, à revoir au prochain clean. |
|
||||
| 1.13 | 2026-04-22 | Sprint 3.6b — Ajout FTD-24 🟡 (polling auto exercices/modèle pending). 17 FTD actives → cap dépassé, un clean 3.6.5 devra résoudre FTD-23/24 ensemble. |
|
||||
| 1.14 | 2026-04-23 | Triage : FTD-04, FTD-05, FTD-20, FTD-22 fermées. FTD-25, FTD-26 ajoutées. 15 FTD actives (cap respecté). |
|
||||
| 1.15 | 2026-04-23 | Réorg sécurité : FTD-06, FTD-08, FTD-15 gelées (backlog post-MVP). FTD-27 🔴, FTD-28 🔴, FTD-29 🟡 ajoutées (sécurité). 15 FTD actives (cap respecté). |
|
||||
| 1.16 | 2026-04-23 | FTD-29 fermée (Dependabot config). 14 FTD actives. |
|
||||
| 1.17 | 2026-04-23 | FTD-27 fermée (CI backend). 13 FTD actives. |
|
||||
| 1.18 | 2026-04-23 | FTD-28 fermée (Semgrep CI). CI frontend verte pour la première fois. 12 FTD actives. |
|
||||
| 1.19 | 2026-04-23 | FTD-23 et FTD-24 fermées (clean useAutosave après correction + polling automatique jobs pending dans useRapport). 10 FTD actives (cap 15). |
|
||||
| Version | Date | Changements |
|
||||
| ------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 1.0 | 2026-04-17 | Création initiale avec 9 FTD identifiées depuis l'audit backend et les décisions d'architecture |
|
||||
| 1.1 | 2026-04-17 | Ajout FTD-10 (Semgrep CI), FTD-11 (`@theme` Tailwind 4), FTD-12 (tests `api-client`) suite à l'étape 11 du Sprint 0 |
|
||||
| 1.2 | 2026-04-17 | Ajout FTD-13 résolu (incompatibilité Vitest 3 / Vite 8) suite à l'étape 12-bis du Sprint 0 |
|
||||
| 1.3 | 2026-04-18 | FTD-11 résolu (design system Sprint 0.5) ; ajout FTD-14 (anti-FOUC), FTD-15 (option 'system' thème) |
|
||||
| 1.4 | 2026-04-18 | FTD-16 résolu (VITE_MAINTENANCE_MODE implémenté — Sprint 1 étape 6) |
|
||||
| 1.5 | 2026-04-19 | Ajout FTD-17 (clé ['plan'] dupliquée entre features — Sprint 3 étape 14) |
|
||||
| 1.6 | 2026-04-20 | Ajout FTD-18 (SimulationForm shadcn Button — Sprint 0.5 bis D2) ; ajout FTD-19 (token --shadow-focus manquant — Sprint 0.5 bis D2) |
|
||||
| 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 |
|
||||
| 1.11 | 2026-04-22 | Sprint 3.5 Clean — FTD-17, FTD-18, FTD-19 résolus. 15 FTD actives restantes (cap de 15 respecté) |
|
||||
| 1.12 | 2026-04-22 | Sprint 3.6a — Ajout FTD-23 🟡 (useAutosave fire après correction). 16 FTD actives → cap de 15 dépassé temporairement, à revoir au prochain clean. |
|
||||
| 1.13 | 2026-04-22 | Sprint 3.6b — Ajout FTD-24 🟡 (polling auto exercices/modèle pending). 17 FTD actives → cap dépassé, un clean 3.6.5 devra résoudre FTD-23/24 ensemble. |
|
||||
| 1.14 | 2026-04-23 | Triage : FTD-04, FTD-05, FTD-20, FTD-22 fermées. FTD-25, FTD-26 ajoutées. 15 FTD actives (cap respecté). |
|
||||
| 1.15 | 2026-04-23 | Réorg sécurité : FTD-06, FTD-08, FTD-15 gelées (backlog post-MVP). FTD-27 🔴, FTD-28 🔴, FTD-29 🟡 ajoutées (sécurité). 15 FTD actives (cap respecté). |
|
||||
| 1.16 | 2026-04-23 | FTD-29 fermée (Dependabot config). 14 FTD actives. |
|
||||
| 1.17 | 2026-04-23 | FTD-27 fermée (CI backend). 13 FTD actives. |
|
||||
| 1.18 | 2026-04-23 | FTD-28 fermée (Semgrep CI). CI frontend verte pour la première fois. 12 FTD actives. |
|
||||
| 1.19 | 2026-04-23 | FTD-23 et FTD-24 fermées (clean useAutosave après correction + polling automatique jobs pending dans useRapport). 10 FTD actives (cap 15). |
|
||||
| 1.20 | 2026-04-25 | Sprint 4c-1 — Ajout FTD-30 🟡 (rotation token Deepgram sans grace period), FTD-31 🟢 (page enregistrement EO non resumable), FTD-32 🟢 (Safari iOS non testé), FTD-33 🟢 (EO_T2_LIVE verrouillé en dur). 14 FTD actives (cap 15 respecté). |
|
||||
| 1.21 | 2026-04-25 | Sprint 4c-2 — Ajout FTD-34 🟢 (présentation T1 en localStorage clair), FTD-35 🟡 (refresh sans simulation active sur PresentationGenereeT1Page). **16 FTD actives — cap dépassé temporairement, accepté par Hermann pour cette session ; clean à planifier au prochain Sprint.** |
|
||||
| 1.22 | 2026-04-25 | Sprint 4c-3 — Ajout FTD-36 🟡 (upload audio base64 sans progression), FTD-37 🟢 (code Deepgram live dormant à trancher). FTD-30 dégradée 🟡→🟢 et passée en « gelé » (Deepgram live mis en pause). **17 FTD actives — cap toujours dépassé, clean prioritaire au Sprint suivant.** |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue