expria-frontend/docs/CHANGELOG.md
Hermann_Kitio 8390e8b873 feat(corrections): Sprint 3.6a — nouveaux prompts + taxonomie erreurs + génération parallèle
Côté frontend : timeout corrections 30→60s (aligné avec backend 55s),
FTD-23 documentée, TAXONOMIE_ERREURS.md ajouté.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:28:02 +03:00

17 KiB
Raw Blame History

Changelog — Expria Frontend

Toutes les modifications notables du projet frontend sont documentées dans ce fichier.

Format basé sur Keep a Changelog.

Convention

Chaque entrée suit ce format :

## [Unreleased] — YYYY-MM-DD — Session <nom>

### Added (nouveautés)
- ...

### Changed (modifications)
- ...

### Fixed (corrections)
- ...

### Removed (suppressions)
- ...

### Security (sécurité)
- ...

[Unreleased]

Added

  • Documentation initiale du projet (ARCHITECTURE, ONBOARDING, SECURITY, etc.)
  • 5 ADRs pour les décisions architecturales majeures
  • Code source de src/entities/user/access.ts et lib.ts avec tests

[Unreleased] — 2026-04-22 — Sprint 3.5 — Clean post-Sprint 3

Changed

  • FTD-17 résolu : PLAN_QUERY_KEY centralisé dans src/entities/user/query-keys.ts (constantes pures, aucun import runtime). usePlan le ré-exporte ; SimulationPage et RapportPage remplacent leur useQuery inline par le hook usePlan() — déduplication totale de la clé et de la config staleTime.
  • FTD-18 résolu : SimulationForm migré de @/shared/components/ui/button (shadcn) vers la primitive canonique @/shared/ui/Button. Aucun variant à adapter (usage sans prop variant).
  • FTD-19 résolu : token --shadow-focus ajouté dans @theme {} (0 0 0 3px rgba(27, 79, 216, 0.18) — conforme DESIGN_SYSTEM.md §2) et dans .dark {} (recalculé sur la teinte expria dark). Migration de 5 occurrences ring-2 ring-expria/20 → utility shadow-focus dans Button, Card, SimulationForm (×3), SpecialCharsKeyboard.
  • Factorisation SimulationForm : className dupliquée des deux boutons secondaires (« Suggestions d'idées » / « Changer de sujet ») extraite en const locale secondaryActionBtn.
  • TECH_DEBT.md → v1.11. 15 FTD actives (cap de 15 respecté).

Notes

  • Timeouts DeepSeek intermittents observés pendant les tests manuels Groupe B + C — cause externe (API tierce), hors périmètre refactor Sprint 3.5.
  • B8 : comportement actuel diffère du spec PARCOURS_UTILISATEURS.md §2 "Quota atteint" — affichage d'une bannière inline au lieu du modal de blocage attendu. À corriger dans un sprint dédié (non inclus dans ce clean, qui n'introduit aucune nouvelle fonctionnalité).

[Unreleased] — 2026-04-22 — Sprint 3.6a — Qualité correction — Backend

Added (backend)

  • src/lib/taxonomieErreurs.ts : constantes des 63 codes TCF Canada + 4 codes autre par critère, validation runtime isValidCode / isValidCritere, et injection au prompt via buildTaxonomyPromptSection.
  • Prompts dynamiques dans src/lib/deepseek.ts : buildCorrectionPrompt (prompt maître avec nclc_cible 9 ou 10, sujet, documents T3), buildModelPrompt (production modèle cible NCLC 9 fixe), buildExercicesPrompt (3 exercices ciblés sur erreurs_codes + extraits exemple, format {difficulte, theme, diagnostic, consigne, extrait, indice, correction, explication}).
  • Post-traitement production modèle : wordCountTCF, stripModelAnnotations, truncateToMaxWords.
  • Route POST /corrections/ee accepte le paramètre nclc_cible (optionnel, défaut 9, valeurs acceptées : 9 ou 10 ; sinon 400 VALIDATION_ERROR).
  • Migration SQL supabase/migrations/004_sprint_3_6a_qualite_correction.sql — colonnes : revelation, diagnostic, conseil_nclc, erreurs_codes, exercices, modele, nclc_cible, exercices_status, modele_status + index GIN sur erreurs_codes (pour Sprint 3.6c).
  • controllers/__tests__/correctionController.test.ts (7 tests) : parallélisme, statuts ready/error, nclc_cible=10 propagé, simulation introuvable/autre user.
  • docs/TECH_DEBT.md TD-15 🟡 : jobs fire-and-forget peuvent rester pending si redémarrage process.

