mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-04-06 21:41:42 +02:00
feat: capitalise Epic 2 app-alexandrie + enrichit post-bmad-install
- Intègre 9 propositions de 95_a_capitaliser.md (Stripe, webhooks, Redis, entitlements, guards, catch silencieux, conventions File List) - Ajoute core-bmad-master dans les agents patchés (orchestrateur) - Différencie les fichiers cibles par rôle d'agent (dev/architect/qa…) - Patch dev-story et code-review XML pour déclencher la capitalisation à chaque fin de story et après chaque code review Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,11 @@ Dernière mise à jour : 09-03-2026
|
||||
- [Stripe : `billing_cycle_anchor` vs `current_period_end`](#risque-stripe-current-period-end)
|
||||
- [PostgreSQL/Prisma : `@unique` nullable](#risque-prisma-unique-nullable)
|
||||
- [Observabilité insuffisante](#risque-observabilite-insuffisante)
|
||||
- [Webhooks entrants — répondre 200 pendant `processing` (event perdu)](#risque-webhook-200-processing)
|
||||
- [Redis — thrash de connexion sous charge](#risque-redis-thrash-connexion)
|
||||
- [Entitlements — TTL cache supérieur au SLA de propagation](#risque-entitlements-ttl-sla)
|
||||
- [Guard NestJS route-level — null-check manquant sur `request.user`](#risque-guard-request-user-null)
|
||||
- [Compteurs in-memory ≠ métriques persistées](#risque-compteurs-inmemory)
|
||||
|
||||
---
|
||||
|
||||
@@ -254,3 +259,122 @@ Dernière mise à jour : 09-03-2026
|
||||
- Logs structurés + requestId/traceId
|
||||
- Métriques de base (latence, erreurs, throughput)
|
||||
- Alertes simples sur 5xx/latence
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-webhook-200-processing"></a>
|
||||
## Webhooks entrants — répondre 200 pendant `processing` (event perdu)
|
||||
|
||||
### Risques
|
||||
|
||||
- Le provider (Stripe, etc.) arrête ses retries après un 2xx, même si le premier worker a échoué
|
||||
- Event non appliqué mais marqué "traité" → état incohérent silencieux
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Webhook reçu, 200 retourné, mais l'état en base n'est pas mis à jour
|
||||
- Aucun retry du provider → impossible à détecter sans monitoring actif
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- Lock DB (`WebhookEvent`) avec machine d'état : `pending` → `processing` → `processed` / `failed`
|
||||
- Si `processing` détecté (concurrent) : attendre brièvement la transition `processed`, sinon répondre **non-2xx** (force retry provider)
|
||||
- Ne jamais passer à `processed` sans preuve d'un traitement effectif
|
||||
- Contexte technique : Stripe / NestJS — 09-03-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-redis-thrash-connexion"></a>
|
||||
## Redis — thrash de connexion sous charge
|
||||
|
||||
### Risques
|
||||
|
||||
- Connexions concurrentes multiples si `connect()` est appelé "à la demande" sans lock
|
||||
- Spam logs + saturation connexions quand Redis est down ou lent
|
||||
|
||||
### Symptômes
|
||||
|
||||
- N appels simultanés → N tentatives de connexion en parallèle
|
||||
- Logs "Redis connection failed" en rafale au démarrage ou lors d'un restart Redis
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
```typescript
|
||||
// Pattern single-flight + cooldown + fallback DB best-effort
|
||||
if (!this.connectPromise) {
|
||||
this.connectPromise = this.client.connect().finally(() => { this.connectPromise = null; });
|
||||
}
|
||||
await this.connectPromise;
|
||||
// Si échec → nextConnectRetryAtMs = now + 1000 → return false → fallback DB
|
||||
```
|
||||
|
||||
- Contexte technique : Redis / NestJS — 09-03-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-entitlements-ttl-sla"></a>
|
||||
## Entitlements — TTL cache supérieur au SLA de propagation
|
||||
|
||||
### Risques
|
||||
|
||||
- TTL cache > SLA propagation → un webhook raté viole mécaniquement le SLA (accès stale plus long que garanti)
|
||||
- Utilisateur avec accès périmé ou sans accès dû, pendant toute la durée du TTL résiduel
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Accès premium encore actif après annulation (ou inversement)
|
||||
- NFR "propagation ≤ 60s" non respecté en cas de webhook manqué
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- TTL cache ≤ SLA cible (ex : NFR "≤ 60s" → TTL = 60s max)
|
||||
- Toujours coupler TTL + invalidation explicite via webhook (les deux, pas l'un ou l'autre)
|
||||
- Contexte technique : Redis / entitlements / NestJS — 09-03-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-guard-request-user-null"></a>
|
||||
## Guard NestJS route-level — null-check manquant sur `request.user`
|
||||
|
||||
### Risques
|
||||
|
||||
- Un guard route-level qui lit `request.user.userId` sans null-check lève une `TypeError` (500) si `request.user` est absent
|
||||
- Mauvaise registration de module, test d'intégration mal configuré, ou middleware custom peuvent produire cet état
|
||||
|
||||
### Symptômes
|
||||
|
||||
- `TypeError: Cannot read properties of undefined (reading 'userId')` en prod
|
||||
- Tests "verts" car `request.user` mocké globalement, mais pas le guard isolé
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
```typescript
|
||||
const user = (request as any).user as { userId: string } | undefined;
|
||||
if (!user?.userId) {
|
||||
throw new UnauthorizedException({ error: { code: 'UNAUTHENTICATED', message: '...' } });
|
||||
}
|
||||
```
|
||||
|
||||
- **Règle** : les guards route-level ne font pas confiance aux guards globaux pour leurs invariants — ils se défendent eux-mêmes.
|
||||
- Contexte technique : NestJS v10+ — 09-03-2026
|
||||
|
||||
---
|
||||
|
||||
<a id="risque-compteurs-inmemory"></a>
|
||||
## Compteurs in-memory ≠ métriques persistées
|
||||
|
||||
### Risques
|
||||
|
||||
- Compteurs in-memory remis à zéro au restart (perte de données)
|
||||
- Non agrégables sur plusieurs instances (données partielles par pod)
|
||||
|
||||
### Symptômes
|
||||
|
||||
- Métriques qui "repartent de 0" à chaque déploiement
|
||||
- Dashboards incorrects en environnement multi-instance
|
||||
|
||||
### Bonnes pratiques / mitigations
|
||||
|
||||
- V1 low-cost : `Redis INCRBY` best-effort par `eventType` → persisté et agrégé multi-instances
|
||||
- Évolutif vers Prometheus/OTel sans changer l'interface (abstraction dès le départ)
|
||||
- Contexte technique : Redis / NestJS — 09-03-2026
|
||||
|
||||
Reference in New Issue
Block a user