Capitalise nouveaux patterns backend/frontend/BMAD et externalise les templates du post-install BMAD

This commit is contained in:
MaksTinyWorkshop
2026-03-10 10:52:07 +01:00
parent 4a3df7cd01
commit f7a55b1113
23 changed files with 742 additions and 220 deletions

View File

@@ -8,7 +8,7 @@ Ce fichier contient **uniquement** des patterns back-end :
Objectif : éviter de réinventer la roue et réduire le temps de debug.
Dernière mise à jour : 09-03-2026
Dernière mise à jour : 10-03-2026
---
@@ -27,6 +27,10 @@ Dernière mise à jour : 09-03-2026
- [Stripe — metadata sur `subscription_data`, pas sur la Session](#pattern-stripe-subscription-metadata)
- [Webhooks entrants — parsing unique (single constructWebhookEvent)](#pattern-webhook-parsing-unique)
- [Contracts-First — error codes comme contrat obligatoire](#pattern-contracts-error-codes)
- [RedisHealthService avec cache interne court](#pattern-redis-health-cache-court)
- [Sémantique explicite `Trial` vs `Paid` dans Subscription](#pattern-subscription-trial-vs-paid)
- [Restauration dachats Stripe en 3 étapes](#pattern-restauration-achats-stripe)
- [Mapping explicite de `P2002` Prisma sur update de champ unique](#pattern-prisma-p2002-update-unique)
---
@@ -558,6 +562,132 @@ handlePackWebhookEvent(event): PackWebhookResult | null
---
<a id="pattern-redis-health-cache-court"></a>
## Pattern : RedisHealthService avec cache interne court
- Objectif : exposer un état Redis exploitable par les guards globaux sans ping Redis à chaque requête.
- Contexte : backend Node/NestJS avec Redis consulté dans le chemin de décision décriture.
- Quand lutiliser : quand plusieurs requêtes concurrentes doivent consulter létat Redis.
- Quand léviter : si Redis nest pas consulté dans le chemin request/response.
- Avantage :
- réduit fortement le flood de `PING`
- garde un signal détat suffisamment frais
- Limites / vigilance :
- la fenêtre de cache doit rester courte
- létat initial doit être explicite et assumé
- Validé le : 10-03-2026
- Contexte technique : NestJS / Redis
### Implémentation (exemple minimal)
```txt
- Mémoriser lastStatus et lastCheck
- Si le dernier check a moins de 5s, retourner létat en cache
- Sinon exécuter un vrai PING et mettre le cache à jour
- Utiliser un état initial optimiste (`up`) si le produit ne doit pas bloquer les écritures au boot
```
### Checklist
- Cache court documenté
- Pas de ping Redis à chaque requête
- Comportement initial explicite
---
<a id="pattern-subscription-trial-vs-paid"></a>
## Pattern : Sémantique explicite `Trial` vs `Paid` dans Subscription
- Objectif : aligner le modèle métier, les guards et les jeux de tests sur une définition unique de labonnement payant actif.
- Contexte : modèle `Subscription``trialEndsAt` matérialise un essai.
- Quand lutiliser : dès quun même enregistrement supporte trial et abonnement payant.
- Quand léviter : si trial et abonnement payant sont modélisés par des entités distinctes.
- Avantage :
- évite les incohérences silencieuses dans les guards
- rend les fixtures et mocks e2e cohérents avec la règle métier
- Limites / vigilance :
- toute logique `isActive` doit préciser si elle signifie “trial ou paid” ou “paid only”
- Validé le : 10-03-2026
- Contexte technique : Backend agnostique / modèle dabonnement
### Implémentation (exemple minimal)
```txt
- Un abonnement payant actif nest pas seulement status = ACTIVE
- Il doit aussi avoir trialEndsAt = null
- Les fixtures et mocks e2e dun abonnement payant fixent toujours trialEndsAt: null
```
### Checklist
- Règle métier explicitée
- Guards alignés sur la sémantique choisie
- Fixtures et seeds cohérents
---
<a id="pattern-restauration-achats-stripe"></a>
## Pattern : restauration dachats Stripe en 3 étapes
- Objectif : reconstruire un état local cohérent à partir de Stripe sans dépendre dune hypothèse fragile.
- Contexte : flux de restore purchases mobile/web avec état local potentiellement désynchronisé.
- Quand lutiliser : dès quun utilisateur peut restaurer des achats depuis un nouveau device ou après désynchronisation.
- Quand léviter : si létat Stripe nest pas la source de vérité.
- Avantage :
- rend la réconciliation explicite
- supporte retries et restaurations tardives
- Limites / vigilance :
- la pagination Stripe et lidempotence décriture restent obligatoires
- Validé le : 10-03-2026
- Contexte technique : Stripe API / backend Node/NestJS
### Implémentation (exemple minimal)
```txt
1. Résolution du customer Stripe (ID persisté en DB, fallback robuste si absent)
2. Reconstruction de létat Stripe utile au domaine
3. Réconciliation et écritures locales idempotentes
```
### Checklist
- `stripeCustomerId` persistant côté app
- Réconciliation explicite documentée
- Upsert ou écriture idempotente
---
<a id="pattern-prisma-p2002-update-unique"></a>
## Pattern : mapping explicite de `P2002` Prisma sur update de champ unique
- Objectif : transformer un conflit dunicité prévisible en erreur métier exploitable plutôt quen 500 opaque.
- Contexte : `update` Prisma sur un champ `@unique` alimenté par une source externe ou concurrente.
- Quand lutiliser : dès quun champ unique peut être mis à jour après création.
- Quand léviter : jamais si le champ peut réellement entrer en collision.
- Avantage :
- réponse client stable
- diagnostic métier plus rapide
- Limites / vigilance :
- le mapping doit rester cohérent avec le format derreur API standardisé
- Validé le : 10-03-2026
- Contexte technique : Prisma / PostgreSQL / NestJS
### Implémentation (exemple minimal)
```txt
- Catch explicite de PrismaClientKnownRequestError code P2002
- Mapping vers une erreur métier stable
- Conserver requestId et format derreur standardisé
```
### Checklist
- `P2002` intercepté sur les updates sensibles
- Code derreur métier stable
- Pas de 500 générique sur conflit prévisible
---
### Notes importantes
- On préfère 5 patterns solides à 50 “bons conseils”.