mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-04-06 21:41:42 +02:00
- backend/risques/nestjs : guard multi-statut READ_METHODS avant statut - backend/patterns/nestjs : fusionner lastSeenAt dans la réconciliation - backend/risques/contracts : pas de process.env dans services/helpers - backend/risques/nextjs : self-request Server Action + EXDEV atomic write - backend/risques/prisma : champ enum-like stocké en String - frontend/risques/general : Alert.prompt iOS-only - frontend/risques/tests : 3 anti-patterns (helpers copiés, test indirect, test façade) - workflow/risques/story-tracking : 2 entrées (hors périmètre, File List approximative) - skill capitalisation-triage : nouveau format de rapport (tableaux par domaine) - 95_a_capitaliser.md : purgé
190 lines
7.3 KiB
Markdown
190 lines
7.3 KiB
Markdown
# Backend — Risques & vigilance : Contracts
|
|
|
|
> Extrait de la base de connaissance Lead_tech. Voir `knowledge/backend/risques/README.md` pour l'index complet.
|
|
|
|
---
|
|
|
|
<a id="risque-contrats-api-implicites"></a>
|
|
## Contrats API implicites (validation faible ou absente)
|
|
|
|
### Risques
|
|
|
|
- Entrées non validées → erreurs bizarres / vulnérabilités
|
|
- Changements qui cassent le front et les intégrations
|
|
|
|
### Symptômes
|
|
|
|
- 500 sur erreurs utilisateur
|
|
- Incohérences de format de réponse
|
|
- "Ça marche en staging, pas en prod" (données réelles)
|
|
|
|
### Bonnes pratiques / mitigations
|
|
|
|
- Schémas (OpenAPI/JSON Schema) + validation serveur
|
|
- Formats de réponse cohérents
|
|
- Versionner/éviter breaking changes
|
|
|
|
---
|
|
|
|
<a id="risque-erreurs-non-standardisees"></a>
|
|
## Erreurs non standardisées (4xx/5xx incohérents)
|
|
|
|
### Risques
|
|
|
|
- Front et automatisations impossibles à rendre robustes
|
|
- Debug long (pas de codes internes, pas de corrélation)
|
|
|
|
### Symptômes
|
|
|
|
- Clients qui "retry" sur des 4xx
|
|
- Messages techniques exposés aux utilisateurs
|
|
- Logs inexploitables
|
|
|
|
### Bonnes pratiques / mitigations
|
|
|
|
- Mapping HTTP standard + format d'erreur stable
|
|
- Codes internes d'erreurs applicatives
|
|
- requestId/traceId partout
|
|
|
|
---
|
|
|
|
<a id="risque-duplication-constantes-contracts"></a>
|
|
## Duplication silencieuse de constantes partagées (contracts) via fichier orphelin
|
|
|
|
### Risques
|
|
|
|
- Deux sources de vérité qui divergent silencieusement (ex : topics officiels, enums métier, slugs)
|
|
- Bug non détecté par TypeScript si la duplication est dans un fichier non importé (code mort)
|
|
|
|
### Symptômes
|
|
|
|
- Incohérences entre API et client sur des listes/enums "censées être partagées"
|
|
- "Ça marche chez moi" selon l'endroit où la constante est importée
|
|
- Un fichier de config existe dans `apps/*` mais n'est jamais importé/greffé au runtime
|
|
|
|
### Bonnes pratiques / mitigations
|
|
|
|
- Toute constante partagée vit dans `packages/contracts/src/` et est importée depuis là (jamais recopiée dans `apps/*`)
|
|
- En review : repérer les fichiers "config/constants" ajoutés dans `apps/*` sur des domaines déjà couverts par `contracts`
|
|
- (Optionnel) Outillage : intégrer une étape de détection de code mort / exports inutilisés au CI si ça devient récurrent
|
|
|
|
---
|
|
|
|
<a id="risque-contracts-schema-orphelin"></a>
|
|
## Contracts : schema orphelin / type de retour désynchronisé
|
|
|
|
### Risques
|
|
|
|
- Un `RequestSchema` défini dans `packages/contracts` mais jamais importé dans le controller ni le service mobile → dead code silencieux qui crée une fausse confiance
|
|
- Un type de retour inline (`string` brut) à la place du type contracts → désynchronisation silencieuse entre contrat et implémentation
|
|
|
|
### Symptômes
|
|
|
|
- `grep` du nom du schema ne trouve aucun `import` en dehors de sa définition
|
|
- Service retourne `Promise<{ status: string }>` au lieu de `Promise<CurationResponse>` — le `status` n'est pas validé comme `CurationStatus`
|
|
- Endpoints `POST /action` sans body ayant un schema `{ pathParam: string }` — le param vient du path, pas du body
|
|
|
|
### Bonnes pratiques / mitigations
|
|
|
|
À chaque story qui ajoute des schemas dans `packages/contracts`, vérifier en review :
|
|
|
|
1. Chaque `RequestSchema` est utilisé dans un `ZodValidationPipe` (API) ou importé dans le service mobile.
|
|
2. Les `ResponseSchema` correspondent au type de retour typé du service (`Promise<TheType>`, pas un type inline).
|
|
3. Les endpoints sans body (`POST /action`) définissent `z.object({})` ou omettent le body schema — ne jamais placer les path params dans le body schema.
|
|
|
|
```typescript
|
|
// ❌ Anti-pattern — type inline, status non typé
|
|
async showcaseThread(...): Promise<{ threadId: string; status: string }> { ... }
|
|
|
|
// ✅ Pattern correct — type contracts importé
|
|
import type { CurationResponse } from '@app-alexandrie/contracts';
|
|
async showcaseThread(...): Promise<CurationResponse> { ... }
|
|
```
|
|
|
|
- Contexte technique : NestJS / Zod / contracts-first — app-alexandrie 23-03-2026
|
|
|
|
---
|
|
|
|
<a id="risque-code-erreur-generique-409"></a>
|
|
## Code d'erreur générique sur statut HTTP sémantique (409 CONFLICT)
|
|
|
|
### Risques
|
|
|
|
- Utiliser `VALIDATION_ERROR` ou `INTERNAL_ERROR` sur un 409 rend les erreurs indistinguables côté client et monitoring
|
|
- Les clients (mobile, monitoring, tests) ne peuvent pas brancher une logique conditionnelle sans un code sémantique
|
|
|
|
### Symptômes
|
|
|
|
- Tous les conflits métier remontent le même code → impossible de distinguer "alias déjà résolu" de "handle déjà pris"
|
|
- Tests forcés à matcher le message texte au lieu du code → fragiles
|
|
|
|
### Bonnes pratiques / mitigations
|
|
|
|
Chaque scénario métier distinct doit avoir son propre code dans `error-code.ts` :
|
|
|
|
```typescript
|
|
// ❌ Anti-pattern — code générique sur 409
|
|
throw new ConflictException({ error: { code: 'VALIDATION_ERROR', message: '...' } });
|
|
|
|
// ✅ Correct — code sémantique spécifique
|
|
throw new ConflictException({ error: { code: 'ALIAS_ALREADY_RESOLVED', message: '...' } });
|
|
throw new ConflictException({ error: { code: 'HANDLE_ALREADY_TAKEN', message: '...' } });
|
|
```
|
|
|
|
- **Règle** : 1 scénario métier distinct = 1 code d'erreur distinct
|
|
- **Checklist review** : tout 409/422 doit avoir un code dans `error-code.ts`, jamais `VALIDATION_ERROR` ou `INTERNAL_ERROR`
|
|
|
|
- Contexte technique : NestJS / error-code.ts — app-alexandrie 24-03-2026
|
|
|
|
---
|
|
|
|
<a id="risque-forbidden-pour-validation"></a>
|
|
## `ForbiddenException` (403) utilisé pour des erreurs de validation
|
|
|
|
### Risques
|
|
|
|
- Les clients qui filtrent par HTTP 400 manquent les erreurs de validation lancées en 403
|
|
- Sémantique API incorrecte → comportements clients imprévisibles
|
|
|
|
### Symptômes
|
|
|
|
- `ForbiddenException` lancée pour des tags invalides, des formats incorrects, des liens HTTP
|
|
- Clients API qui ignorent ces erreurs ou les traitent comme des refus d'accès
|
|
|
|
### Bonnes pratiques / mitigations
|
|
|
|
Tableau de correspondance :
|
|
|
|
| Cas | Exception correcte | Code HTTP |
|
|
|---|---|---|
|
|
| Tags invalides, contenu trop long, format incorrect | `BadRequestException` | 400 |
|
|
| Accès refusé explicitement (accès forum, trial read-only) | `ForbiddenException` | 403 |
|
|
| Quota dépassé | `HttpException(429)` via `HttpStatus.TOO_MANY_REQUESTS` | 429 |
|
|
|
|
- **Règle** : HTTP 403 = "tu n'as pas le droit d'effectuer cette action". HTTP 400 = "ta requête est mal formée".
|
|
- Contexte technique : NestJS / HTTP — 20-03-2026
|
|
|
|
---
|
|
|
|
<a id="risque-process-env-direct-service"></a>
|
|
## Feature flags / config : lecture directe de `process.env` dans les services ou helpers métier
|
|
|
|
### Risques
|
|
|
|
- Tests verts malgré une dépendance implicite à l'état global du process
|
|
- La validation Zod de l'env (ConfigService) existe mais est contournée au runtime via un helper non injecté
|
|
- Story conforme "pas de process.env direct en service métier" mais violation dans un helper utilisé par le service
|
|
|
|
### Symptômes
|
|
|
|
- `process.env.FEATURE_FLAG_X` dans un helper métier plutôt que dans un module ConfigService
|
|
- Tests passent mais comportement diverge selon l'env du process
|
|
|
|
### Bonnes pratiques / mitigations
|
|
|
|
- Ne jamais lire `process.env` directement dans les services ni les helpers métier.
|
|
- Injecter `ConfigService` (NestJS) et centraliser la lecture via une fonction pure recevant la config injectée.
|
|
- **Checklist review** : rechercher `process.env` dans `src/` hors `config/` ou `main.ts` — tout hit est suspect.
|
|
|
|
- Contexte technique : NestJS / ConfigService — 30-03-2026
|