10 KiB
10 KiB
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.tsetlib.tsavec tests
2026-04-21 — Tâche G5 — Suggestions d'idées DeepSeek
Ajouté
- Backend —
POST /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)danssrc/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 - Frontend —
getIdees(consigne, contenu)dansentities/report/api.ts(POST/sujets/idees, timeoutMs 15 000) - Hook
useIdees—useMutationexposant{ 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: Planajouté àSimulationForm(wiringplanData.plandepuisSimulationPage)
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, ouidees.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, composantSujetSelector,getSujets()surGET /sujets?mode=&tache=) - Refonte UX
/sujets(Option A) — page dédiée avec grille de cartesSujetCard(responsive 1/2/3 colonnes), état partagé viaSimulationFlowProviderpour survivre aux navigations entre/simulation/eeet/sujets. MVP : refresh sur/sujetsredirige vers/simulation/ee. - Bouton "Changer de sujet" dans
SimulationForm— retour à/sujetsviagoToSubjectPicker - Prop
type: 'EE' | 'EO'surTaskSelector(EO_CARDS réservé usage futur — non routé,/simulation/eoresteComingSoonjusqu'au Sprint EO)
Modifié
useSimulationrefacto en consommateur deSimulationFlowProvider(source de vérité déplacée hors du hook)SujetDisplayredevient 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émentsimulations_useddéplacé desimulationController.create()verscorrectionController.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
selectSujetdeuseSimulation— orphelin - FTD-22 tracée résolue partiellement (step
'choosing-subject'goToSubjectPickerconservé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.ts—Critere.note→Critere.score,Report.exercices: Exercice[]→Report.exercices: string[], JSDoc ajustésrc/features/simulations/pages/RapportPage.tsx— importExerciceretiré,critere.note→critere.score,ExerciceCardrefactoré pour consommer unestringrendue en Markdown, clé d'itération par index
Supprimé
- Interface
Exercice { titre, contenu }deentities/report/types.ts— remplacée parstring[]pour coller au contrat backend
Contexte (backend associé, expria-backend)
Quatre commits côté backend finalisent l'alignement du contrat Report :
feat(corrections): renommagesproduction_modele→modele,suggestions_idees→idees, ajoutfeedback_court+ prompts DeepSeek mis à jour + validations runtimefeat(corrections): réponse enrichie avecsimulation_idcôtécorrectionControllerfeat(simulations): nouvelle routeGET /simulations/:id(auth owner, gestionSIMULATION_NOT_FOUND/AUTH_REQUIRED/REPORT_NOT_READY) + 4 testsfeat(simulations): sujet aléatoire (tablesujets) 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 | nulldansentities/production/types.ts - Consommer le sujet retourné dans
SimulationPage(affichage consigne + docs) - Consommer
feedback_courtdansRapportPage(rendu toujours visible — cf. PLANS_TARIFAIRES §2 — déjà supporté par le typeReport, 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 verrouillagehasAccess()(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>sionClickfourni)src/shared/ui/Badge.tsx— primitive Badge (variants: plan/nclc/neutral ; couleur selonplanValuepour variant plan)
Modifié
src/app/router.tsx— layout routes viaPrivateLayout(ProtectedRoute+AppLayout+Outlet) ;ComingSooninline ; redirect/simulation→/simulation/eesrc/features/simulations/components/TaskSelector.tsx— refonte avecCard interactive/Card default opacity-60,Badge"EE"/"EO", eyebrowtracking-widest, icône verrousrc/features/simulations/pages/SimulationPage.tsx— suppression header interne (Logo + ThemeToggle) ; root<main>;Buttonmigré vers@/shared/ui/Buttonvariant="secondary"src/features/dashboard/pages/DashboardPage.tsx— suppression header interne ;Buttonvariant="primary"avecnavigate('/simulation/ee');Badgevariant="plan" planValue={data.plan}; tout migré vers@/shared/ui/
Documentation
docs/TECH_DEBT.mdv1.6 — ajout FTD-18 (SimulationForm migration Button), FTD-19 (token--shadow-focusmanquant)
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_MODEdansmain.tsx— sitrue, aucun provider ne se monte, aucun appel réseau - Variable
VITE_MAINTENANCE_MODEdansenv.ts(optionnelle, défautfalse) - 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 — ajoutVITE_MAINTENANCE_MODEdans la liste des variablesTECH_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é)