# Évolution LMS EFEKTIVACADEMIE — Backlog d'issues par sprint (05/08/2026)

85 issues — état de l'art re-vérifié le 05/08 sur la branche de référence `development` (les mentions « État development » dans les issues en découlent).

⚠️ **Phase 0 close le 05/08 : les décisions de `06_DECISIONS_ATELIER_P0.md` prévalent sur toute recommandation par défaut mentionnée ici.** Les issues ci-dessous ont été mises à jour en conséquence ; en cas de divergence, le relevé de décisions fait foi. **Les issues du chantier tracking/pilotage (EA-004/005, EA-010…013, EA-016/017, EA-049, EA-051, EA-055, EA-082) sont spécifiées par `05_SPEC_PILOTAGE_ANALYTICS.md` (schémas de tables, KPI figés, recette bout-en-bout) — cette spec prévaut sur les CA résumés ici.**

Conventions :
- **Repo** : `BACK` (EFEKTIVACADEMIE-BACK), `FRONT` (EFEKTIVACADEMIE-FRONT), `PIPELINE` (microlearning-video-v2-light), ou combiné. Branche de référence : `development`.
- **Labels** proposés : `chantier:CH0…CH7`, `sprint:S1…S10`, `type:feat|fix|sec|infra|design`, `bloquant` (sur le chemin critique d'autres issues).
- **Dépend de** : l'issue ne démarre pas tant que la dépendance n'est pas livrée (P0.x/P1.x = livrables de cadrage/conception, cf. `02_PLAN_ACTION.md`).
- Les critères d'acceptation (CA) sont contractuels : une issue n'est fermée que si tous sont vérifiés.

---

## Sprint 1 — CH0 Assainissement + CH1 Socle tracking

### EA-001 · [BACK] Migrations de rattrapage — aligner le schéma sur la prod
`type:infra` `bloquant` — Dépend de : P0.4
État `development` (re-vérifié 05/08) : `is_active`, `order_no`, `category_id` ont leurs migrations. Restent : fillable fantômes de `sections` (`description`, `start_date`, `frequency`, `start_after_enroll`), colonne morte `sections.required_score`, écriture `enrollments.is_complete` à vérifier, `down()` vide sur la migration `is_active`, FK `category_id/subcategory_id` en `onDelete cascade` (supprimer une catégorie détruit ses cours !), fichiers de debug versionnés à purger.
**CA** : diff schéma prod ↔ migrations documenté ; fillable fantômes tranchés (migration ou retrait) ; cascade remplacée par `set null`/restrict + test ; `migrate:fresh` + seed produit un schéma iso-prod ; dépôt purgé des fichiers parasites.

### EA-002 · [BACK] Sécurité certificats — IDOR + périmètre du ZIP
`type:sec` — Dépend de : —
`downloadCertificate` fait un `find($id)` sans contrôle de propriété (IDOR + **500** sur ID inexistant, `LearnerCourseController.php:205-215`) ; les PDF sont sur le disque `public` (atteignables par URL directe) ; `downloadAllCertificates` zippe tout le dossier pour un manager sans `course_ids`.
**CA** : un apprenant ne peut télécharger que ses certificats (403 sinon, 404 propre sur ID inexistant, testé) ; certificats déplacés hors disque public ; le ZIP manager est limité à son périmètre hiérarchique ; tests d'accès ajoutés.

### EA-003 · [BACK] Création d'utilisateurs — admin uniquement + liste blanche de rôles
`type:sec` `bloquant` — Dépend de : P0.2
**Escalade de privilèges complète (re-vérifiée sur `development`)** : `assignRole($validated['role'])` est exécuté **avant** le garde-fou (`UserController.php:630` vs switch ligne 647), `role` sans liste blanche (la règle `in:` correcte existe ligne 920 du même fichier — régression), 5 points d'entrée → un `sub_manager` peut créer un `admin` en une requête.
**CA** : **création ET modification de compte réservées à l'admin** (décision F9 — plus strict que la proposition initiale : le retrait vise aussi la modification) ; `Rule::in` sur les rôles autorisés AVANT toute persistance ; les autres rôles conservent l'inscription d'utilisateurs *existants* à des formations et l'invitation d'inconnus via compte inactif (EA-044) ; test prouvant qu'un sub_manager ne peut plus créer d'admin.
Note : la partie « liste blanche + ordre de contrôle » est **déjà livrée** par la PR de sécurité #11 ; reste le retrait fonctionnel des routes.

### EA-004 · [BACK] Ressources de cours — route de téléchargement authentifiée et journalisée
`type:sec` `bloquant` — Dépend de : —
`course_files` est servi en statique public (`/storage/course_resources/...`) : non authentifié, non journalisé, non révocable. Aggravations re-vérifiées : `getFiles` ne vérifie pas l'inscription au cours ; `deleteFile` fait un `find($id)` sans contrôle de propriété (IDOR en écriture).
**CA** : route authentifiée conforme **spec Lot 1.2** (table `resource_downloads` avec `kind=resource|certificate` ; la route certificats existante journalise aussi) ; les fichiers ne sont plus accessibles en direct (hors disque `public` ou règle serveur) ; anciens liens front migrés (cf. EA-005) ; test : un download crée exactement une ligne et renvoie le fichier.

### EA-005 · [FRONT] Consommer la route de téléchargement authentifiée
`type:sec` — Dépend de : EA-004
**CA** : l'onglet Ressources et tout lien de fichier passent par la route authentifiée (blob/redirect) ; plus aucune URL `VITE_APP_MEDIA_URL + stored_path` pour les ressources (spec Lot 1.2 : 3 endroits identifiés dans le front).

### EA-006 · [BACK] Uploads — restrictions MIME et taille
`type:sec` — Dépend de : —
**CA** : liste blanche de types MIME par contexte (ressources, images, médias de leçon) ; message d'erreur clair ; test de rejet d'un exécutable renommé.

### EA-007 · [FRONT] Retrait de la visio ZegoCloud (secret exposé)
`type:sec` — Dépend de : **décision F15** (actée : retrait complet, « à étudier plus tard »)
`serverSecret` en clair dans `VideoCallRoom.jsx` + `generateKitTokenForTest`.
**CA** : route `/video-call`, composant, icônes d'appel et dépendance retirés ; le type de message `video_call` reste toléré à l'affichage pour l'historique ; secret révoqué côté ZegoCloud.

### EA-008 · [FRONT] Gardes de routes par rôle
`type:sec` — Dépend de : P0.2
`ProtectedRoute` ne vérifie qu'un token ; le rôle est lu du localStorage sans contrôle.
**CA** : chaque route déclare les rôles autorisés ; accès refusé → redirection propre ; le rôle de référence vient de l'API (`/my-status` ou équivalent), pas du localStorage seul.

### EA-009 · [BACK] Bugs de reporting connus
`type:fix` — Dépend de : —
Quatre bugs identifiés dans l'audit : `getSingleCourseStats` ignore le périmètre managérial (signature à 1 paramètre), `CourseCompleRation` sans `unique()` (doubles comptages), `month-wise-chart` non filtré par périmètre, `sidebarStatics` switch sans `break` (sub_manager/manager_general → payload director).
**CA** : chaque bug corrigé + test de non-régression chiffré (jeu de données avec 2 managers, vérif que chacun ne voit que son périmètre).

### EA-010 · [BACK] Tracking — journal des connexions
`type:feat` `bloquant` — Dépend de : spec 05 (Lot 1.3)
**CA** : table `login_events` (`user_id, logged_at, ip_truncated, user_agent`) alimentée à la création du token Sanctum — sans dépendre des tokens, supprimés au logout ; `users.last_login_at` maintenu ; exposé nulle part pour l'instant (l'exposition vient en EA-016).

