Des endpoints construits et jamais utilisés quand même
An endpoint queued an outbox event for a dispatcher that did not exist, so it returned 200 and no email was ever sent.
Construit, et rien ne s'en servait
Livré, typé, injecté, inatteignable. Rien ne l'a jamais appelé.
L'essentiel du tableau de bord d'admin est dans cet état : endpoints construits, typecheck propre, tests unitaires qui passent, injection de dépendances qui se résout contre du vrai Postgres et du vrai Redis, séparations 403/200 vérifiées en direct — et jamais pilotés depuis une interface.
Deux endroits où ce trou a des dents, tous deux signalés dans le registre plutôt qu'escamotés :
L'invitation de relecteur écrit une ligne ReviewerInvite et met en file un événement d'outbox email.reviewer_invite, et le dispatcher d'outbox n'est pas construit, donc l'e-mail ne part jamais. L'endpoint renvoie un succès et rien n'atteint un humain.
La révocation de consentement a une logique de nettoyage et un endpoint d'aperçu derrière une confirmation typée, et le job worker horaire qui l'exécute réellement n'existe pas. Donc une révocation peut être demandée et rien ne la traite.
Les deux ont la même forme : la moitié synchrone d'une fonctionnalité est faite, la moitié asynchrone qui la rend réelle ne l'est pas, et du point de vue de l'API tout a l'air correct.
Mise à jour 2026-08-30 : les deux sont réglés. control-plane/worker enregistre maintenant cinq vrais jobs — un dispatcher d'outbox (réclame avec FOR UPDATE SKIP LOCKED, rend le template, envoie via Resend/SMTP, marque sent/failed), un nettoyage horaire de révocation de consentement (vérifié en direct : annule les identifiants de soumission, bascule rights_status à revoked, écrit une ligne d'audit sans identifiant), un balayage horaire des téléversements en attente, un job d'expiration des claims et un recalcul nocturne des statistiques. Le trou restant du dispatcher est plus petit et d'une autre nature : il fonctionne correctement, mais aucun vrai transport (RESEND_API_KEY/SMTP_URL) n'est configuré en dev, donc rien n'a encore atteint une boîte de réception — une tâche de configuration de déploiement, pas un problème de code manquant. La leçon générale tient même si ces deux instances sont réglées : qu'une moitié synchrone d'une fonctionnalité ait l'air faite ne dit rien sur si sa moitié asynchrone existe, et l'API ne peut pas faire la différence non plus.