Les tests E2E échouaient pour trois raisons principales :
1. Initialisation asynchrone TipTap — L'éditeur rich-text s'initialise
via des imports dynamiques dans onMount(). Les tests interagissaient
avec .rich-text-content avant que l'élément n'existe dans le DOM.
Ajout d'attentes explicites avant chaque interaction avec l'éditeur.
2. Pollution inter-tests — Les fonctions de nettoyage (classes, subjects)
ne supprimaient pas les tables dépendantes (homework, evaluations,
schedule_slots), provoquant des erreurs FK silencieuses dans les
try/catch. De plus, homework_submissions n'a pas de ON DELETE CASCADE
sur homework_id, nécessitant une suppression explicite.
3. État partagé du tenant — Les règles de devoirs (homework_rules) et le
calendrier scolaire (school_calendar_entries avec Vacances de Printemps)
persistaient entre les fichiers de test, bloquant la création de devoirs
dans des tests non liés aux règles.
Les enseignants avaient besoin de consignes plus claires pour les élèves :
le champ description en texte brut ne permettait ni mise en forme ni
partage de documents. Cette limitation obligeait à décrire verbalement
les ressources au lieu de les joindre directement.
L'éditeur WYSIWYG (TipTap) remplace le textarea avec gras, italique,
listes et liens. Le contenu HTML est sanitisé côté backend via
symfony/html-sanitizer pour prévenir les injections XSS. Les pièces
jointes (PDF, JPEG, PNG, max 10 Mo) sont uploadées via une API dédiée
avec validation MIME côté domaine et protection path-traversal sur le
téléchargement. Les descriptions en texte brut existantes restent
lisibles sans migration de données.
La page devoirs enchaînait séquentiellement les appels classes, subjects,
assignments et homework, produisant un waterfall de ~2.5s. En les lançant
dans un seul Promise.all, le temps de chargement correspond désormais au
plus lent des appels (~600ms) au lieu de leur somme.
Pour résoudre la dépendance de assignments sur le userId (nécessaire dans
l'URL), un nouveau helper getAuthenticatedUserId() encapsule le mécanisme
de token refresh côté module auth, évitant aux pages d'importer
refreshToken directement.
Chaque branche side-effect (loadAssignments, loadHomeworks) gère ses
erreurs via .catch() local pour éviter l'état partiel si l'une échoue
pendant que les autres réussissent.
Un enseignant qui donne le même travail à plusieurs classes devait
jusqu'ici recréer manuellement chaque devoir. La duplication permet
de sélectionner les classes cibles, d'ajuster les dates d'échéance
par classe, et de créer tous les devoirs en une seule opération
atomique (transaction).
La validation s'effectue par classe (affectation enseignant, date
d'échéance) avec un rapport d'erreurs détaillé. L'infrastructure
de warnings est prête pour les règles de timing de la Story 5.3.
Le filtrage par classe dans la liste des devoirs passe côté serveur
pour rester compatible avec la pagination.
Les enseignants avaient besoin d'un outil pour créer des devoirs assignés
à leurs classes, avec filtrage automatique par matière selon la classe
sélectionnée. Le système valide que la date d'échéance tombe un jour
ouvrable (lundi-vendredi) et empêche les dates dans le passé.
Le domaine modélise le devoir comme un agrégat avec pièces jointes,
statut brouillon/publié, et événements métier (création, modification,
suppression). Les handlers de notification écoutent ces événements pour
les futurs envois aux parents et élèves.