Changed (backend)

  • correctEE dans deepseek.ts — nouvelle signature correctEE(CorrectionInput) + nouvelle forme CorrectionRapport (revelation, diagnostic, criteres[{exemple,suggestion,astuce}], conseil_nclc, erreurs_codes). EERapport devient alias de CorrectionRapport.
  • correctionController.correctEE : lance 3 appels DeepSeek en parallèle ; await uniquement sur la correction pour répondre 200 ; modèle et exercices s'exécutent en fire-and-forget et mettent à jour {exercices,exercices_status} et {modele,modele_status} en base (pending → ready/error).
  • simulationController.getById retourne les nouveaux champs : nclc_cible, exercices, exercices_status, modele, modele_status en plus du rapport enrichi.
  • deepseek.test.ts réécrit — 25 tests (ancien pipeline supprimé, nouveaux tests sur correctEE/generateProductionModele/generateExercices/helpers + EO inchangé).

Notes

  • Option A retenue : backend renvoie uniquement la nouvelle forme. Frontend (Sprint 3.6b) casse tant que non livré — livraison groupée sans déploiement intermédiaire.
  • Prompt exercices rédigé côté backend (option b), basé sur les codes taxonomie + extraits exemple des critères. Format aligné sur captures d'écran demandées.
  • Migration SQL à exécuter manuellement via supabase db push — Hermann avant le premier test end-to-end.
  • Tests backend : 173/173 verts (+18 vs baseline de 155).

[Unreleased] — 2026-04-22 — Planification Sprint 3.6a/3.6b/3.6c

Added

  • Sprints 3.6a (backend prompts + taxonomie), 3.6b (frontend rapport enrichi), 3.6c (analyse patterns Premium) ajoutés à la ROADMAP entre Sprint 3.5 et Sprint 4.
  • TAXONOMIE_ERREURS.md — 63 codes d'erreurs TCF Canada sur 4 critères + 4 codes « autre » + procédure d'enrichissement.

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é

  • BackendPOST /sujets/idees : génère 5 suggestions d'idées via DeepSeek pour aider l'étudiant à prolonger sa rédaction (prompt coach TCF Canada, temperature 0.5, timeout 15 s via AbortSignal, JSON strict { idees: string[] })
  • generateIdees(consigne, contenu) dans src/lib/deepseek.ts (validation tableau non vide)
  • 5 tests route POST /sujets/idees : 401 sans auth, 400 sujet_consigne manquant, 400 contenu < 30 mots, 200 succès avec idees[], 500 DeepSeek throw
  • FrontendgetIdees(consigne, contenu) dans entities/report/api.ts (POST /sujets/idees, timeoutMs 15 000)
  • Hook useIdeesuseMutation exposant { idees, isLoading, error, fetchIdees, reset }
  • Composant IdeesSuggestions — modal shadcn Dialog avec liste à puces, états loading/erreur/succès, reset() automatique à la fermeture
  • Bouton "Suggestions d'idées" (icône Lightbulb) dans SimulationForm à côté de "Changer de sujet"
  • Prop plan: Plan ajouté à SimulationForm (wiring planData.plan depuis SimulationPage)

Règles d'accès

  • Règle D respectée : hasAccess(plan, 'tips') obligatoire
  • Plan Free : bouton visible mais désactivé avec tooltip "Disponible en Standard" (tips=false pour Free)
  • Standard + Premium : bouton actif dès 30 mots écrits
  • Désactivé également si !sujet, isSubmitting, ou idees.isLoading

Tests

  • Backend — Typecheck : 0 erreur, Vitest : 144/144 passés (+5 tests POST /sujets/idees)
  • Frontend — Typecheck : 0 erreur, Vitest : 67/67 passés
  • Test manuel : validé avec compte Standard (bouton actif à 30+ mots, modal affiche 5 idées) et Free (bouton verrouillé avec tooltip)

2026-04-21 — Tâche G4 + Refonte page /sujets + Fix quota simulations

