Aller au contenu

4 bugs de production — module Enfants et authentification

Contexte

Investigation du 2026-06-25 suite à un signalement : un enfant saisi pour la commune de Kandi disparaissait de la liste après fermeture/ réouverture de session. Le symptôme initial était transitoire (auto-résolu), mais l'investigation a révélé 4 bugs structurels réels, tous corrigés et déployés le jour même.

Contenu

Bug 1 — Audit connexion planté silencieusement

AuditLogRepositoryPrisma.creer() passait ressourceId comme champ scalaire direct, alors que dans le client Prisma compilé, ressourceId est une FK relationnelle vers RessourceAudit — le vrai champ scalaire est cibleId. Erreur PrismaClientValidationError loguée à chaque connexion, absorbée silencieusement par le try/catch non bloquant de l'étape audit — l'audit de connexion était donc perdu à chaque fois, sans jamais remonter d'erreur visible à l'utilisateur. Fix : cibleId: donnees.ressourceId au lieu de ressourceId: ....

Bug 2 — communeCode absent du profil après connexion

Chaîne de propagation cassée en 4 endroits différents entre le backend et le frontend : ConnexionHandler.formatSuccessResponse(), ConnexionUseCase.construireResultat() (3 branches : connexion directe, 2FA configuré, 2FA non configuré), l'interface IConnexionUseCase, et côté frontend l'entité User (constructeur, fromLoginResult(), toProfile()) — aucun de ces points ne transportait communeCode. Conséquence : tout composant frontend filtrant par commune de l'utilisateur travaillait avec undefined. Fix : ajout du champ à chaque maillon de la chaîne.

Bug 3 — Mode hors-ligne : liste des enfants vide

Deux erreurs dans EnfantsRepository.lister() (voir aussi ProjetESM/debug/tests-terrain-pwa-offline) : la fonction extraire lisait data.items alors que le backend retourne data.donnees.enfants (structure jamais trouvée → cache jamais alimenté) ; et la fonction construire renvoyait { items, total } au lieu de { donnees: { enfants, total, page, ... } } attendu par useEnfants. Fix : aligner les deux fonctions sur la structure réelle de la réponse backend, sans toucher au type TypeScript ListeEnfantsResult (qui reste en décalage documenté, géré ailleurs par un select de hook).

Bug 4 — Listing filtré par créateur au lieu de par commune (le plus grave)

EnfantRepositoryPrisma.lister() initialisait le WHERE avec { idUtilisateur } (le créateur de la fiche) au lieu d'un scope par commune. Conséquence concrète : un agent PSYCHOLOGUE de Kandi ne voyait que les enfants qu'il avait lui-même saisis, pas ceux saisis par ses collègues de la même commune — et même un ADMIN ne voyait que ses propres créations. Cause racine plus profonde : ListerEnfantsHandler ne transmettait pas le scope commune au use case, et EnfantsModuleController.createContext() (construit à la main) ne définissait pas getCommuneCode(), pourtant déclarée dans IHttpContext — contrairement à ExpressHttpContext qui l'implémentait déjà correctement ailleurs dans le projet.

Logique corrigée : agent terrain → getCommuneCode() retourne son code commune → WHERE communeCode = 'KANDI' ; admin/accès global → getCommuneCode() retourne null → aucun filtre, accès à tous les enfants. Validation : agent Kandi voit 2 enfants (sa commune), admin en voit 6 (toutes communes).

Décision / Conclusion

Bugs corrigés et déployés (backend ×3, frontend ×1 avec PWA v1.3.0). Le bug 4 est le plus significatif structurellement : un contrôleur qui construit son propre IHttpContext à la main (au lieu d'utiliser ExpressHttpContext standard) peut silencieusement omettre des méthodes de l'interface sans qu'aucune erreur de compilation ne le signale — le même risque existe potentiellement dans d'autres modules avec un createContext() maison.

À faire (points de vigilance identifiés)

  • Vérifier si d'autres contrôleurs ont un createContext() maison sans getCommuneCode()/getRole().
  • Nettoyer le type ListeEnfantsResult ({ items, total }) en décalage avec la vraie réponse backend ({ donnees: {...} }), actuellement masqué par des as any.
  • obtenirParId() filtre toujours par idUtilisateur (pas par commune) — même incohérence que le bug 4, pas encore corrigée pour cette méthode.

Liens connexes