Aller au contenu

Leçons — câblage de @kanmaber/auth-backend dans jobPipeline

Date : 2026-07-03

Ce document capitalise sur ce qui a été appris pendant le câblage réel du package @kanmaber/auth-backend (voir 20260703_1434_procedure-cablage-auth-package.md pour la procédure détaillée). Deux problèmes réels ont été trouvés et corrigés — les leçons ci-dessous sont génériques, valables au-delà de ce package, pour tout package partagé sous Shared/packages/.


Leçon 1 — Une valeur hardcodée utilisée comme clé étrangère est une bombe à retardement silencieuse

Ce qui s'est passé : InscrireUtilisateurUseCase (dans le package) hardcodait idRole: 'role_observateur', valeur utilisée directement comme profilId (FK) par le repository Prisma — sans lookup, sans validation, sans documentation nulle part (ni README, ni script de seed livré, ni commentaire). Résultat : la première inscription réelle a crashé avec une violation de contrainte FK Prisma brute, un message technique opaque sans rapport avec la cause réelle.

Pourquoi c'est dangereux : ça a passé le typecheck (c'est une string valide), ça a passé les smoke tests (qui ne font qu'assembler des objets DI, jamais une vraie requête DB), et ça n'a été détecté qu'au premier test curl réel de bout en bout — après tout le reste du câblage.

Correction appliquée : remplacer le hardcode par une résolution dynamique via une clé métier stable et unique (ProfilUtilisateur.code), avec une erreur métier explicite (PROFIL_PAR_DEFAUT_INTROUVABLE) si le seed est absent — au lieu de laisser remonter l'erreur Prisma brute.

Règle à retenir : dans un package partagé, toute valeur qui référence une donnée censée exister côté consommateur (seed, config par défaut, rôle par défaut...) doit être : 1. résolue dynamiquement par une clé métier lisible (code), jamais un id technique arbitraire (cuid, uuid) hardcodé ; 2. accompagnée d'une erreur claire si la ressource est absente, pas d'un crash technique opaque ; 3. documentée (README ou script de seed livré avec le package) si le consommateur doit préparer des données en amont.


Leçon 2 — npm install sur une dépendance file:...tgz peut silencieusement garder l'ancien code

Ce qui s'est passé : après avoir corrigé le package, reconstruit (npm run build) et regénéré le tarball (npm pack), un rm -rf node_modules/@kanmaber/auth-backend && npm install dans jobPipeline a bien réécrit le fichier (nouveau timestamp), mais avec l'ancien contenu. Aucune erreur, aucun avertissement.

Cause : package-lock.json retient un hash d'intégrité (integrity) calculé lors de la première installation. Tant que le chemin et le numéro de version de la dépendance file: restent identiques, npm fait confiance à son cache local (~/.npm/_cacache) au lieu de relire réellement les octets du .tgz sur le disque — même si ce fichier a physiquement changé entre-temps.

Solutions envisagées : - Extraction manuelle du .tgz dans node_modules (tar -xzf ... --strip-components=1) — fonctionne, mais manuel et facile à oublier à chaque itération future. - Pointer la dépendance vers le dossier source plutôt que le .tgz** (file:../../Shared/packages/auth-backend) — **rejeté** : npm crée alors un symlink, et Node résout les imports internes du package (ex.@prisma/client) via lenode_modules**du dossier du package**, pas celui de jobPipeline. Or cenode_modulescontient un client Prisma généré depuis le schéma *fragment* du package, différent du schéma *fusionné* réel de jobPipeline (champstelephone/titreabsents,updatedAtsans@updatedAt) — un bug de désynchronisation silencieux et bien pire que le problème de cache initial. - **Solution retenue : bumper la version du package à chaque modification** (1.0.01.0.1, etc.) avantnpm pack, et mettre à jour la référencefile:...tgzcôté consommateur en conséquence. Un nouveau numéro de version force npm à traiter le contenu comme neuf, sans passer par le cache. Vérifié : après bump,npm install` seul (sans extraction manuelle) a correctement repris le nouveau code.

Règle à retenir : pour un package interne distribué en .tgz local (file: + tarball, pas un vrai registre npm) : - toujours bumper la version avant npm pack, même en dev interne — ne jamais republier un .tgz avec le même numéro de version ; supprimer l'ancien .tgz pour éviter toute ambiguïté ; - ne pas pointer vers le dossier source tant que le package a son propre node_modules avec des dépendances qui pourraient diverger de celles du consommateur (notamment @prisma/client, généré depuis un schéma) ; - après tout rebuild d'un package file:, vérifier explicitement (grep sur une chaîne caractéristique du changement) que le contenu installé dans node_modules du consommateur correspond bien à la nouvelle version — ne jamais supposer que npm install a fonctionné.


Leçon 3 (rappel) — le typecheck et les smoke tests ne prouvent pas qu'une fonctionnalité marche

Les deux bugs ci-dessus (Leçon 1 et l'absence de champs Zod requis confirmationMotDePasse/accepteCGU dans le payload d'inscription) sont passés inaperçus jusqu'au premier vrai test curl de bout en bout. Ni tsc --noEmit, ni le script smoke-test-auth-package.mjs (qui ne fait qu'instancier les objets DI) ne les auraient révélés. Confirme la pratique déjà en vigueur : tester le comportement réel (requête HTTP bout en bout) avant de considérer un câblage terminé, pas seulement la compilation.


Checklist à réutiliser pour tout futur package Shared/packages/*

  • [ ] Toute valeur de référence hardcodée (rôle par défaut, config...) est résolue dynamiquement par une clé métier, pas un id technique fixe.
  • [ ] Le package documente (README ou script de seed) toute donnée qu'il suppose exister côté consommateur.
  • [ ] Le numéro de version est bumpé à chaque modification avant npm pack.
  • [ ] L'ancien .tgz est supprimé après un bump, pour éviter toute confusion.
  • [ ] Après npm install d'un package file:...tgz mis à jour, on vérifie par grep que le contenu installé correspond bien à la nouvelle version.
  • [ ] Un test end-to-end réel (curl/navigateur) valide le câblage — pas seulement le typecheck ou un smoke test d'assemblage DI.