Ajouté

  • Tâche G4 — choix du sujet avec dropdown intégré et bouton aléatoire dans SimulationForm (hook useSujets, composant SujetSelector, getSujets() sur GET /sujets?mode=&tache=)
  • Refonte UX /sujets (Option A) — page dédiée avec grille de cartes SujetCard (responsive 1/2/3 colonnes), état partagé via SimulationFlowProvider pour survivre aux navigations entre /simulation/ee et /sujets. MVP : refresh sur /sujets redirige vers /simulation/ee.
  • Bouton "Changer de sujet" dans SimulationForm — retour à /sujets via goToSubjectPicker
  • Prop type: 'EE' | 'EO' sur TaskSelector (EO_CARDS réservé usage futur — non routé, /simulation/eo reste ComingSoon jusqu'au Sprint EO)

Modifié

  • useSimulation refacto en consommateur de SimulationFlowProvider (source de vérité déplacée hors du hook)
  • SujetDisplay redevient présentationnel (dropdown retiré)
  • TaskSelector : retrait des cartes EO de la page Expression Écrite (affiche uniquement EE T1/T2/T3)

Corrigé

  • Quota simulations (backend — commit ecb478e, expria-backend) : incrément simulations_used déplacé de simulationController.create() vers correctionController.correctEE/EO (Option B). Une simulation créée mais jamais corrigée ne consomme plus le quota utilisateur.

Supprimé

  • SujetSelector.tsx — orphelin après refonte /sujets
  • Helper selectSujet de useSimulation — orphelin
  • FTD-22 tracée résolue partiellement (step 'choosing-subject'
    • goToSubjectPicker conservés intentionnellement)

Tests

  • Typecheck : 0 erreur
  • Vitest : 67/67 passés
  • Test manuel : flux complet EE T1 avec choix de sujet (carte + aléatoire + changement de sujet) validé

2026-04-21 — Tâches G2+G3 — Clavier + Minuteur

Ajouté

  • Composant SpecialCharsKeyboard — 30 caractères spéciaux français en flex-wrap, sticky au scroll
  • Bloc "Temps restant" sticky avec TimerDisplay MM:SS (critique < 2min : rouge + pulse, expiré : rouge bold)
  • Composant WordCountBar — barre de progression colorée (orange < cible, vert dans cible, rouge > cible)
  • Hook useTimer avec 7 tests unitaires
  • Config par tâche dans simulationConfig.ts (EE T1: 10min/60-120 mots, T2: 20min/120-150, T3: 30min/120-180)
  • Auto-submit à l'expiration si ≥ 30 mots
  • Bouton "Soumettre ma production" (était "Envoyer")
  • Textarea auto-resize sans scroll interne

Changed

  • Compteur de caractères remplacé par WordCountBar
  • Bouton soumission bloqué si < 30 mots

Tests

  • Typecheck : 0 erreur
  • Vitest : 66/66 passés (+7 tests useTimer)
  • Test manuel : minuteur + clavier validés sur mobile et desktop

2026-04-21 — Tâche G1 — Affichage de la consigne

Ajouté

  • Interface SujetData dans entities/production/types.ts
  • Production enrichie avec sujet: SujetData | null
  • Composant SujetDisplay — affiche consigne, rôle, contexte, doc1, doc2 selon le sujet retourné
  • useSimulation expose sujet dans son retour
  • SimulationForm intègre SujetDisplay au-dessus de la textarea
  • FTD-21 tracée (persistance session simulation)

Tests

  • Typecheck : 0 erreur
  • Vitest : 59/59 passés
  • Test manuel : consigne affichée sur /simulation/ee

2026-04-20 — Audit frontend ↔ backend — alignement types Report

Modifié

  • src/entities/report/types.tsCritere.noteCritere.score, Report.exercices: Exercice[]Report.exercices: string[], JSDoc ajusté
  • src/features/simulations/pages/RapportPage.tsx — import Exercice retiré, critere.notecritere.score, ExerciceCard refactoré pour consommer une string rendue en Markdown, clé d'itération par index

Supprimé

  • Interface Exercice { titre, contenu } de entities/report/types.ts — remplacée par string[] pour coller au contrat backend

Contexte (backend associé, expria-backend)

Quatre commits côté backend finalisent l'alignement du contrat Report :

  • feat(corrections): renommages production_modelemodele, suggestions_ideesidees, ajout feedback_court + prompts DeepSeek mis à jour + validations runtime
  • feat(corrections): réponse enrichie avec simulation_id côté correctionController
  • feat(simulations): nouvelle route GET /simulations/:id (auth owner, gestion SIMULATION_NOT_FOUND/AUTH_REQUIRED/REPORT_NOT_READY) + 4 tests
  • feat(simulations): sujet aléatoire (table sujets) retourné avec chaque production créée (EO_T2_LIVE exclu, non bloquant si aucun sujet actif)

Tests

  • Typecheck : 0 erreur
  • Vitest : 59/59 passés

À faire (hors scope — session frontend dédiée ultérieurement)

  • Ajouter sujet: SujetData | null dans entities/production/types.ts
  • Consommer le sujet retourné dans SimulationPage (affichage consigne + docs)
  • Consommer feedback_court dans RapportPage (rendu toujours visible — cf. PLANS_TARIFAIRES §2 — déjà supporté par le type Report, reste à brancher dans l'UI si ce n'est pas déjà le cas)

2026-04-20 — Sprint 0.5 bis — AppLayout + primitives UI + refonte visuelle

Ajouté

  • src/app/AppLayout.tsx — layout applicatif desktop/mobile (sidebar fixe 240px, drawer mobile, BottomNav)
  • src/app/Sidebar.tsx — navigation latérale avec verrouillage hasAccess() (Progression, Examen blanc, Historique)
  • src/app/MobileHeader.tsx — header mobile sticky (Logo, ThemeToggle, bouton menu hamburger)
  • src/app/BottomNav.tsx — navigation mobile fixe (4 items, bottom sheet "Simuler", tap target min 44px)
  • src/shared/ui/Button.tsx — primitive Button (variants: primary/secondary/ghost/upgrade ; sizes: sm/md/lg ; loading Loader2)
  • src/shared/ui/Card.tsx — primitive Card (variants: default/raised/interactive ; rendu <button> si onClick fourni)
  • src/shared/ui/Badge.tsx — primitive Badge (variants: plan/nclc/neutral ; couleur selon planValue pour variant plan)

Modifié

  • src/app/router.tsx — layout routes via PrivateLayout (ProtectedRoute + AppLayout + Outlet) ; ComingSoon inline ; redirect /simulation/simulation/ee
  • src/features/simulations/components/TaskSelector.tsx — refonte avec Card interactive / Card default opacity-60, Badge "EE"/"EO", eyebrow tracking-widest, icône verrou
  • src/features/simulations/pages/SimulationPage.tsx — suppression header interne (Logo + ThemeToggle) ; root <main> ; Button migré vers @/shared/ui/Button variant="secondary"
  • src/features/dashboard/pages/DashboardPage.tsx — suppression header interne ; Button variant="primary" avec navigate('/simulation/ee') ; Badge variant="plan" planValue={data.plan} ; tout migré vers @/shared/ui/

Documentation

  • docs/TECH_DEBT.md v1.6 — ajout FTD-18 (SimulationForm migration Button), FTD-19 (token --shadow-focus manquant)

Tests

  • Typecheck : 0 erreur
  • Vitest : 59/59 passés
  • Tests manuels : à valider par Hermann

2026-04-19 — Sprint 1 / Étape 6 — Maintenance mode + outillage sécurité

Ajouté

  • Page de maintenance statique (src/app/MaintenancePage.tsx) — logo + message, tokens Direction H, zéro dépendance
  • Guard VITE_MAINTENANCE_MODE dans main.tsx — si true, aucun provider ne se monte, aucun appel réseau
  • Variable VITE_MAINTENANCE_MODE dans env.ts (optionnelle, défaut false)
  • Hook PreToolUse Claude Code (security-check.sh) — 9 patterns SECURITY.md §2
  • Hook Stop Claude Code (check-file-size.sh) — alerte fichiers > 200 lignes
  • MCP server Semgrep enregistré dans Claude Code

Documentation

  • ARCHITECTURE.md §7 — ajout VITE_MAINTENANCE_MODE dans la liste des variables
  • TECH_DEBT.md — FTD-16 résolu (maintenance mode implémenté)

Tests

  • Typecheck : 0 erreur
  • Vitest : 37/37 passés
  • Test manuel : maintenance mode vérifié (page affichée, aucun appel réseau, routing bloqué)