### EA-011 · [BACK] Tracking — ouvertures de supports (lesson_views)
`type:feat` `bloquant` — Dépend de : spec 05 (Lot 1.1)
**CA** : table `lesson_views` conforme spec (`user_id, lesson_id, course_id dénormalisé, viewed_at, duration_seconds, source` ; index `(course_id, viewed_at)` et `(user_id, viewed_at)`) ; `POST /api/track/lesson-view` appelé au montage du composant de lecture ; **insertion systématique** (historique, pas d'updateOrCreate) ; anti-bruit côté back : vues du même user×lesson espacées de moins de [30] s ignorées — **valeur configurable, pas une constante en dur** (elle ne pourra être calibrée qu'après observation de données réelles) ; l'endpoint renvoie l'identifiant de la vue retenue (cf. piège EA-012).

### EA-012 · [BACK] Tracking — progression média et temps passé
`type:feat` `bloquant` — Dépend de : spec 05 (Lot 1.1), EA-011
**CA** : `lesson_views.duration_seconds` renseignée en fin de lecture (heartbeat ou `navigator.sendBeacon` à la fermeture, best effort — méthode figée par la spec) ; en complément, position de lecture par user×support persistée (pour la reprise EA-035) ; écritures non bloquantes (queue si nécessaire) ; le temps passé par support et par cours est calculable par simple agrégation.

⚠️ **Piège à traiter explicitement — couplage dédoublonnage ↔ durée.** La vue et sa durée sont
écrites en deux temps (ouverture, puis fermeture). Quand la fenêtre anti-bruit d'EA-011 écarte une
ouverture comme doublon, la durée qui arrive ensuite doit se **rattacher à la ligne conservée** :
ni ligne orpheline, ni écrasement d'une durée déjà mesurée. Correctif de conception recommandé :
le front génère un **identifiant de vue** au montage du lecteur et le renvoie avec la durée ; le
back résout cet identifiant vers la ligne retenue (et non vers un couple user×leçon, ambigu).
**CA associés** : (a) rouvrir 3 fois une leçon en 10 s produit 1 ligne et 1 durée cohérente ;
(b) deux consultations réellement espacées produisent 2 lignes avec 2 durées distinctes ;
(c) une durée arrivant après un doublon écarté ne crée aucune ligne supplémentaire ;
(d) une durée en retard n'écrase jamais une valeur déjà supérieure.

### EA-013 · [BACK] Quiz — historisation des tentatives
`type:feat` `bloquant` — Dépend de : —
`attemptQuestion()` supprime les scores précédents ; `quizRetake()` purge tout.
**CA** : table `quiz_attempts` conforme spec Lot 1.4 (`user_id, quiz_id, attempt_no, score_percent, submitted_at`) + détail des réponses par tentative ; alimentée à chaque soumission **sans supprimer** `quiz_scores`, qui reste la « dernière tentative » (rétro-compat front) ; reprise des `quiz_scores` existants comme tentative n°1.

### EA-014 · [BACK] Pagination paramétrable
`type:fix` — Dépend de : —
`UserController::index` pagine à 20 en dur.
**CA** : `per_page` respecté (borné, ex. 10-100) sur les endpoints de liste ; défaut inchangé.

