# État avant mise en production — 22 août 2026

Point de départ écrit par le pilote pour la conversation de **réorganisation du
passage en prod**. Il ne remplace pas les issues : il dit **où on en est** et
**ce qui reste vrai**, pour qu'une nouvelle conversation n'ait pas à
reconstituer trois semaines.

⚠️ Ce document est daté. Vérifier au code avant de s'appuyer dessus — c'est
précisément la règle que la session du 22/08 a apprise à ses dépens.

⚠️ **Et il périme vite.** Deux incohérences y ont été trouvées par une
conversation voisine quelques heures après sa publication — §1 et §3 se
contredisaient sur le nombre de blocants restants, parce que §1 avait été mis à
jour et pas §3. **Quand une section change, relire les autres.** Un document
d'état qui se contredit est pire qu'un document absent : on croit le lire.

## 1. Ce qui bloque réellement la production

Sept issues portaient l'étiquette « bloquant ». **Vérification au code du
22/08 : trois seulement l'étaient encore.**

| | état au 22/08 |
|---|---|
| **#445** suppression de cours détruit l'historique | ✅ **corrigé et mergé** (PR #611) — refus 409, 24 inscriptions préservées, contre-épreuve 12/14 |
| **#412** points au refus + e-mails parasites | ✅ **corrigé et mergé** (PR #612) — ⚠️ l'énoncé était **faux** sur son point principal : un garde-fou en aval empêchait déjà le crédit |
| **#389** journal d'audit — la capture | ✅ **livré et mergé** (PR #615, 38 tests) — 260 apprenants × 10 formations = **1 entrée**, pas 2 600 |
| #393 Sentry serveur · FRONT#143 Sentry écran | ✅ **livrés le 16/08**, issues restées ouvertes à tort |
| #391 · FRONT#140 masquage chat/annonces/tickets | ✅ **fait** — routes derrière une garde qui refuse par défaut ; annonces et tickets **n'existent nulle part** |

