mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-04-27 23:08:16 +02:00
capitalisation: intégration 28 entrées knowledge + 2 CLAUDE.md RL799_V2 (triage branche mcp_v1)
28 nouvelles sections intégrées dans 12 fichiers knowledge (backend risques/patterns, frontend risques/patterns, workflow risques). Couvre rate limiting, RGPD, CSP Next.js, refresh token TOCTOU, catch-all Prisma, distinction 401/403, tests E2E Playwright, etc. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -283,3 +283,50 @@ it('retourne 403 si subscription inactive', async () => {
|
||||
- **Signal review** : `email: user.email` dans le mapping d'un endpoint annuaire
|
||||
|
||||
- Contexte technique : auth / annuaire — RL799_V2 02-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-toctou-rotation-refresh-token"></a>
|
||||
## TOCTOU sur rotation de refresh token
|
||||
|
||||
### Risques
|
||||
|
||||
- Un pattern `findUnique` + `update` séparés sur la rotation de refresh token crée une fenêtre TOCTOU
|
||||
- Deux requêtes concurrentes avec le même refresh token passent toutes les deux la vérification avant que l'une ne révoque → deux sessions valides émises, le vol de token passe inaperçu
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Deux sessions actives issues du même refresh token
|
||||
- Détection de vol impossible car les deux tokens sont valides
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Toujours utiliser un `updateMany` atomique avec condition `WHERE revokedAt IS NULL AND expiresAt > NOW()` et vérifier `count === 1`
|
||||
- Si `count === 0`, le token a déjà été utilisé → révoquer **tous** les tokens du user (token family detection, RFC 6819)
|
||||
- **Signal review** : `findUnique` suivi de `update` séparés dans un flux de rotation de refresh token
|
||||
|
||||
- Contexte technique : auth / refresh token — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-drift-auth-copier-coller"></a>
|
||||
## Drift d'authentification par copier-coller de pattern auth
|
||||
|
||||
### Risques
|
||||
|
||||
- Quand un helper d'auth centralisé existe (`requireRoleAccess`), mais que de nouveaux services réimplémentent le même pattern manuellement (`extractAccessToken` + `verifyToken` + vérification locale), chaque service développe ses propres variantes (codes d'erreur différents, 401 vs 403, requestId ou non)
|
||||
- La surface d'auth devient incohérente et indéfendable en audit
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Un audit RBAC révèle qu'une part significative des routes ont un pattern d'auth "fait maison" au lieu du helper standard
|
||||
- Codes d'erreur divergents entre services pour la même situation (token absent)
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Tout nouveau handler HTTP DOIT utiliser le helper centralisé pour l'authentification et l'autorisation
|
||||
- Ne JAMAIS importer `extractAccessToken` + `verifyToken` directement dans un service métier
|
||||
- Si le helper ne couvre pas un besoin (ex: besoin de `userId` en plus de `email`), étendre le helper plutôt que contourner
|
||||
- **Signal review** : import de `verifyToken` dans un fichier service (hors `authHelpers.ts`)
|
||||
|
||||
- Contexte technique : auth / architecture — RL799_V2 08-04-2026
|
||||
|
||||
@@ -438,3 +438,313 @@ try {
|
||||
- Permet la surcharge en test et le rechargement dynamique
|
||||
|
||||
- Contexte technique : Node.js / tests — RL799_V2 07-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-rate-limiting-couverture-test"></a>
|
||||
## Rate limiting — couverture de test insuffisante
|
||||
|
||||
### Risques
|
||||
|
||||
- Tester uniquement l'objet `RateLimiter` en isolation (`.check()`, `.reset()`) donne une fausse confiance. Les bugs de câblage (limiter non appelé, mauvais limiter sur le mauvais endpoint, format de réponse 429 incorrect) passent au travers.
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Tests unitaires verts mais réponse 429 absente ou mal formatée en intégration
|
||||
- Header `retry-after` manquant dans la réponse HTTP
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Pour chaque rate limiter intégré dans un endpoint, ajouter au minimum :
|
||||
1. Un test d'intégration qui dépasse le seuil via le handler HTTP et vérifie status 429 + body + header `retry-after`
|
||||
2. Un test d'expiration de fenêtre (mock `Date.now` et avancer le temps)
|
||||
3. Vérifier que le logging sécurité est déclenché (au minimum visible dans la sortie test)
|
||||
|
||||
- Contexte technique : backend / rate limiting — RL799_V2 07-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-nommage-metriques-agregees-dto"></a>
|
||||
## Nommage des métriques agrégées dans les DTO
|
||||
|
||||
### Risques
|
||||
|
||||
- Nommer un champ `xxxCount` ou `xxxThisYear` sans que le nom reflète exactement ce qui est compté
|
||||
- Confusion en maintenance, bugs d'affichage, labels UI incohérents
|
||||
|
||||
### Symptômes
|
||||
|
||||
- `tenuesThisYear` qui compte en réalité les *présences* du membre, pas le nombre total de tenues
|
||||
- Labels frontend incohérents avec le comportement réel du champ
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Le nom du champ DTO doit refléter exactement l'entité comptée ET le scope du comptage
|
||||
- Préférer `presencesThisYear` à `tenuesThisYear` si on compte les attendances d'un user, réserver `tenuesThisYear` pour le COUNT de tenues elles-mêmes
|
||||
- **Signal review** : tout champ `xxxCount` ou `xxxThisYear` dont le nom ne correspond pas à la requête sous-jacente
|
||||
|
||||
- Contexte technique : backend / DTO — RL799_V2 07-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-gitignore-env-wildcard"></a>
|
||||
## `.gitignore` — `.env*` wildcard capture `.env.example`
|
||||
|
||||
### Risques
|
||||
|
||||
- Utiliser `.env*` dans `.gitignore` sans exception exclut aussi `.env.example`, qui est le fichier standard de documentation des variables d'environnement et qui DOIT être versionné
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Le fichier `.env.example` existe sur le disque mais n'apparaît pas dans `git status`
|
||||
- Les développeurs ne savent pas quelles variables configurer
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Toujours ajouter `!.env.example` après le wildcard `.env*` dans chaque `.gitignore` (racine ET sous-projets du monorepo)
|
||||
- Vérifier avec `git check-ignore <path>` que l'exception fonctionne
|
||||
- **Signal review** : `.env*` dans `.gitignore` sans `!.env.example`
|
||||
|
||||
- Contexte technique : git / configuration — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-strip-html-regex-single-pass"></a>
|
||||
## Strip HTML regex — single-pass insuffisant
|
||||
|
||||
### Risques
|
||||
|
||||
- `input.replace(/<[^>]*>/g, '')` en un seul passage laisse des fragments exploitables sur des inputs malformés type `<scr<script>ipt>alert(1)</script>`
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Après strip, le résultat contient encore des fragments `>` ou des reconstitutions partielles de tags
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Toujours (1) boucler le strip jusqu'à stabilisation (`while (prev !== result)`) ET (2) supprimer les chevrons orphelins `<>` après la boucle
|
||||
- Pour du plain text (pas de rich text), c'est suffisant. Pour du rich text, utiliser une lib dédiée (DOMPurify, sanitize-html)
|
||||
- **Signal review** : `replace(/<[^>]*>/g, '')` sans boucle dans un code qui traite de l'input utilisateur
|
||||
|
||||
- Contexte technique : sécurité / sanitisation — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-incoherence-source-verite-filtrage-affichage"></a>
|
||||
## Incohérence source de vérité — filtrage vs affichage sur des tables différentes
|
||||
|
||||
### Risques
|
||||
|
||||
- Filtrer des entités sur un champ d'une table relationnelle (`profile.grade`) tout en affichant le résultat depuis une autre table (`directory.grade`). Si les deux tables ne sont pas synchronisées en permanence, les résultats de filtrage et d'affichage divergent silencieusement.
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Un membre apparaît éligible mais avec un grade affiché incohérent, ou inversement un membre éligible est invisible parce que seule la table d'affichage a été mise à jour
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Toujours utiliser la même table comme source de vérité pour le filtrage ET l'affichage d'un même attribut
|
||||
- Si deux tables portent la même information, choisir celle qui fait autorité et aligner le code dessus
|
||||
- **Signal review** : `where` sur `tableA.field` avec `select` sur `tableB.field` pour le même attribut
|
||||
|
||||
- Contexte technique : Prisma / relations — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-check-then-create-p2002"></a>
|
||||
## Check-then-create non atomique — catcher P2002
|
||||
|
||||
### Risques
|
||||
|
||||
- Vérifier l'existence d'un enregistrement (`findFirst/findUnique`) puis créer dans un second appel est une race condition classique
|
||||
- Deux requêtes concurrentes passent le check, l'une échoue sur la contrainte unique
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Erreur 500 générique au lieu d'un conflit 409, intermittent et difficile à reproduire
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Toujours catcher l'erreur Prisma `P2002` (unique constraint violation) dans le bloc catch de la création et la transformer en réponse métier explicite (`USER_ALREADY_EXISTS`, `CONFLICT`, etc.)
|
||||
- Le check préalable reste utile pour le cas nominal mais ne doit pas être la seule protection
|
||||
- **Règle** : tout `prisma.create` sur une entité à contrainte unique doit avoir un catch `P2002`
|
||||
|
||||
- Contexte technique : Prisma / concurrence — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-double-update-non-transactionnel"></a>
|
||||
## Double update non transactionnel sur la même entité
|
||||
|
||||
### Risques
|
||||
|
||||
- Enchaîner deux `prisma.update` séparés sur la même entité (ex: update status puis update metadata) sans transaction laisse l'entité dans un état partiel si le second échoue
|
||||
|
||||
### Symptômes
|
||||
|
||||
- L'entité est dans un état qui ne correspond à aucune transition définie
|
||||
- Les flux aval (workflows, UI) se retrouvent bloqués
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Quand plusieurs champs d'une même entité doivent être modifiés ensemble pour représenter une transition d'état cohérente, les regrouper dans un seul appel `prisma.update` ou les envelopper dans une `$transaction`
|
||||
- **Signal review** : deux `prisma.update` séquentiels sur le même `where: { id }` sans `$transaction`
|
||||
|
||||
- Contexte technique : Prisma / atomicité — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-fallback-legacy-bypass-workflow"></a>
|
||||
## Fallback "legacy" qui bypass un nouveau workflow
|
||||
|
||||
### Risques
|
||||
|
||||
- Laisser un fallback de compatibilité dans une transition d'état (ex: accepter `'draft'` en plus de `'pending_vm_approval'` comme état source de la publication) crée un chemin de contournement du nouveau workflow
|
||||
- Un appel direct à la fonction interne bypass le contrôle métier
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Transition d'état possible depuis un état qui ne devrait plus être accepté
|
||||
- `{ in: ['ancien', 'nouveau'] }` dans un filtre Prisma sur une transition d'état
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Quand un nouveau workflow remplace un flux direct, retirer le fallback vers l'ancien état dans la transition atomique
|
||||
- Si la rétro-compatibilité est nécessaire, l'encapsuler dans un flag explicite ou une route dédiée, pas dans un `{ in: ['ancien', 'nouveau'] }` silencieux
|
||||
|
||||
- Contexte technique : workflow / transitions d'état — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-couverture-chemins-ecriture-securite"></a>
|
||||
## Couverture incomplète des chemins d'écriture lors d'ajout de sécurité transverse
|
||||
|
||||
### Risques
|
||||
|
||||
- Quand on ajoute une mesure de sécurité (chiffrement, sanitisation, validation, audit) sur un chemin d'écriture (ex: upload), les chemins alternatifs vers la même ressource (ex: create-from-text, import CSV, seed) sont oubliés, laissant une faille
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Un chemin d'écriture protégé, un autre non protégé, pour la même ressource
|
||||
- Données non chiffrées ou non sanitisées créées par un chemin secondaire
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Avant de marquer une tâche sécurité comme terminée, lister TOUS les chemins d'écriture vers la ressource ciblée (grep `createDocument`, `writeFile`, `prisma.model.create`) et vérifier que chacun est couvert
|
||||
- Documenter la liste dans les Dev Notes de la story
|
||||
|
||||
- Contexte technique : sécurité / transverse — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-anonymisation-rgpd-pieges"></a>
|
||||
## Anonymisation RGPD — pièges courants
|
||||
|
||||
### Risques
|
||||
|
||||
- **Données personnelles dans les audit logs** : stocker email ou nom dans les métadonnées d'un audit log d'anonymisation annule le droit à l'oubli (art. 17)
|
||||
- **Password en clair après anonymisation** : remplacer le password par une string comme `'ANONYMIZED'` est un signal exploitable en base
|
||||
- **Dernier admin anonymisable** : le système peut se retrouver sans administrateur
|
||||
- **Sessions non révoquées** : le JWT existant reste valide jusqu'à expiration
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Email en clair dans les métadonnées d'audit après anonymisation
|
||||
- Password `'ANONYMIZED'` visible en base au lieu d'un hash bcrypt structurellement invalide
|
||||
- Aucun admin actif restant après anonymisation
|
||||
- Utilisateur anonymisé qui peut encore accéder à l'application
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Utiliser un hash tronqué (ex: `sha256(email).slice(0,12)`) pour la corrélation dans les audit logs, pas l'email brut
|
||||
- Remplacer le password par un hash bcrypt structurellement invalide (ex: `$2b$10$INVALID...`)
|
||||
- Vérifier qu'au moins un admin actif reste après anonymisation
|
||||
- Révoquer tous les refresh tokens du user dans la même transaction
|
||||
|
||||
- Contexte technique : RGPD / sécurité — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-assertions-body-erreur-migration-codes"></a>
|
||||
## Assertions de body d'erreur non mises à jour après migration de codes
|
||||
|
||||
### Risques
|
||||
|
||||
- Lors d'une migration de codes d'erreur (ex: distinguer `UNAUTHORIZED` de `FORBIDDEN`), les assertions de status HTTP sont mises à jour mais pas les assertions sur le body JSON
|
||||
|
||||
### Symptômes
|
||||
|
||||
- `assert.equal(response.status, 401)` passe, mais `assert.equal(body.error.code, 'FORBIDDEN')` échoue — le code réel est `UNAUTHORIZED`
|
||||
- Détecté seulement quand on relance la suite complète
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Lors de toute modification d'un code d'erreur dans un helper centralisé, rechercher TOUTES les assertions qui testent l'ancien code (`grep -rn 'FORBIDDEN' __tests__/`) et les mettre à jour en cohérence
|
||||
- Ne pas se fier au fait que "les tests passent" sans les exécuter réellement
|
||||
|
||||
- Contexte technique : tests / migration de codes — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-audit-conditionnel-lookup-secondaire"></a>
|
||||
## Audit conditionnel sur un lookup DB secondaire
|
||||
|
||||
### Risques
|
||||
|
||||
- Le handler utilise `requireRoleAccess` qui ne retourne que `{ email, role }` mais pas `userId`. Pour logger l'audit, un second lookup (`getUserByEmail`) est nécessaire et peut échouer silencieusement
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Une action sensible (création, promotion, suppression) réussit mais aucun log d'audit n'est écrit
|
||||
- Le caller est pourtant authentifié
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Sur tout endpoint qui doit journaliser un audit, utiliser un helper qui retourne `{ userId, email, role }` directement depuis le JWT `sub` claim, plutôt qu'un helper + lookup DB
|
||||
- Le userId est déjà dans le token — pas besoin d'aller le chercher en base
|
||||
|
||||
- Contexte technique : audit / auth — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-derive-format-erreur-api"></a>
|
||||
## Dérive du format d'erreur API entre services
|
||||
|
||||
### Risques
|
||||
|
||||
- Chaque service recrée sa propre fonction `errorResponse` locale au lieu de réutiliser un helper centralisé
|
||||
- Le format standard `{ error: { code, message, requestId } }` n'est pas imposé par le typage
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Certaines routes API retournent `{ error: { code, message } }` sans `requestId`, d'autres incluent le `requestId`
|
||||
- Les erreurs sans requestId sont impossibles à tracer en production
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Tout nouveau service doit inclure `requestId: crypto.randomUUID()` dans ses réponses d'erreur
|
||||
- Factoriser un helper `createApiErrorResponse` partagé dans `lib/` pour éviter la divergence
|
||||
- **Signal review** : réponse d'erreur sans `requestId` dans un nouveau service
|
||||
|
||||
- Contexte technique : observabilité / API — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-unicite-applicative-sans-contrainte-db"></a>
|
||||
## Unicité applicative sans contrainte DB
|
||||
|
||||
### Risques
|
||||
|
||||
- Un contrôle d'unicité uniquement applicatif sur des affectations "actives" reste vulnérable aux races concurrentes et peut créer deux titulaires actifs sur un même rôle
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Deux enregistrements actifs pour un slot censé être unique (ex: deux titulaires pour un rôle d'officier)
|
||||
- Bug intermittent sous charge concurrente, invisible en dev
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Pour tout agrégat avec invariant "un seul actif" (ex: mandat d'officier par rôle), imposer une contrainte d'unicité au niveau base (index unique partiel ou stratégie équivalente) en plus des checks service
|
||||
- Les checks applicatifs seuls ne suffisent pas sous concurrence
|
||||
|
||||
- Contexte technique : Prisma / contraintes — RL799_V2 08-04-2026
|
||||
|
||||
@@ -120,3 +120,47 @@ return buildLocalizedPath(locale, "home");
|
||||
- **Règle** : `os.tmpdir()` est interdit pour les fichiers qui seront renommés vers un volume Docker bind-mounté.
|
||||
|
||||
- Contexte technique : Node.js / Docker / fichiers media — app-template-resto 31-03-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-csp-strict-routes-html-api"></a>
|
||||
## CSP strict casse les routes HTML dans une API Next.js
|
||||
|
||||
### Risques
|
||||
|
||||
- Appliquer un CSP strict (`default-src 'self'`) via `headers()` dans `next.config.ts` sur toutes les routes `/api/*` casse les routes qui servent du HTML avec des dépendances externes (Swagger UI, pages de documentation, etc.)
|
||||
|
||||
### Symptômes
|
||||
|
||||
- La page HTML se charge mais reste blanche — les scripts et styles externes sont bloqués silencieusement par le navigateur
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Quand on ajoute des headers de sécurité via un pattern global, vérifier s'il existe des routes qui servent du HTML (pas uniquement du JSON)
|
||||
- Si oui, ajouter une règle dédiée plus spécifique **en premier** dans le tableau `headers()` (Next.js matche dans l'ordre de déclaration) avec un CSP adapté
|
||||
- Factoriser les headers communs dans une constante partagée
|
||||
|
||||
- Contexte technique : Next.js / CSP — RL799_V2 08-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-middleware-faux-argument-edge"></a>
|
||||
## Middleware Next.js — faux argument "Edge Runtime incompatible" pour éviter les imports
|
||||
|
||||
### Risques
|
||||
|
||||
- Dupliquer la logique métier dans `middleware.ts` au lieu d'importer depuis `src/lib/` sous prétexte que "Edge Runtime ne supporte pas les imports cross-boundary"
|
||||
- C'est faux pour les modules purs (pas de `fs`, `child_process`, `crypto` Node-only, etc.)
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Logique dupliquée entre middleware et utilitaires, dérive garantie à la prochaine modification
|
||||
- Commentaire dans le code justifiant la duplication par une incompatibilité Edge non vérifiée
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Le middleware Next.js peut importer n'importe quel module local tant que celui-ci n'utilise que des API compatibles Edge (Web APIs, `process.env`, opérations JS pures)
|
||||
- Factoriser la logique partagée dans un module commun et l'importer depuis le middleware
|
||||
- **Signal review** : logique dupliquée dans `middleware.ts` avec un commentaire "Edge incompatible"
|
||||
|
||||
- Contexte technique : Next.js / middleware — RL799_V2 08-04-2026
|
||||
|
||||
@@ -384,3 +384,26 @@ Checklist minimale après `prisma migrate resolve --applied` :
|
||||
- **Signal review** : si le code suppose l'unicité, la base doit l'imposer explicitement
|
||||
|
||||
- Contexte technique : Prisma / contraintes DB — RL799_V2 06-04-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-catch-all-silencieux-repository"></a>
|
||||
## Catch-all silencieux dans les repositories Prisma
|
||||
|
||||
### Risques
|
||||
|
||||
- Un `try { prisma.update(...); return true } catch { return false }` dans un repository masque TOUTES les erreurs Prisma (connexion perdue, timeout, contrainte violée) derrière une réponse "not found"
|
||||
- Le service appelant ne peut pas distinguer un échec technique d'une absence de données
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Le service retourne 404 alors que la DB est down, ou 404 alors qu'une contrainte FK est violée
|
||||
- Le monitoring ne voit aucune erreur 500
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Dans les repositories Prisma, catcher uniquement `Prisma.PrismaClientKnownRequestError` avec le code spécifique attendu (`P2025` pour record not found, `P2002` pour unique constraint)
|
||||
- Re-throw toute autre erreur pour qu'elle remonte en 500 dans le handler
|
||||
- **Signal review** : `catch {` ou `catch (e) {` sans vérification de `e.code` dans un repository Prisma
|
||||
|
||||
- Contexte technique : Prisma / error handling — RL799_V2 08-04-2026
|
||||
|
||||
Reference in New Issue
Block a user