### EA-083 · [BACK] Quiz autonomes — périmètre et mise en file de la notification
`type:fix` — Dépend de : —
Découvert à la re-vérification : `notifyStandaloneQuizIfAvailable` (`QuizController.php:245-291`) notifie **tous les apprenants de la plateforme** (aucun périmètre d'inscription) avec une boucle d'emails **synchrone** dans le cycle requête → timeout assuré à la publication sur une base de quelques centaines d'apprenants.
**CA** : ciblage limité au périmètre pertinent (inscrits du cours parent, ou périmètre décidé en P0.2 pour les quiz vraiment autonomes) ; envoi via queue ; test de non-régression sur le déclenchement unique (`standalone_notified_at`).

### EA-015 · [BACK] Complétion — unicité et garde-fous
`type:fix` — Dépend de : —
`completed_courses` sans contrainte d'unicité ; certificat généré pour un cours sans leçon ni quiz (`0 === 0`).
**CA** : contrainte unique `(learner_id, course_id)` + dédoublonnage des données existantes ; pas de complétion/certificat sur cours vide ; tests.

---

## Sprint 2 — CH1 fin + CH2 Socle UX transverse

### EA-016 · [BACK] Exposition API des données de suivi
`type:feat` `bloquant` — Dépend de : EA-010, EA-011, EA-012, EA-013
**CA** : les API manager/admin exposent par apprenant×cours : `completed_at` (dans `GET /manager/learner/detail/{id}` et l'export XLSX — spec Lot 1.5), dernière connexion, nombre de connexions, **jours actifs distincts**, temps total, temps moyen par session, téléchargements, tentatives de quiz ; agrégats par cours (funnel inscrits→démarrés→terminés) ; **KPI implémentés exactement selon la spec Lot 2.5** (Démarré = ≥1 lesson_view OU ≥1 learner_lesson OU ≥1 tentative ; Récurrence = jours calendaires distincts avec événement ; Taux de complétion = terminés ÷ inscrits, période et périmètre appliqués aux deux termes ; exclusion des rôles ≠ learner et des comptes « test ») ; périmètre hiérarchique respecté partout ; agrégations SQL (pas de N+1) ; **critère de sortie : scénario de recette bout-en-bout de la spec vérifié**.

### EA-017 · [BACK] Tracking — conformité RGPD
`type:infra` — Dépend de : spec 05 (exigences transverses), EA-010…013
**CA** : IP tronquée (/24) ou hashée ; rétention paramétrable ([24] mois par défaut) + purge planifiée ; mention dans la politique de confidentialité + texte d'information utilisateur (front) ; accès aux données nominatives limité aux rôles habilités (F11) ; **droit d'accès/effacement couvrant les nouvelles tables** (export + suppression sur demande).

### EA-018 · [BACK] % d'avancement par apprenant×cours — pondéré par la durée
`type:feat` `bloquant` — Dépend de : **décision F3** (actée 05/08), EA-028
**CA** : avancement = **somme des durées des supports terminés ÷ durée totale de la formation** (option B, décision F3) — service unique, pas de calculs dispersés. Les supports sans durée intrinsèque (quiz notamment) reçoivent une **durée estimée par défaut** (proposition : 30 s par question), **modifiable par l'admin** comme toute autre durée ; sans cela la pondération est incalculable. Exposé dans les payloads apprenant (mes cours) et manager (listes, cockpit) ; statut dérivé Non débutée/En cours/Terminée exposé par apprenant×cours ; cohérent avec les agrégats dashboard.
**Conditions posées par le métier (F3)** : (a) l'affichage reste **explicite pour l'apprenant** — le pourcentage est accompagné d'un compteur en clair (« 3 leçons terminées sur 5 »), la pondération n'est jamais exposée telle quelle ; (b) les **leçons terminées sont visualisées** en complément de la barre de progression.

### EA-019 · [FRONT] Composant DataTable générique
`type:feat` `bloquant` — Dépend de : P1.9
Tables maison dupliquées (tri recopié 6×, aucun filtre).
**CA** : composant unique : tri sur toutes les colonnes déclarées, filtres par colonne (facettes), recherche globale, pagination serveur, états vides/chargement ; documenté ; adopté sur un premier écran pilote (admin utilisateurs) sans régression.

### EA-020 · [BACK] Contrat API générique de listes
`type:feat` `bloquant` — Dépend de : P1.9
**CA** : convention unique `?search=&sort[]=&filters[]=&page=&per_page=` implémentée via un trait/scope réutilisable ; appliquée à l'endpoint utilisateurs (pilote) ; documentée pour la généralisation.

### EA-021 · [FRONT+BACK] Préférences de colonnes par utilisateur
`type:feat` — Dépend de : EA-019
**CA** : ordre des colonnes modifiable par glisser-déposer ; afficher/masquer par colonne ; persisté par user et par écran (table `user_preferences`) ; restauré à la connexion ; bouton réinitialiser.

### EA-022 · [BACK] Export Excel générique
`type:feat` — Dépend de : EA-020, décision Z16
**CA** : tout endpoint de liste au contrat générique est exportable en XLSX avec les filtres/tris courants appliqués et les colonnes visibles de l'utilisateur ; périmètre de données par rôle respecté (matrice Z16) ; en-têtes FR.

### EA-023 · [FRONT] Bouton d'export sur toutes les vues listes
`type:feat` — Dépend de : EA-019, EA-022
**CA** : bouton export sur chaque écran migré vers la DataTable ; téléchargement du XLSX reflétant exactement la vue courante (filtres, tris, colonnes).

### EA-024 · [BACK] Socle notifications
`type:feat` `bloquant` — Dépend de : P1.8
État `development` (re-vérifié 05/08) : le front est **déjà fonctionnel** (cloche, non-lus, marquage lu) ; le back reste limité à **5 types** (inscription ×3, réponse de fil suivi, quiz autonome), sans préférences, sans emails couplés, sans push.
**CA** : service unique d'émission (événement → notification in-app + email — canaux actés en F14) ; types couverts au minimum : cours affecté, cours terminé, certificat obtenu, message reçu, annonce, invitation, ticket ; **préférences par utilisateur : oui** ; **digest : oui** — envoi immédiat pour chat, annonces et tickets, digest pour les événements de faible priorité (type « cours ajouté ») ; compteur non-lus + marquage lu ; templates email HTML FR (remplace `Mail::raw`).

### EA-025 · [FRONT] Centre de notifications — extension
`type:feat` — Dépend de : EA-024
La cloche est **déjà fonctionnelle** sur `development` (badge non-lus, liste, marquage lu — `NavbarPanel.jsx:1048-1134`) ; issue rescopée en extension.
**CA** : clic sur une notification → navigation vers l'objet concerné ; couverture des nouveaux types EA-024 ; écran de préférences utilisateur ; mise à jour temps réel via Echo/Pusher ou polling (choix P1.8).

### EA-026 · [FRONT] Navigation retour systématique
`type:feat` — Dépend de : —
**CA** : chaque écran de détail a un retour ramenant à la page précédente (`navigate(-1)` avec repli vers la liste parente si accès direct par URL) ; le bouton retour de la page cours est couvert ; composant partagé (fin des SVG dupliqués).

---

## Sprint 3 — CH3 Modèle de contenu + page cours v1

### EA-027 · [BACK] Typage des supports et vocabulaire Formation>Leçon>Support
`type:feat` `bloquant` — Dépend de : **décision F1** (actée 05/08)
Le modèle ne connaît que `lesson` (type deviné par extension) et `quiz`.
**CA** : table de **types de supports administrable** — chaque type porte un libellé, une icône et une **famille de rendu** parmi `video | audio | document | page` (modèle « étiquette + famille de rendu », décision F1) ; types initiaux : vidéo, podcast, réel, article, fiche, **infographie** (famille document), **quiz = support à part entière** ; l'admin peut créer un nouveau type en le rattachant à une famille existante, **sans développement** ; le champ `support_type` remplace la déduction par extension et est rétro-rempli sur l'existant ; l'API expose type + famille ; le renommage de vocabulaire (section→leçon, lesson→support) est appliqué côté libellés API/front sans casser les tables.
Hors périmètre (chiffrage séparé si besoin) : type entièrement libre avec rendu configurable.

### EA-028 · [BACK] Durées par support et durée de leçon
`type:feat` — Dépend de : **décision F2** (actée 05/08), EA-027
**CA** : chaque support porte une durée résolue selon un **ordre de priorité strict** : (1) durée fournie par l'**import automatique du module** (manifeste SCORM/xAPI/JSON pipeline) ; (2) à défaut, **extraction automatique** — ffprobe à l'upload, oEmbed **côté serveur et stocké une fois** pour les URLs (fin des appels oEmbed à chaque affichage), estimation mots ÷ 200/min pour article/fiche ; (3) l'**admin peut toujours corriger** la durée de n'importe quel support, y compris celle issue d'un import. La source retenue est tracée (import / auto / manuelle). Durée de leçon = somme des supports, durée de formation = somme des leçons ; **précision à la seconde** ; exposées dans les payloads ; rétro-remplissage de l'existant.

### EA-029 · [FRONT] Refonte page cours — structure 3 onglets
`type:feat` `bloquant` — Dépend de : P1.2 (maquette, résout C5)
**CA** : bandeau blanc et menu supprimés ; 3 onglets Menu / Ressources / Chat conformes à la maquette ; contenus « À propos » et quiz rangés selon P1.2 ; le MVP fil d'Ariane est intégré (pas de fork) ; responsive vérifié.

### EA-030 · [FRONT] Ligne de support enrichie
`type:feat` — Dépend de : EA-027, EA-028, EA-029
**CA** : chaque ligne affiche type, durée, statut terminé ; clic sur la ligne lance le support (vidéo/podcast/réel) directement — plus besoin de passer par le player courant ; verrouillage séquentiel (`is_required`) conservé.

### EA-031 · [BACK] Statut « terminé » par support pour tous les types
`type:feat` — Dépend de : EA-027
État `development` : la complétion est déjà **automatique à 50 % de visionnage** pour vidéo/audio/YouTube/Vimeo (bouton « Terminer la leçon » supprimé) ; le PDF se complète au simple `onLoad` (trop laxiste).
**CA** : règle de complétion par type validée en P0.1 (médias : seuil % configurable — 50 % actuel comme défaut ; article/fiche : action explicite ou temps minimal, pas un simple chargement) ; endpoint unique de complétion ; l'état est visible dans la liste des supports.

### EA-032 · [FRONT] Onglet Chat de la page cours
`type:feat` — Dépend de : EA-029
**CA** : le fil de discussion du cours (DiscussionThread) vit dans l'onglet Chat ; les images mockées en dur sont retirées ; visible selon inscription (règle actuelle conservée).

### EA-033 · [FRONT] Mes cours — statuts, avancement, certificats
`type:feat` — Dépend de : EA-018
**CA** : chaque formation affiche statut (Non débutée/En cours/Terminée), % d'avancement (barre) pour les cours en cours, certificat obtenu + icône de téléchargement ; filtres par statut (généralisation du MVP) ; iso avec les statuts vus par le manager.

---

## Sprint 4 — CH3 Players, reprise, ressources, deeplinks

### EA-034 · [FRONT] Player unifié avec télémétrie
`type:feat` `bloquant` — Dépend de : P1.2
État `development` : Vimeo est piloté par l'API postMessage (événements timeupdate/ended captés), YouTube par polling, natif par `timeupdate` — mais la logique est éclatée dans `StudentCourseDetail.jsx` (2 343 l.) et dupliquée dans `AdminCourseDetail.jsx`.
**CA** : composant player unique par famille (Vimeo — postMessage ou Player SDK, YouTube, HTML5) émettant des événements normalisés play/pause/timeupdate/ended, extrait des pages monolithiques et partagé entre les 2 pages cours ; alimente le tracking (EA-011/012) ; plein écran conservé.

### EA-035 · [FRONT+BACK] Reprise à la seconde
`type:feat` — Dépend de : EA-012, EA-034
État `development` : une reprise **intra-session** existe (`lessonTimeMap` en state React) mais est perdue au rechargement et ne couvre pas Vimeo.
**CA** : la position est sauvegardée régulièrement (heartbeat) et à la pause/fermeture ; à la réouverture, lecture reprise à la position sauvegardée (vidéo, podcast, réel — Vimeo inclus) ; fonctionne après rechargement et changement d'appareil (stocké serveur, pas localStorage ni state).

### EA-036 · [BACK] Liaison documents ↔ support (transcripts et PDF)
`type:feat` `bloquant` — Dépend de : EA-027
**CA** : une ressource peut être rattachée à un support précis (pas seulement au cours) avec un type (`transcript`, `pdf`, `autre`) ; l'admin peut ajouter/remplacer la version PDF liée à chaque vidéo/audio ; l'API de la page cours renvoie les documents par support.

### EA-037 · [FRONT] Téléchargement par support
`type:feat` — Dépend de : EA-036, EA-005
**CA** : bouton de téléchargement sur chaque ligne de support ayant au moins un document ; **masqué sinon** ; passe par la route authentifiée (l'événement de téléchargement est donc journalisé) ; l'admin voit l'interface de liaison des PDF.

### EA-038 · [FRONT+BACK] Deeplinks de support avec minutage + résolution des slugs côté API
`type:feat` — Dépend de : P0.1 (Z7, Z18), EA-029
État `development` : les slugs existent (6 entités back, trait `HasSlug`, accents translittérés ; routes front `/courses/:slug`) **mais aucune route API ne résout un slug** — le front garde une table slug→id en localStorage. **Bug réel : un lien partagé/ouvert dans un autre navigateur ne résout pas.**
**CA** : résolution serveur du slug (endpoint acceptant slug OU id) — les liens partagés fonctionnent depuis n'importe quel navigateur ; toute ligne de support offre « copier le lien » ; format `/courses/{slug}?support={id}&t={secondes}` ; l'ouverture positionne le bon support au bon minutage, le deeplink survit à l'authentification ; anciens formats d'URL redirigés.

### EA-039 · [FRONT] Badge de leçon terminée → certificat
`type:feat` — Dépend de : P0.3 (Z8), EA-031
**CA** : conformément à la décision Z8 : badge visuel cliquable à chaque leçon terminée ; ouvre/télécharge le certificat selon la règle décidée (certificat de formation une fois éligible) ; états intermédiaires clairs (leçon finie mais formation en cours).

### EA-040 · [BACK] Complétion automatique harmonisée des médias
`type:feat` — Dépend de : EA-034, EA-031
**CA** : la fin de lecture (ou seuil) complète le support quel que soit le player ; suppression de la dépendance à `isVimeoVideo` ; la génération de certificat à 100 % reste automatique et unique (EA-015).

---

## Sprint 5 — CH4 Organisation : sociétés, hiérarchie, invitations

### EA-041 · [BACK] Référentiel sociétés + profil métier
`type:feat` `bloquant` — Dépend de : P0.3 (Z3, Z4… décisions), P0.2
Aucune table société ; profil éclaté en 7 tables par rôle sans champ métier.
**CA** : table `companies` (nom, statut) gérée dans Paramètres admin ; `users.company_id` ; champ `profil` (référentiel décidé en P0.2 : gestionnaire, etc.) ; exposés dans les payloads utilisateurs ; reprise de données des utilisateurs existants (import/affectation en masse).

### EA-042 · [BACK] Rattachement inversé au manager
`type:feat` `bloquant` — Dépend de : P0.2
Aujourd'hui : rattachement en masse depuis le manager (`whereIn(...)->update(parent_id)`).
**CA** : à la création/édition d'un utilisateur : sélection « rattaché au manager » parmi les managers existants ; un manager peut exister sans aucun rattaché ; l'ancien mécanisme retiré ou aligné ; `parent_id` reste la colonne support (pas de double vérité).

### EA-043 · [BACK] Rôles — Manager RH, rétrogradation de `manager`, seeds, unification des routes
`type:feat` `bloquant` — Dépend de : **décision F7** (actée 05/08)
`director`/`manager_general` non seedés ; pas de rôle RH ; 5 blocs de routes copiés-collés ; `manager` a aujourd'hui une portée globale.
**CA** : rôle `manager_rh` créé + seeds complets et **idempotents** (`firstOrCreate` — le seeder actuel plante sur une base déjà peuplée) ; **`manager` rétrogradé au niveau manager d'équipe** — même périmètre qu'un `sub_manager`, plus aucune portée globale (les droits globaux restent à `admin`), sans migration de comptes ; `manager_general` et `director` ont des **droits identiques** (distinction de libellé) ; **Manager RH** voit sa **hiérarchie directe et indirecte**, l'accès à l'ensemble des utilisateurs passant par son **onglet dédié** (EA-053) ; les blocs de routes dupliqués fusionnés en un groupe unique dont le périmètre est résolu par le rôle ; matrice F7 testée rôle par rôle.
**Prérequis d'investigation** : l'audit F20 doit d'abord établir **à quoi sert réellement `sub_manager` en production** (hypothèse : il recouvre les « manager » et « manager RH » actuels avec de simples masquages d'écrans) — le nettoyage en dépend.

### EA-044 · [BACK] Invitations refondues — 1 mail par utilisateur
`type:feat` — Dépend de : P0.3 (Z13), EA-003
Double boucle = 1 mail par (user×formation) ; `Mail::raw` sans template ; token jamais utilisé ; enrollment forcé `Approved` — et **l'invitation écrase silencieusement une inscription existante** (delete puis re-create) ; N+1 sur la liste des invités (`invitedGuests`).
**CA** : un envoi couvrant N formations produit **1 seul email** par utilisateur listant les N formations avec leurs liens ; template HTML FR ; token d'invitation réel avec expiration ; le statut d'inscription suit le workflow décidé (plus d'écrasement silencieux d'une inscription existante) ; `enrollments.assigned_by` + date renseignés (qui a affecté, quand).
**Invitation d'un utilisateur inconnu (décision F9)** : ouverte aux managers (`manager`, `manager_general`, `director`, `manager_rh`) et à l'admin. Elle **ne crée pas un compte** : elle crée un **compte inactif** qui ne devient réel qu'à l'**acceptation** (lien à expiration). C'est ce mécanisme qui concilie « seul l'admin crée des comptes » et « les managers peuvent inviter ». Plus aucun mot de passe généré ni transmis en clair.

### EA-045 · [BACK] Onboarding première connexion
`type:feat` — Dépend de : EA-044
Aujourd'hui : mot de passe aléatoire envoyé en clair.
**CA** : le nouvel utilisateur reçoit un mail d'onboarding avec lien sécurisé « définir mon mot de passe » (plus aucun mot de passe en clair par email) ; à la première connexion : parcours de complétion des données personnelles + définition du mot de passe ; testé pour un utilisateur créé par admin et un invité.

### EA-046 · [FRONT] Écran admin Utilisateurs refondu
`type:feat` `bloquant` — Dépend de : EA-019, EA-020, EA-041, EA-042
**CA** : DataTable avec recherche sur tous les champs (nom, prénom, email, rôle…), tris sur toutes les colonnes, filtres rôle/statut/manager de rattachement ; colonnes manager de rattachement (vide si aucun ; hover card : nom, prénom, rôle, société), société, profil ; création/édition avec sélection du manager ; pagination paramétrable.

### EA-047 · [FRONT+BACK] Vue « formations suivies » par utilisateur
`type:feat` — Dépend de : EA-016, EA-044 (assigned_by)
**CA** : depuis la fiche utilisateur : nombre de formations suivies + détail (formation, statut, % avancement, qui l'a affectée et quand) ; accessible à l'admin et aux rôles managériaux dans leur périmètre.

---

## Sprint 6 — CH4 Équipes, cockpit, dashboard

### EA-048 · [BACK] Hiérarchie récursive et règle de profondeur
`type:feat` `bloquant` — Dépend de : EA-042
**CA** : service de résolution de l'arbre hiérarchique (CTE récursive sur `parent_id`) : rattachés directs, rattachés indirects, profondeur ; l'API expose `has_indirect_reports` (règle « >1 niveau ⇒ onglet Mes équipes ») ; protégé contre les cycles ; performances validées sur 1 000+ utilisateurs.

### EA-049 · [FRONT+BACK] « Mes collaborateurs » (hiérarchie directe)
`type:feat` `bloquant` — Dépend de : EA-046 (DataTable), EA-016, EA-018
Remplace l'onglet « Utilisateurs » du pilotage.
**CA** : liste des rattachés directs uniquement ; colonnes : rôle, société, profil, icône mail (copie l'adresse / mailto — l'adresse n'est plus affichée en clair), nb formations suivies / en cours / non débutées / total, nb certificats + téléchargement, **badge de profil d'usage** (Jamais actif / One-shot / Occasionnel / Récurrent — seuils spec Lot 2.2) ; tris/filtres/export ; renommage « Utilisateurs » → « Mes collaborateurs ».

### EA-050 · [FRONT+BACK] Actions de masse sur les collaborateurs
`type:feat` — Dépend de : EA-049
**CA** : cases à cocher multi-sélection ; actions groupées : activer/désactiver (switch), édition des certificats (périmètre décidé en P1.4) ; confirmation avant action ; journalisation de qui a fait quoi.

### EA-051 · [FRONT+BACK] Cockpit apprenant × formation
`type:feat` `bloquant` — Dépend de : EA-016, P1.4
**CA** : ligne de collaborateur cliquable → page détail des formations (statut, %, certificat téléchargeable) ; chaque formation cliquable → cockpit : résultats aux quiz et évaluations, tentatives, durée de connexion, date de dernière connexion, nombre de connexions, durée moyenne, temps total, documents téléchargés ; **timeline d'activité individuelle** (vues, quiz, complétions, téléchargements — spec Lot 2.2) ; KPI conformes aux définitions figées (spec Lot 2.5) + revue P1.4 pour les indicateurs non couverts ; affiche honnêtement « données disponibles depuis [date de mise en service du tracking] ».

### EA-052 · [FRONT] « Mes équipes » (manager général / directeur)
`type:feat` — Dépend de : EA-048, EA-049
**CA** : onglet visible seulement si rattachés indirects (règle EA-048) ; ensemble de la hiérarchie directe+indirecte ; colonnes supplémentaires Manager de rattachement et Société ; mêmes fonctionnalités que Mes collaborateurs (cockpit inclus).

### EA-053 · [FRONT+BACK] « Tous les collaborateurs » (Manager RH)
`type:feat` — Dépend de : EA-043, EA-049
**CA** : rôle manager_rh opérationnel ; ses écrans courants portent sur sa **hiérarchie directe et indirecte** (décision F7) ; l'accès à l'ensemble des utilisateurs de la plateforme se fait **via cet onglet dédié**, avec les mêmes fonctionnalités (cockpit, export) ; périmètre d'export conforme à la matrice F11.

### EA-054 · [FRONT+BACK] Liste apprenants formateur enrichie
`type:feat` — Dépend de : EA-016, EA-051
**CA** : pour chaque apprenant×formation du formateur : nom de la formation, statut, date d'inscription, date de dernière connexion, certificat (téléchargement si obtenu) ; ligne cliquable → **même cockpit que les managers, avec le suivi détaillé** (temps, connexions, résultats — décision F7, qui prévaut sur la restriction initialement envisagée en F11), restreint aux apprenants de **ses** formations ; chat avec les apprenants de ses formations (renvoie vers EA-071).

### EA-055 · [FRONT+BACK] Dashboard de pilotage refondu
`type:feat` — Dépend de : P1.4, EA-016, EA-009, spec 05 (Lot 2.1)
**CA** : vue « Modules » conforme spec Lot 2.1 : tableau triable/filtrable par période — inscrits, démarrés, terminés, taux de complétion, vues de leçons, apprenants uniques actifs, temps moyen passé, téléchargements, score quiz moyen ; funnel inscrit→démarré→terminé ; maquette P1.4 pour la mise en forme ; remplace les endpoints bugués corrigés en EA-009 ; export avec filtres actifs.

### EA-085 · [FRONT+BACK] Cockpit — vue tutos différenciée et formations les plus consultées
`type:feat` — Dépend de : **décision F11** (actée 05/08), EA-016, EA-051, EA-084
**CA** : dans le cockpit, les tutos ont une **vue distincte des formations** — nombre de tutos visionnés, temps passé, **liste des tutos visionnés** — et **n'affichent ni statut de formation ni résultat de quiz** ; côté pilotage global, **analyse des formations les plus consultées tous utilisateurs confondus**, avec le **détail par leçon** ; exports associés.

### EA-082 · [FRONT+BACK] Vue « Documents » — pilotage des téléchargements
`type:feat` — Dépend de : EA-004, EA-016, spec 05 (Lot 2.3)
**CA** : vue admin/managériale des téléchargements par fichier et par apprenant, avec dates ; filtres période/module/périmètre ; export avec filtres actifs ; périmètre hiérarchique respecté ; alimentée par `resource_downloads` (ressources ET certificats).

### EA-056 · [FRONT] Navigation pilotage réduite
`type:feat` — Dépend de : P1.1, EA-049
**CA** : partie Pilotage limitée à **Dashboard / Invitation / Mes collaborateurs** (+ Mes équipes ou Tous les collaborateurs selon le rôle) — **pas d'écran « Rôle »** (décision F10 : l'écran n'a pas lieu d'être) ; onglets obsolètes retirés (`Historique`, `Mes favoris` déplacés côté apprentissage) ; bascule Pilotage/Apprentissage du MVP conservée.

---

## Sprint 7 — CH5 Studio admin : navigation, écran cours, création

### EA-057 · [FRONT] Coquille de navigation admin — 3 menus
`type:feat` `bloquant` — Dépend de : P1.1
`AdminUsers.jsx` (3 358 l.) concentre 9 onglets.
**CA** : sidebar admin avec 3 menus : Utilisateurs / Cours / Paramètres ; layout routes dédiées (`/admin/utilisateurs`, `/admin/cours`, `/admin/parametres`) ; les onglets actuels sont rangés dans ces 3 menus (Points, Parcours, Cat/Sous-cat/Balises → sous Cours ou Paramètres selon P1.1 ; Chat → cf. EA-071) ; le monolithe est découpé en pages par menu (aucune page > 800 l.).

### EA-058 · [FRONT] Écran Cours — menu latéral par type
`type:feat` `bloquant` — Dépend de : EA-057, P0.3 (Z17)
**CA** : partie gauche = menu Parcours / Cours / Tuto / Catégorie / Sous-catégorie / Balises ; chaque entrée affiche sa liste ; « Tuto » selon la définition Z17.

### EA-059 · [BACK] Brouillon / Publié réel sur les cours
`type:feat` `bloquant` — Dépend de : —
`status` binaire actif/inactif ; seul `learning_paths` a draft/published.
**CA** : statut `draft/published` (+ conservation de l'existant en migration) ; un cours en brouillon est invisible côté apprenant et non-inscriptible ; la publication est une action explicite ; API alignée.

### EA-060 · [FRONT] Liste des cours — switch publier, filtres, vignettes
`type:feat` — Dépend de : EA-058, EA-059, EA-019
**CA** : switch Brouillon/Publié avec confirmation « Êtes-vous sûr de vouloir publier ce cours ? » ; filtres catégorie/sous-catégorie/durée/balises ; vignettes de catégorie et sous-catégorie affichées sur chaque carte/ligne et cliquables → liste des cours de la même cat/sous-cat.

### EA-061 · [FRONT+BACK] Réorganisation par glisser-déposer direct
`type:feat` — Dépend de : EA-058
DnD actuellement confiné à des modales, 2 libs dont `react-beautiful-dnd` dépréciée.
**CA** : lib DnD unifiée (`@hello-pangea/dnd`) ; réorganisation directe dans les listes (sans modale) : formations au sein d'une cat/sous-cat, ordre des catégories et sous-catégories ; persistance immédiate + retour visuel ; anciennes modales retirées.

### EA-084 · [FRONT+BACK] Tutos et processus — modèle, catalogue et navigation
`type:feat` — Dépend de : **décision F6** (actée 05/08), EA-027, EA-058
**CA** : un **tuto = une vidéo courte** autonome (pas de certificat, pas de quiz obligatoire) ; un tuto est **rattachable à un ou plusieurs « processus »**, un processus affichant ses tutos **dans l'ordre de traitement** ; le processus **réutilise le mécanisme existant des parcours** (`learning_path_courses` : rattachement multiple + ordre déjà en base) plutôt que de créer une entité concurrente ; la section Tuto du catalogue adopte une **navigation de type YouTube** (vignettes, lecture enchaînée, tutos liés du même processus) ; migration des tutos existants (aujourd'hui des ensembles de vidéos) vers le nouveau modèle unitaire.

### EA-062 · [FRONT] « Ajouter » unifié
`type:feat` — Dépend de : EA-058
**CA** : « Créer une nouvelle formation » remplacé par « Ajouter » → choix Cours / Tuto / Parcours ; chaque choix ouvre le formulaire adéquat ; la chaîne legacy anglaise (`AdminCreateCourse`, `AddSection`) est supprimée.

### EA-063 · [FRONT] Studio de création de cours refondu
`type:feat` `bloquant` — Dépend de : P1.3, EA-027, EA-061
**CA** : structure en accordéons (sections/leçons repliables) ; tout déplaçable en DnD direct (sections et supports) ; bouton `+` pour ajouter une section ; par section : bouton Éditer, bouton Publier (confirmation), corbeille (confirmation) ; libellés (section, cours, leçon) éditables au clic ; ajout de support via icône `+` puis choix du type (vidéo, podcast, réel, article, fiche, quiz…) ; boutons « réorganiser » supprimés.

---

## Sprint 8 — CH5 Quiz avancé et analyse

### EA-064 · [BACK] Nouveaux types de questions — appariement, ordonnancement
`type:feat` — Dépend de : —
Types actuels : `mcq_single`, `mcq_multiple`.
**CA** : types `matching` (paires à apparier) et `ordering` (séquence à remettre en ordre) : modèle, correction automatique, scoring ; rendu apprenant et éditeur ; compatibles tentatives historisées et analyse d'items.

### EA-065 · [BACK] Politique de passage
`type:feat` `bloquant` — Dépend de : P0.3 (Z14), EA-013
`passing_percentage` n'est jamais évalué (re-confirmé sur `development` : la complétion du quiz ne lit ni score ni seuil, `EnrollmentController.php:459-471` ; `sections.required_score` = colonne morte). Acquis de `development` réutilisables : commentaires de réponse par option (`answer_comment` + `show_answer_comments`) = la brique « feedback » existe déjà.
**CA** : par quiz : nombre de tentatives max, délai entre essais, limite de temps, feedback immédiat ou en fin, mélange des questions et des options, seuil réellement appliqué (échec = pas de complétion). Défauts validés (F16) : seuil 70 %, tentatives illimitées, aucun délai, aucune limite de temps, feedback en fin de quiz, mélange activé — **à la condition expresse que chacun de ces réglages soit modifiable par l'admin, quiz par quiz**. **Acquis existants préservés**, aucune dé-certification rétroactive.
Note : l'application effective du seuil pour l'avenir est **déjà livrée** par la PR de sécurité #11 ; reste ici l'ensemble des réglages et leur interface d'administration.

### EA-066 · [BACK] Pondération par question
`type:feat` — Dépend de : EA-065
**CA** : poids par question (défaut 1) ; score = somme pondérée ; seuil appliqué sur le score pondéré ; visible dans l'éditeur et le résultat apprenant.

### EA-067 · [BACK+FRONT] Banque de questions partagée
`type:feat` `bloquant` — Dépend de : P1.3, EA-064
Chaque quiz est un silo (questions liées à un quiz).
**CA** : les questions vivent dans une banque taguée par thème ; un quiz référence des questions de la banque (les quiz existants migrés) ; tirage aléatoire de N parmi M à chaque tentative ; réutilisation d'une question dans plusieurs quiz ; gestion des tags.

### EA-068 · [FRONT] Éditeur de quiz refondu
`type:feat` — Dépend de : EA-063, EA-067
**CA** : accordéons ; glisser-déposer des questions et des réponses ; recherche/repli quand la liste dépasse 20 questions ; duplication de quiz ; édition des nouveaux types ; réglages de la politique de passage et de la pondération.

### EA-069 · [BACK] Import/export et journal des quiz
`type:feat` — Dépend de : EA-067
**CA** : import et export GIFT et CSV (banque et quiz) avec rapport d'erreurs ; journal des modifications (qui a changé quoi et quand : question, options, politique) consultable.

### EA-070 · [FRONT+BACK] Analyse des items et temps par support
`type:feat` — Dépend de : EA-013, EA-012, EA-016
**CA** : par question : % de réussite, indice de discrimination, répartition des choix sur les distracteurs (avec signal « distracteur mort » jamais choisi et « question > 95 % » non discriminante) ; par support : temps passé moyen/médian ; accessible admin + formateur sur son périmètre ; exportable ; calculé sur les tentatives historisées.

---

## Sprint 9 — CH6 Communication

### EA-071 · [FRONT+BACK] Chat refondu
`type:feat` `bloquant` — Dépend de : P1.5, EA-024
Chat existant : 1-à-1 + groupes, sans PJ, visio à retirer, admin dans un onglet du monolithe.
**CA** : deux onglets Chat / Groupes ; conversations non lues en ordre antéchronologique ; date et heure sur chaque message ; pièces jointes (types/taille bornés, stockage authentifié) ; membres d'un groupe visibles et supprimables ; côté admin : filtres rôle/entité + recherche d'utilisateur ; côté apprenant : à l'ouverture, choix « Parler à un admin » / « Demande de support » (routage selon Z9) ; notification à chaque message reçu (via EA-024) ; temps réel actif (`BROADCAST_CONNECTION` Pusher en prod) ; formateur ↔ apprenants de ses formations.

### EA-072 · [FRONT+BACK] Annonces générales
`type:feat` — Dépend de : EA-024
**CA** : l'admin (et rôles autorisés P0.2) compose une annonce vers un groupe d'utilisateurs sélectionnés (par rôle, société, formation ou sélection manuelle) ; l'annonce est épinglée en haut de la zone de chat des destinataires ; notification à l'envoi ; historique des annonces ; dépublication possible.

### EA-073 · [FRONT+BACK] Tickets
`type:feat` — Dépend de : P1.5, EA-024, décision Z9/Z15
**CA** : création par un manager uniquement ; numéro interne auto (format séquentiel) ; statuts (ouvert / en cours / résolu / clos) avec indicateur visuel vert/rouge ; **priorité à 2 niveaux** (normal / urgent) ; fil de discussion attaché au ticket ; **conversion d'une conversation de chat en ticket par l'admin** (décision F13) ; filtres et tris (statut, demandeur, date, priorité) ; notifications aux deux parties à chaque changement ; clôture avec motif.

---

## Sprint 10 — CH7 Intégration pipeline & évaluations avancées

> Règle d'architecture : le pipeline **génère** (grounding + jury obligatoires — tout nouveau
> type de support rejoint le registre `SUPPORT_GENERATORS`), le LMS **consomme et orchestre**.
> Les issues [PIPELINE] se créent dans `microlearning-video-v2-light` et touchent `scripts/`
> → **feu vert explicite requis** avant réalisation (règle no-engine-changes).

### EA-074 · [PIPELINE] Artefact transcript PDF par vidéo/audio
`type:feat` `bloquant` — Dépend de : P1.7
**CA** : pour chaque vidéo/audio produit, le pipeline génère un PDF de transcript (narration + horodatages issus de Whisper) versionné avec le module ; intégré au registre des supports (grounding/publish gate) ; livré dans le paquet du module.

### EA-075 · [BACK] Ingestion des transcripts
`type:feat` — Dépend de : EA-074, EA-036
**CA** : à l'import d'un module, les transcripts sont automatiquement rattachés à leurs supports (type `transcript`) ; téléchargeables via la route authentifiée ; le bouton n'apparaît que si le document existe (EA-037).

### EA-076 · [PIPELINE] Export des quiz au format d'import LMS
`type:feat` — Dépend de : P1.7
**CA** : les quiz générés par le pipeline sont exportés dans le format d'import de la banque (GIFT ou JSON du contrat v2), tagués par thème/notion ; passés au jury avant publication.

### EA-077 · [BACK] Import des quiz générés dans la banque
`type:feat` — Dépend de : EA-067, EA-069, EA-076
**CA** : import d'un lot de questions générées avec tags et rattachement au module ; marquées « générées » (traçabilité) ; utilisables en tirage aléatoire comme les questions manuelles.

### EA-078 · [PIPELINE] Support « mise en situation »
`type:feat` — Dépend de : P1.7
**CA** : nouveau type de support (mini-cas + questions rattachées) généré groundé sur le canon (chargeur `support_grounding`, jury via `publish_support`) ; ajouté au registre `SUPPORT_GENERATORS` (test de contrat vert) ; format de livraison défini au contrat v2.

### EA-079 · [FRONT+BACK] Rendu et édition de la mise en situation
`type:feat` — Dépend de : EA-078, EA-027, EA-064
**CA** : type de support `mise_en_situation` côté LMS : énoncé du cas + questions (types existants) ; rendu apprenant (lecture du cas puis questions) ; import depuis le pipeline + retouche possible dans le studio ; résultats intégrés au cockpit et à l'analyse d'items.

### EA-080 · [PIPELINE+BACK] Remédiation minutée (contrat v2)
`type:feat` — Dépend de : P1.7 (résout C2), EA-038, EA-013
**CA** : le contrat pipeline↔LMS v2 porte le mapping question → notion/objectif pédagogique → (support, timestamp) ; côté LMS, l'écran de résultats de quiz affiche pour chaque question ratée : « Revoir [support] à [minutage] » avec deeplink fonctionnel (EA-038) ; les notions référencées utilisent les ids stables du référentiel (pas un vocabulaire parallèle) ; données exposées pour le futur plan de rappel (courbe de désapprentissage — orchestration LMS).

### EA-081 · [BACK] Ingestion automatique des paquets de modules (manifeste / SCORM)
`type:feat` — Dépend de : P0.3 (Z4), P1.7
**CA** : selon la décision Z4 — a minima : import d'un paquet produit par le pipeline (manifeste JSON v2) créant automatiquement la structure formation/leçons/supports/ressources/quiz dans le studio (en brouillon) ; idempotent (ré-import = mise à jour, pas doublon) ; si l'option player SCORM générique est retenue, elle fait l'objet d'un chantier séparé chiffré à part (E2).

---

## Graphe des dépendances critiques (résumé)

```
P0.1 ──► EA-027 (supports typés) ──► EA-028/030/031/036/063/079
P0.2 ──► EA-003/008/041/042/043 ──► EA-046 ──► EA-049 ──► EA-050/051/052/053/054
spec 05 ──► EA-010/011/012/013 ──► EA-016 ──► EA-047/051/054/055/070/082
                      EA-012 ──► EA-035 (reprise)   EA-013 ──► EA-065/070
P1.9 ──► EA-019/020 ──► EA-021/022/023/046/049/060
P1.8 ──► EA-024 ──► EA-025/071/072/073
P1.1 ──► EA-056/057 ──► EA-058 ──► EA-060/061/062 ; P1.3 ──► EA-063 ──► EA-068
EA-059 ──► EA-060 ; EA-067 ──► EA-068/069/077
P1.7 ──► EA-074/076/078/080/081 (+ feu vert moteur pipeline)
EA-034 ──► EA-035/040 ; EA-036 ──► EA-037/075 ; EA-038 ──► EA-080
```