**Les trois blocants applicatifs sont réglés au 22/08.** Ce qui reste avant
production ne relève plus du développement applicatif : voir §2 (bascule) et
§1bis (ce que le journal d'audit a mis au jour en chemin).

## 1bis. Deux failles trouvées PAR HASARD le 22/08 — nouvelles entrées

Le fil du journal d'audit devait recenser les chemins de création de comptes.
**C'est en faisant ce recensement qu'il a trouvé les deux failles ci-dessous.**
⚠️ Ce qui doit inquiéter n'est pas leur gravité, c'est **la façon dont on les a
trouvées** : personne ne les cherchait.

### #617 — des routes sans garde de rôle
`POST /invite`, `POST /invite-mail` (qui **créent des comptes**), et les routes
de `categories` et `tag` (**y compris DELETE**) n'ont **aucun contrôle de
rôle**. Vérifié au `route:list` par le pilote.

**Nuance** : elles exigent `Authenticate:sanctum` — donc pas ouvertes à
l'internet. Mais **n'importe quel compte suffit, y compris un apprenant**.
⚠️ Dans ce produit, « il faut être connecté » ne protège de rien : les comptes
apprenants sont nombreux, créés en masse, et les moins surveillés.

**Même famille que la faille d'escalade fermée par la PR #11.** L'inventaire
systématique des routes sans garde de rôle, sur les 346 routes réelles,
**n'a jamais été fait**.

### #618 — fichiers nominatifs sur le disque public
`MyLearnerController:156` écrit l'export « Mes apprenants » sur le disque
`public`. Le même disque porte **46 certificats PDF nominatifs**
(`EnrollmentController:787`), dont le nom est **devinable** :
`certificate_<idApprenant>_<idCours>.pdf`.

⚠️ **Mesuré par le pilote : sur staging, rien n'est servi** — 404 sur trois
chemins et deux types de fichiers. **Mais la protection vient de la
configuration du serveur, pas du code** : elle n'est écrite nulle part,
personne ne l'a décidée, rien ne la teste. Le lien `public/storage` a été créé
délibérément en novembre 2025.

**La première question, avant tout développement : le disque public est-il
servi en PRODUCTION ?** Le pilote n'a pas le mandat d'y répondre. Un export est
un instantané ; **un certificat est une preuve QUALIOPI permanente et
énumérable** — c'est lui le vrai sujet.

### #619 — le serveur ne signale rien
**Aucun environnement ne porte de DSN Sentry.** Le code est livré depuis le
16/08 ; la configuration n'a jamais été posée. **Le serveur est muet**, et
personne ne l'a vu pendant six jours parce que l'écran, lui, remonte bien.

⚠️ Ce constat est resté **écrit dans aucune issue** jusqu'au 22/08 au soir —
relevé par une conversation voisine appliquant la règle « une chose écrite
nulle part n'existe pas ». **Le pilote y était pris en défaut sur sa propre
règle.** Il a maintenant son issue : **#619**.

⚠️ `SENTRY_ENVIRONMENT` commande l'envoi lui-même : poser le DSN seul ne suffit
pas. Et le DSN ne se devine pas — **c'est le seul point qui demande une action
humaine.**

## 2. Les blocants de bascule, hors périmètre applicatif

| | |
|---|---|
| **#136** base de production en **MyISAM** | Les clés étrangères n'existent pas. ⚠️ **À la conversion InnoDB, des cascades écrites il y a longtemps s'ACTIVERONT toutes seules** — dont celle qui efface les inscriptions avec un cours. Compter les orphelins AVANT : une clé étrangère refuse de se créer s'il en existe, et la migration échoue au milieu. |
| **#137** rattrapage de migrations | |
| **reprise infra OVH** | Récupérer les accès serveur, sortir l'équipe dev externe. Premier risque du planning V1. |

## 3. Le tri des jalons L4.7 / L4.8 (42 issues ouvertes)

Proposition du pilote, **non encore arbitrée** :

- **7 issues** étaient classées bloquantes. ⚠️ **Au 22/08 au soir, il n'en reste
  AUCUNE au sens applicatif** : trois ont été corrigées et mergées le jour même
  (#445, #412, #389), quatre étaient déjà livrées depuis le 16/08 sous une
  issue restée ouverte à tort (#393, FRONT#143, #391, FRONT#140). **Voir §1
  pour le détail ligne par ligne.**
  Ce qui bloque encore ne relève **pas du développement applicatif** : le geste
  de configuration **#619** (§1), les deux failles **#617/#618** (§1bis), et
  les blocants de bascule du **§2**.
- **14 issues** = finition pendant L5, dont **10 déjà développées** (3 PR
  ouvertes, 5 en recette, 2 en dev)
- **21 issues** = après la production : relances automatiques, cockpit
  apprenant (4), actions groupées (6), export du tableau de bord, fonctions
  d'invitation suspendues faute de route

⚠️ **Un compte de jalon ne dit pas ce qui est développé.** « 27 issues
ouvertes » recouvrait 5 chantiers déjà livrés, 3 PR à fusionner et 2 en cours.
**Aller au code avant d'annoncer un chiffre.**

## 4. Dette de dispositif — ce qui a fait perdre du temps

| constat | portée |
|---|---|
| **Le contrat d'interface servi datait du 8 août** | Un écran s'est réglé sur un contrat faux → FRONT#336. Refermé par une porte de CI (#603/#604). |
| **8 PR bloquées pour toujours** (#608) | Ouvertes avant la CI, elles ne porteront jamais le contrôle requis. Dont la procédure de déploiement (#426) qui décrivait **exactement** la panne du 22/08. **Une chose écrite mais non fusionnée ne protège personne.** |
| **Un déploiement peut laisser l'arbre à moitié appliqué** (#607) | Et un arbre à moitié appliqué **démarre**. |
| **Couverture du contrat** (#609) | 346 routes réelles, 209 documentées. Les 14 « fantômes » sont **9 annotations mal posées**, pas des routes mortes. Les 151 non documentées : **57 sont nos écrans d'août**, 90 le socle de janvier. |

## 5. Arbitrages produits rendus le 21-22/08, à ne pas réinstruire

- **Libération progressive** (#562) : option de la formation, **pas** propriété
  du type. Chaque élément contenu porte son échéance — date fixe ou délai
  relatif au début du cours. ⚠️ **« Le début du cours » n'est pas défini** pour
  un apprenant inscrit après le démarrage : à trancher avant tout code.
- **Aperçu** (#592) : rien d'enregistré, et la distinction aperçu/inscrit
  portée **dans la donnée**. C'est un **écart**, pas une évolution.
- **Tarif** (#594) : champ payant/gratuit, HT **et** TTC, taxes en phase 2.
  Sujet **SaaS**, aucune formation payante aujourd'hui.
- **YouTube** : refusé à la saisie avant L5 (#589/#590/FRONT#339).
- **Managers créateurs de formations** (#610) : **post-L5**.

## 6. Ce qui attend une décision humaine

1. **La nature de la clé Stripe en production** (#600) — procédure dans
   l'issue. ⚠️ La route de paiement **n'est atteignable depuis aucun écran**,
   mais elle répond.
2. **Les points d'inscription ne se gagnent qu'une fois dans une vie** (#614),
   tous cours confondus. Voulu ou non ?
3. **Le tri L4.7/L4.8** ci-dessus, groupe par groupe.
4. **Le disque public est-il servi en production ?** (#618) — une requête suffit
   à répondre, et elle décide de l'urgence de tout le volet fichiers nominatifs.
5. **Le DSN du projet Sentry serveur** (#619) — la valeur ne se devine pas, et
   sans elle aucune erreur applicative ne remonte, ni en recette ni en prod.
