mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-04-06 21:41:42 +02:00
docs: ajoute index+ancres et capitalise app-alexandrie
This commit is contained in:
@@ -8,7 +8,22 @@ Ce fichier contient **uniquement** des patterns back-end :
|
|||||||
|
|
||||||
Objectif : éviter de réinventer la roue et réduire le temps de debug.
|
Objectif : éviter de réinventer la roue et réduire le temps de debug.
|
||||||
|
|
||||||
Dernière mise à jour : 25-01-2026
|
Dernière mise à jour : 09-03-2026
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
- [Format d’erreur API standardisé](#pattern-format-derreur-api-standardise)
|
||||||
|
- [Middleware de corrélation (requestId / traceId)](#pattern-middleware-correlation-requestid-traceid)
|
||||||
|
- [Idempotency key pour opérations sensibles](#pattern-idempotency-key-operations-sensibles)
|
||||||
|
- [Pagination robuste (cursor-based) pour les listings](#pattern-pagination-robuste-cursor-based)
|
||||||
|
- [Exécution asynchrone des tâches longues (queue + outbox light)](#pattern-execution-asynchrone-taches-longues)
|
||||||
|
- [Soft delete et archivage explicite](#pattern-soft-delete-archivage-explicite)
|
||||||
|
- [Webhooks sortants robustes et idempotents](#pattern-webhooks-sortants-robustes-idempotents)
|
||||||
|
- [Contracts-First / Zod-Infer / No-DTO (monorepo TypeScript fullstack)](#pattern-contracts-first-zod-infer-no-dto)
|
||||||
|
- [Guard global NestJS — ordre d’enregistrement et décorateurs de bypass](#pattern-guard-global-nestjs)
|
||||||
|
- [Provider-Strategy pour intégrations tierces — périmètre complet](#pattern-provider-strategy-integrations-tierces)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -65,6 +80,7 @@ Si ce n’est pas confirmé comme fonctionnel et utile, **ça n’a rien à fair
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-format-derreur-api-standardise"></a>
|
||||||
## Pattern : Format d’erreur API standardisé
|
## Pattern : Format d’erreur API standardisé
|
||||||
|
|
||||||
- Objectif : fournir des erreurs prévisibles, exploitables et cohérentes pour tous les clients.
|
- Objectif : fournir des erreurs prévisibles, exploitables et cohérentes pour tous les clients.
|
||||||
@@ -101,6 +117,7 @@ Si ce n’est pas confirmé comme fonctionnel et utile, **ça n’a rien à fair
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-middleware-correlation-requestid-traceid"></a>
|
||||||
## Pattern : Middleware de corrélation (requestId / traceId)
|
## Pattern : Middleware de corrélation (requestId / traceId)
|
||||||
|
|
||||||
- Objectif : relier chaque requête aux logs et erreurs associées.
|
- Objectif : relier chaque requête aux logs et erreurs associées.
|
||||||
@@ -131,6 +148,7 @@ Si ce n’est pas confirmé comme fonctionnel et utile, **ça n’a rien à fair
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-idempotency-key-operations-sensibles"></a>
|
||||||
## Pattern : Idempotency key pour opérations sensibles
|
## Pattern : Idempotency key pour opérations sensibles
|
||||||
|
|
||||||
- Objectif : empêcher les doublons lors de retries ou timeouts.
|
- Objectif : empêcher les doublons lors de retries ou timeouts.
|
||||||
@@ -161,6 +179,7 @@ Si ce n’est pas confirmé comme fonctionnel et utile, **ça n’a rien à fair
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-pagination-robuste-cursor-based"></a>
|
||||||
## Pattern : Pagination robuste (cursor-based) pour les listings
|
## Pattern : Pagination robuste (cursor-based) pour les listings
|
||||||
|
|
||||||
- Objectif : fournir des listings stables et performants sans incohérences entre pages.
|
- Objectif : fournir des listings stables et performants sans incohérences entre pages.
|
||||||
@@ -195,6 +214,7 @@ Si ce n’est pas confirmé comme fonctionnel et utile, **ça n’a rien à fair
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-execution-asynchrone-taches-longues"></a>
|
||||||
## Pattern : Exécution asynchrone des tâches longues (queue + outbox light)
|
## Pattern : Exécution asynchrone des tâches longues (queue + outbox light)
|
||||||
|
|
||||||
- Objectif : sortir les opérations longues ou fragiles du chemin request/response.
|
- Objectif : sortir les opérations longues ou fragiles du chemin request/response.
|
||||||
@@ -231,6 +251,7 @@ Si ce n’est pas confirmé comme fonctionnel et utile, **ça n’a rien à fair
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-soft-delete-archivage-explicite"></a>
|
||||||
## Pattern : Soft delete et archivage explicite
|
## Pattern : Soft delete et archivage explicite
|
||||||
|
|
||||||
- Objectif : permettre la suppression logique sans perte immédiate de données.
|
- Objectif : permettre la suppression logique sans perte immédiate de données.
|
||||||
@@ -266,6 +287,7 @@ Si ce n’est pas confirmé comme fonctionnel et utile, **ça n’a rien à fair
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-webhooks-sortants-robustes-idempotents"></a>
|
||||||
## Pattern : Webhooks sortants robustes et idempotents
|
## Pattern : Webhooks sortants robustes et idempotents
|
||||||
|
|
||||||
- Objectif : garantir des intégrations fiables avec des systèmes externes.
|
- Objectif : garantir des intégrations fiables avec des systèmes externes.
|
||||||
@@ -302,6 +324,7 @@ Si ce n’est pas confirmé comme fonctionnel et utile, **ça n’a rien à fair
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-contracts-first-zod-infer-no-dto"></a>
|
||||||
## Pattern : Contracts-First / Zod-Infer / No-DTO (monorepo TypeScript fullstack)
|
## Pattern : Contracts-First / Zod-Infer / No-DTO (monorepo TypeScript fullstack)
|
||||||
|
|
||||||
- Objectif : avoir une seule source de vérité pour les contrats d’interface entre API et client, sans redéfinition manuelle de types.
|
- Objectif : avoir une seule source de vérité pour les contrats d’interface entre API et client, sans redéfinition manuelle de types.
|
||||||
@@ -376,6 +399,7 @@ packages/contracts/src/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-guard-global-nestjs"></a>
|
||||||
## Pattern : Guard global NestJS — ordre d’enregistrement et décorateurs de bypass
|
## Pattern : Guard global NestJS — ordre d’enregistrement et décorateurs de bypass
|
||||||
|
|
||||||
- Objectif : protéger tous les endpoints par défaut, avec un mécanisme explicite pour les exceptions.
|
- Objectif : protéger tous les endpoints par défaut, avec un mécanisme explicite pour les exceptions.
|
||||||
@@ -423,19 +447,52 @@ if (skip) return true;
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Index (à remplir au fil des validations)
|
<a id="pattern-provider-strategy-integrations-tierces"></a>
|
||||||
|
## Pattern : Provider-Strategy pour intégrations tierces — périmètre complet
|
||||||
|
|
||||||
- Format d’erreur API standardisé
|
- Objectif : isoler intégralement la logique propre à un prestataire (Stripe, Brevo, Firebase…) derrière une interface stable, pour éviter la contamination du domaine par le SDK tiers.
|
||||||
- Middleware de corrélation (requestId / traceId)
|
- Contexte : backend NestJS/TypeScript avec 1+ prestataires externes (paiement, email, storage…).
|
||||||
- Idempotency key pour opérations sensibles
|
- Quand l’utiliser : dès qu’un service applicatif dépend d’un SDK tiers (et plus encore s’il y a des webhooks).
|
||||||
- Pagination robuste (cursor-based) pour les listings
|
- Quand l’éviter : intégration ponctuelle non critique sans effet de bord (rare) — sinon on perd vite le contrôle.
|
||||||
- Exécution asynchrone des tâches longues (queue + outbox light)
|
- Avantage :
|
||||||
- Soft delete et archivage explicite
|
- Testabilité : mock du provider, pas du SDK
|
||||||
- Webhooks sortants robustes et idempotents
|
- Remplacement du prestataire sans refactor “en cascade”
|
||||||
- Contracts-First / Zod-Infer / No-DTO (monorepo TypeScript fullstack)
|
- Responsabilités claires : provider = “parle Stripe”, service = “parle domaine”
|
||||||
- Guard global NestJS — ordre d’enregistrement et décorateurs de bypass
|
- Limites / vigilance :
|
||||||
|
- L’interface doit exposer des **types normalisés** (pas de types Stripe)
|
||||||
|
- Le provider gère aussi les webhooks : validation signature, parsing event, mapping
|
||||||
|
- Validé le : 09-03-2026
|
||||||
|
- Contexte technique : NestJS v10+ / intégration Stripe (webhooks) — pattern généralisable
|
||||||
|
|
||||||
⸻
|
### Implémentation (exemple minimal)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// billing-provider.interface.ts (pas d'import Stripe)
|
||||||
|
export type BillingPlan = 'MONTHLY' | 'ANNUAL';
|
||||||
|
|
||||||
|
export type BillingWebhookResult = {
|
||||||
|
userId: string;
|
||||||
|
externalId: string;
|
||||||
|
plan: BillingPlan;
|
||||||
|
status: 'ACTIVE' | 'INACTIVE' | 'CANCELLED';
|
||||||
|
currentPeriodEnd: Date | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface BillingProvider {
|
||||||
|
createCheckoutSession(userId: string, plan: BillingPlan): Promise<{ checkoutUrl: string }>;
|
||||||
|
cancelSubscription(externalId: string): Promise<void>;
|
||||||
|
handleWebhook(rawBody: Buffer, signature: string): Promise<BillingWebhookResult | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// billing.service.ts (domaine uniquement)
|
||||||
|
async handleWebhook(rawBody: Buffer, signature: string): Promise<void> {
|
||||||
|
const result = await this.billingProvider.handleWebhook(rawBody, signature);
|
||||||
|
if (!result) return;
|
||||||
|
await this.prisma.subscription.upsert({ /* données normalisées */ });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Notes importantes
|
### Notes importantes
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Ce fichier recense des risques back-end susceptibles de provoquer :
|
|||||||
- régressions coûteuses,
|
- régressions coûteuses,
|
||||||
- incohérences de données.
|
- incohérences de données.
|
||||||
|
|
||||||
Dernière mise à jour : 25-01-2026
|
Dernière mise à jour : 09-03-2026
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -22,6 +22,22 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
- [AuthN/AuthZ dispersée](#risque-authn-authz-dispersee)
|
||||||
|
- [Guard global manquant (request.user)](#risque-guard-global-manquant)
|
||||||
|
- [Duplication silencieuse de constantes (contracts)](#risque-duplication-constantes-contracts)
|
||||||
|
- [Contrats API implicites](#risque-contrats-api-implicites)
|
||||||
|
- [Erreurs non standardisées](#risque-erreurs-non-standardisees)
|
||||||
|
- [Migrations risquées / non reproductibles](#risque-migrations-risquees)
|
||||||
|
- [Non-idempotence sur opérations sensibles](#risque-non-idempotence)
|
||||||
|
- [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)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-authn-authz-dispersee"></a>
|
||||||
## AuthN/AuthZ dispersée (contrôles d’accès au fil de l’eau)
|
## AuthN/AuthZ dispersée (contrôles d’accès au fil de l’eau)
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
@@ -44,6 +60,52 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-guard-global-manquant"></a>
|
||||||
|
## Guard global manquant (request.user jamais peuplé)
|
||||||
|
|
||||||
|
### Risques
|
||||||
|
|
||||||
|
- Chaîne auth bâtie sur une fondation inopérante (tout “a l’air OK” en dev/tests, mais casse en prod)
|
||||||
|
- Guards aval qui dépendent de `request.user` en erreur (ou contournements involontaires)
|
||||||
|
- Découvert tard (souvent uniquement en code review ou en prod)
|
||||||
|
|
||||||
|
### Symptômes
|
||||||
|
|
||||||
|
- `request.user` vaut `undefined` dans un guard supposé “après auth”
|
||||||
|
- Endpoints qui passent alors qu’ils devraient être refusés (si les guards aval se désactivent/retournent true par défaut)
|
||||||
|
- Tests “verts” car trop mockés (pas de test e2e qui valide le pipeline complet)
|
||||||
|
|
||||||
|
### Bonnes pratiques / mitigations
|
||||||
|
|
||||||
|
- Poser explicitement le guard global dès les foundations (au moins `AuthGuard`)
|
||||||
|
- Vérifier l’ordre des `APP_GUARD` (AuthGuard avant tout guard qui lit `request.user`)
|
||||||
|
- Ajouter au minimum 1 test d’intégration/e2e qui prouve que `request.user` est bien peuplé sur un endpoint protégé
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<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-contrats-api-implicites"></a>
|
||||||
## Contrats API implicites (validation faible ou absente)
|
## Contrats API implicites (validation faible ou absente)
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
@@ -65,6 +127,7 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-erreurs-non-standardisees"></a>
|
||||||
## Erreurs non standardisées (4xx/5xx incohérents)
|
## Erreurs non standardisées (4xx/5xx incohérents)
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
@@ -86,6 +149,7 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-migrations-risquees"></a>
|
||||||
## Migrations risquées / non reproductibles
|
## Migrations risquées / non reproductibles
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
@@ -108,6 +172,7 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-non-idempotence"></a>
|
||||||
## Non-idempotence sur opérations sensibles
|
## Non-idempotence sur opérations sensibles
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
@@ -129,6 +194,48 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-stripe-current-period-end"></a>
|
||||||
|
## Stripe (v17+) : confusion `billing_cycle_anchor` vs `current_period_end`
|
||||||
|
|
||||||
|
### Risques
|
||||||
|
|
||||||
|
- Stocker une date de fin de période incorrecte en DB (bug silencieux)
|
||||||
|
- État d’abonnement incohérent (UI, relances, accès premium)
|
||||||
|
|
||||||
|
### Symptômes
|
||||||
|
|
||||||
|
- `currentPeriodEnd` correspond à une date “bizarre” (souvent proche de la création), ou à un jour du mois
|
||||||
|
- Des accès premium expirent trop tôt / trop tard
|
||||||
|
|
||||||
|
### Bonnes pratiques / mitigations
|
||||||
|
|
||||||
|
- Ne jamais interpréter `billing_cycle_anchor` comme une date de fin de période
|
||||||
|
- Utiliser `subscription.current_period_end` (timestamp) pour la fin de période courante
|
||||||
|
- Ajouter un test sur un événement webhook/Subscription qui vérifie la date persistée
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-prisma-unique-nullable"></a>
|
||||||
|
## PostgreSQL / Prisma : `@unique` sur champ nullable (idempotence cassée)
|
||||||
|
|
||||||
|
### Risques
|
||||||
|
|
||||||
|
- Doublons en base malgré un “unique” attendu (PostgreSQL autorise plusieurs `NULL` dans un index UNIQUE)
|
||||||
|
- Upserts non idempotents si la clé peut être `null` (`where: { externalId: null }` crée plusieurs lignes)
|
||||||
|
|
||||||
|
### Symptômes
|
||||||
|
|
||||||
|
- Plusieurs enregistrements “équivalents” avec `externalId = NULL`
|
||||||
|
- Rejouer un webhook / retry réseau crée une nouvelle ligne au lieu d’upsert
|
||||||
|
|
||||||
|
### Bonnes pratiques / mitigations
|
||||||
|
|
||||||
|
- Toute clé utilisée dans un `where` d’`upsert` doit être **non-nullable**
|
||||||
|
- Si un identifiant externe peut légitimement être `null`, ne pas l’utiliser comme clé d’idempotence : choisir une autre clé unique non-nullable
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-observabilite-insuffisante"></a>
|
||||||
## Observabilité insuffisante (logs non structurés, pas de corrélation)
|
## Observabilité insuffisante (logs non structurés, pas de corrélation)
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
|
|||||||
@@ -6,7 +6,13 @@ sur les projets Lead_tech : tone of voice, structure des docs, formats récurren
|
|||||||
Objectif : produire une documentation cohérente d'un projet à l'autre,
|
Objectif : produire une documentation cohérente d'un projet à l'autre,
|
||||||
réduire le temps de rédaction et de relecture.
|
réduire le temps de rédaction et de relecture.
|
||||||
|
|
||||||
Dernière mise à jour : 2026-03-08
|
Dernière mise à jour : 2026-03-09
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
- [Langue par type de document](#convention-langue-par-type-de-document)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -42,6 +48,7 @@ Pas de "bonne pratique" théorique.
|
|||||||
|
|
||||||
## Conventions actives
|
## Conventions actives
|
||||||
|
|
||||||
|
<a id="convention-langue-par-type-de-document"></a>
|
||||||
### Convention : Langue par type de document
|
### Convention : Langue par type de document
|
||||||
|
|
||||||
- Scope : tous les fichiers du repo Lead_tech et des projets
|
- Scope : tous les fichiers du repo Lead_tech et des projets
|
||||||
@@ -50,7 +57,3 @@ Pas de "bonne pratique" théorique.
|
|||||||
- Contexte projet : Lead_tech (convention globale)
|
- Contexte projet : Lead_tech (convention globale)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Index
|
|
||||||
|
|
||||||
_(à remplir au fil des validations)_
|
|
||||||
|
|||||||
@@ -12,7 +12,16 @@ Il sert de **mémoire durable** pour éviter :
|
|||||||
- de redélibérer éternellement sur des sujets déjà tranchés,
|
- de redélibérer éternellement sur des sujets déjà tranchés,
|
||||||
- de propager des “bonnes pratiques” théoriques non éprouvées.
|
- de propager des “bonnes pratiques” théoriques non éprouvées.
|
||||||
|
|
||||||
Dernière mise à jour : 25-01-2026
|
Dernière mise à jour : 09-03-2026
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
- [Gestion explicite des états UI (loading / empty / error)](#pattern-etats-ui-loading-empty-error)
|
||||||
|
- [Séparation claire server state / client state](#pattern-separation-server-state-client-state)
|
||||||
|
- [Formulaire robuste avec validation et erreurs explicites](#pattern-formulaire-robuste)
|
||||||
|
- [Navigation réactive post-action async (React / Expo Router)](#pattern-navigation-reactive-post-action-async)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -63,6 +72,7 @@ au même niveau d’exigence que le backend.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-etats-ui-loading-empty-error"></a>
|
||||||
## Pattern : Gestion explicite des états UI (loading / empty / error)
|
## Pattern : Gestion explicite des états UI (loading / empty / error)
|
||||||
|
|
||||||
### Synthèse
|
### Synthèse
|
||||||
@@ -111,6 +121,7 @@ if (loading) {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-separation-server-state-client-state"></a>
|
||||||
## Pattern : Séparation claire server state / client state
|
## Pattern : Séparation claire server state / client state
|
||||||
|
|
||||||
### Synthèse
|
### Synthèse
|
||||||
@@ -156,6 +167,7 @@ Ne jamais :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-formulaire-robuste"></a>
|
||||||
## Pattern : Formulaire robuste avec validation et erreurs explicites
|
## Pattern : Formulaire robuste avec validation et erreurs explicites
|
||||||
|
|
||||||
### Synthèse
|
### Synthèse
|
||||||
@@ -199,6 +211,7 @@ Ne jamais :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-navigation-reactive-post-action-async"></a>
|
||||||
## Pattern : Navigation réactive post-action async (React / Expo Router)
|
## Pattern : Navigation réactive post-action async (React / Expo Router)
|
||||||
|
|
||||||
### Synthèse
|
### Synthèse
|
||||||
@@ -273,18 +286,10 @@ const handleOAuth = async () => {
|
|||||||
- [ ] `useEffect` avec dépendances explicites (state pertinent + isLoading + error)
|
- [ ] `useEffect` avec dépendances explicites (state pertinent + isLoading + error)
|
||||||
- [ ] Cas d'erreur géré (ne pas naviguer si error est défini)
|
- [ ] Cas d'erreur géré (ne pas naviguer si error est défini)
|
||||||
- [ ] `useRef` si le trigger vient d'un callback externe (OAuth, deep link)
|
- [ ] `useRef` si le trigger vient d'un callback externe (OAuth, deep link)
|
||||||
|
- [ ] Convention documentée dans la story foundations / project-context avant les premiers écrans
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Index des patterns
|
|
||||||
|
|
||||||
- Gestion explicite des états UI (loading / empty / error)
|
|
||||||
- Séparation claire server state / client state
|
|
||||||
- Formulaire robuste avec validation et erreurs explicites
|
|
||||||
- Navigation réactive post-action async (React / Expo Router)
|
|
||||||
|
|
||||||
⸻
|
|
||||||
|
|
||||||
### Principes transverses
|
### Principes transverses
|
||||||
|
|
||||||
- Un pattern = une responsabilité claire
|
- Un pattern = une responsabilité claire
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Ce fichier recense des risques front-end susceptibles de provoquer :
|
|||||||
- dette technique rapide,
|
- dette technique rapide,
|
||||||
- régressions UX/perf/a11y.
|
- régressions UX/perf/a11y.
|
||||||
|
|
||||||
Dernière mise à jour : 25-01-2026
|
Dernière mise à jour : 09-03-2026
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -21,6 +21,18 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
- [Auth côté client](#risque-auth-cote-client)
|
||||||
|
- [Erreurs silencieuses / écrans blancs](#risque-erreurs-silencieuses)
|
||||||
|
- [Mélange server state / client state](#risque-melange-server-client-state)
|
||||||
|
- [Appels API en state local d’écran](#risque-api-state-local-ecran)
|
||||||
|
- [Performances : sur-renders + bundle](#risque-performances-sur-renders)
|
||||||
|
- [Accessibilité oubliée (a11y)](#risque-accessibilite-oubliee)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-auth-cote-client"></a>
|
||||||
## Auth côté client (mauvaise séparation des responsabilités)
|
## Auth côté client (mauvaise séparation des responsabilités)
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
@@ -49,6 +61,7 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-erreurs-silencieuses"></a>
|
||||||
## Erreurs silencieuses / écrans blancs
|
## Erreurs silencieuses / écrans blancs
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
@@ -70,6 +83,7 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-melange-server-client-state"></a>
|
||||||
## Mélange server state / client state
|
## Mélange server state / client state
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
@@ -92,6 +106,30 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-api-state-local-ecran"></a>
|
||||||
|
## Appels API gérés en state local d’écran (refactor coûteux)
|
||||||
|
|
||||||
|
### Risques
|
||||||
|
|
||||||
|
- Server state non partageable entre écrans (liste/detail, wizard, tabs) → duplication et incohérences
|
||||||
|
- Pas de cache / invalidation standard → bugs subtils et re-fetchs inutiles
|
||||||
|
- Refactor tardif quand l’epic s’étend (mutations, cache, offline, pagination)
|
||||||
|
|
||||||
|
### Symptômes
|
||||||
|
|
||||||
|
- Même appel API recopié dans plusieurs écrans
|
||||||
|
- Un écran “A” modifie une ressource mais l’écran “B” n’est jamais rafraîchi
|
||||||
|
- Code review qui force un refactor vers un store/cache au milieu d’un epic
|
||||||
|
|
||||||
|
### Bonnes pratiques / mitigations
|
||||||
|
|
||||||
|
- Par défaut : créer un store de domaine (ex : Zustand) ou un cache de server state pour tout domaine susceptible d’être réutilisé
|
||||||
|
- Centraliser `isLoading`/`error`/`data` et la stratégie de refresh/invalidation
|
||||||
|
- Exception acceptable : état purement UI, local et jetable (ex : input de recherche, filtres temporaires non persistés)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-performances-sur-renders"></a>
|
||||||
## Performances : sur-renders + bundle non maîtrisé
|
## Performances : sur-renders + bundle non maîtrisé
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
@@ -115,6 +153,7 @@ Dernière mise à jour : 25-01-2026
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-accessibilite-oubliee"></a>
|
||||||
## Accessibilité oubliée (a11y)
|
## Accessibilité oubliée (a11y)
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
|
|||||||
@@ -6,7 +6,13 @@ Ce fichier contient **uniquement** des patterns :
|
|||||||
- validés,
|
- validés,
|
||||||
- utilisés en conditions réelles.
|
- utilisés en conditions réelles.
|
||||||
|
|
||||||
Dernière mise à jour : 2025-12-19
|
Dernière mise à jour : 2026-03-09
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
- [Feature flags pour routage plateformes](#pattern-n8n-feature-flags-routage-plateformes)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -40,6 +46,7 @@ Si ce n’est pas confirmé comme fonctionnel, **ça n’a rien à faire ici**.
|
|||||||
(contenu)
|
(contenu)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<a id="pattern-n8n-feature-flags-routage-plateformes"></a>
|
||||||
## Pattern : Feature flags pour routage plateformes
|
## Pattern : Feature flags pour routage plateformes
|
||||||
|
|
||||||
- Node : Code (JS)
|
- Node : Code (JS)
|
||||||
|
|||||||
@@ -7,10 +7,19 @@ c’est-à-dire susceptibles de provoquer :
|
|||||||
- des comportements inattendus,
|
- des comportements inattendus,
|
||||||
- des problèmes lors des upgrades.
|
- des problèmes lors des upgrades.
|
||||||
|
|
||||||
Dernière mise à jour : 2025-12-19
|
Dernière mise à jour : 2026-03-09
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
- [Vigilance générale](#risque-n8n-vigilance-generale)
|
||||||
|
- [IF Node](#risque-n8n-if-node)
|
||||||
|
- [staticData (`$getWorkflowStaticData`)](#risque-n8n-staticdata)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-n8n-vigilance-generale"></a>
|
||||||
## Vigilance générale
|
## Vigilance générale
|
||||||
|
|
||||||
- Différences de comportement entre n8n **cloud et self-hosted** (certains nodes, credentials, timeouts)
|
- Différences de comportement entre n8n **cloud et self-hosted** (certains nodes, credentials, timeouts)
|
||||||
@@ -28,6 +37,7 @@ Dernière mise à jour : 2025-12-19
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-n8n-if-node"></a>
|
||||||
## IF Node
|
## IF Node
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
@@ -53,6 +63,7 @@ Dernière mise à jour : 2025-12-19
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="risque-n8n-staticdata"></a>
|
||||||
## staticData (`$getWorkflowStaticData`)
|
## staticData (`$getWorkflowStaticData`)
|
||||||
|
|
||||||
### Risques
|
### Risques
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ Ce fichier contient des patterns de **cadrage produit, priorisation et analyse f
|
|||||||
Objectif : éviter de redélibérer sur des sujets déjà tranchés, capitaliser ce qui fonctionne
|
Objectif : éviter de redélibérer sur des sujets déjà tranchés, capitaliser ce qui fonctionne
|
||||||
du point de vue product management et analyse métier.
|
du point de vue product management et analyse métier.
|
||||||
|
|
||||||
Dernière mise à jour : 2026-03-08
|
Dernière mise à jour : 2026-03-09
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
_(à remplir au fil des validations)_
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -53,7 +59,3 @@ Si ce n'est pas **validé par l'expérience projet**, ça n'a pas sa place ici.
|
|||||||
### Checklist (si pertinente)
|
### Checklist (si pertinente)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Index
|
|
||||||
|
|
||||||
_(à remplir au fil des validations)_
|
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ Ce fichier contient **uniquement** des patterns UX/UI :
|
|||||||
Objectif : éviter de redélibérer sur des sujets déjà tranchés et capitaliser
|
Objectif : éviter de redélibérer sur des sujets déjà tranchés et capitaliser
|
||||||
ce qui fonctionne du point de vue utilisateur.
|
ce qui fonctionne du point de vue utilisateur.
|
||||||
|
|
||||||
Dernière mise à jour : 2026-03-08
|
Dernière mise à jour : 2026-03-09
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
_(à remplir au fil des validations)_
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -55,12 +61,6 @@ Si ce n'est pas **validé par l'usage ou l'expérience projet**, ça n'a pas sa
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Index
|
|
||||||
|
|
||||||
_(à remplir au fil des validations)_
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes importantes
|
## Notes importantes
|
||||||
|
|
||||||
- On préfère 5 patterns solides à 50 "guidelines de design".
|
- On préfère 5 patterns solides à 50 "guidelines de design".
|
||||||
|
|||||||
@@ -5,7 +5,13 @@ et les anti-patterns observés en conditions réelles.
|
|||||||
|
|
||||||
Objectif : ne pas répéter les mêmes erreurs de conception d'un projet à l'autre.
|
Objectif : ne pas répéter les mêmes erreurs de conception d'un projet à l'autre.
|
||||||
|
|
||||||
Dernière mise à jour : 2026-03-08
|
Dernière mise à jour : 2026-03-09
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
_(à remplir au fil des observations)_
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -41,7 +47,3 @@ Chaque entrée doit être **issue d'un problème réel**, pas d'une opinion.
|
|||||||
- Contexte produit : ex. `App mobile / onboarding` ou `Webapp / formulaire`
|
- Contexte produit : ex. `App mobile / onboarding` ou `Webapp / formulaire`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Index
|
|
||||||
|
|
||||||
_(à remplir au fil des observations)_
|
|
||||||
|
|||||||
@@ -8,7 +8,96 @@ Objectifs :
|
|||||||
- éviter de reposer les mêmes questions
|
- éviter de reposer les mêmes questions
|
||||||
- assumer les compromis
|
- assumer les compromis
|
||||||
|
|
||||||
Dernière mise à jour : 2025-12-19
|
Dernière mise à jour : 2026-03-09
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
- [Story sizing — foundations vs qualité non bloquante](#decision-story-sizing-foundations)
|
||||||
|
- [Code review adversariale — contexte frais](#decision-code-review-adversariale)
|
||||||
|
- [Workflows n8n complexes = mini-systèmes](#decision-n8n-mini-systemes)
|
||||||
|
- [Le front-end est un logiciel en production](#decision-frontend-production)
|
||||||
|
- [Le back-end est un logiciel en production](#decision-backend-production)
|
||||||
|
- [Contrats d’API explicites et versionnés](#decision-contrats-api)
|
||||||
|
- [Gestion standard des erreurs et des statuts HTTP](#decision-erreurs-http)
|
||||||
|
- [Migrations et évolution de schéma maîtrisées](#decision-migrations)
|
||||||
|
- [Observabilité minimale obligatoire](#decision-observabilite)
|
||||||
|
- [Authentification et autorisation centrales](#decision-auth-central)
|
||||||
|
- [Idempotence et gestion des retries](#decision-idempotence-retries)
|
||||||
|
- [Structure Docker et données persistantes](#decision-structure-docker)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="decision-story-sizing-foundations"></a>
|
||||||
|
## Story sizing — foundations bloquantes vs qualité non bloquante (CI mobile)
|
||||||
|
|
||||||
|
- Date : 2026-03-09
|
||||||
|
- Statut : Accepted
|
||||||
|
- Périmètre : global
|
||||||
|
|
||||||
|
### Contexte
|
||||||
|
|
||||||
|
Des items “infra” ont été mis dans des stories foundations d’epic alors qu’aucune story métier suivante n’en dépendait (ex : CI Maestro mobile iOS/Android).
|
||||||
|
Résultat observé : story foundations “never-done”, friction et coût de contexte, sans bénéfice sur le throughput métier.
|
||||||
|
|
||||||
|
### Options envisagées
|
||||||
|
|
||||||
|
- Mettre toutes les améliorations de qualité dans foundations “par principe”
|
||||||
|
- Séparer les prérequis réellement bloquants du reste (qualité non bloquante)
|
||||||
|
|
||||||
|
### Décision
|
||||||
|
|
||||||
|
On distingue explicitement :
|
||||||
|
|
||||||
|
- **Prérequis bloquants** : à inclure dans foundations (les stories suivantes en dépendent)
|
||||||
|
- **Qualité non bloquante** : story indépendante, en parallèle ou après, sans bloquer le métier
|
||||||
|
|
||||||
|
### Justification
|
||||||
|
|
||||||
|
- Un epic doit pouvoir avancer sur le métier dès que les dépendances techniques minimales sont là
|
||||||
|
- Les chantiers “qualité” (CI mobile, perf, audits…) ont souvent une inertie qui ne doit pas geler l’epic
|
||||||
|
|
||||||
|
### Conséquences
|
||||||
|
|
||||||
|
- Pour chaque AC “infra” en foundations : poser la question “la story X+1 est-elle bloquée si ce n’est pas fait ?”
|
||||||
|
- Si la réponse est non : sortir l’AC en story dédiée (tag qualité / infra), et la planifier à part
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="decision-code-review-adversariale"></a>
|
||||||
|
## Code review adversariale — passe dédiée en contexte frais
|
||||||
|
|
||||||
|
- Date : 2026-03-09
|
||||||
|
- Statut : Accepted
|
||||||
|
- Périmètre : global
|
||||||
|
|
||||||
|
### Contexte
|
||||||
|
|
||||||
|
Certaines issues CRITICAL sont invisibles dans le contexte d’implémentation (biais de confirmation : “je sais comment c’est censé marcher”).
|
||||||
|
Elles émergent uniquement en lecture froide : fondations manquantes, usages dépréciés, invariants non respectés (ex : sessions sans TTL).
|
||||||
|
|
||||||
|
### Options envisagées
|
||||||
|
|
||||||
|
- Review “au fil de l’eau” dans le même contexte que l’implémentation
|
||||||
|
- Review dédiée, séparée, en contexte frais (nouvelle session / nouveau modèle / reviewer différent)
|
||||||
|
|
||||||
|
### Décision
|
||||||
|
|
||||||
|
La code review doit être une passe **séparée** de l’implémentation, en **contexte frais**, avec un objectif explicite : chercher des CRITICAL sans concession.
|
||||||
|
|
||||||
|
### Justification
|
||||||
|
|
||||||
|
- Les incohérences systémiques (sécurité, idempotence, TTL, drift de contracts) se détectent mieux en lecture froide
|
||||||
|
- Réduit fortement le coût de debug tardif (prod/staging) et les refactors “de fondations”
|
||||||
|
|
||||||
|
### Conséquences
|
||||||
|
|
||||||
|
- Process recommandé :
|
||||||
|
1. Dev termine l’implémentation, marque la story `review`
|
||||||
|
2. Nouvelle session (contexte frais) : charger uniquement story + diff
|
||||||
|
3. Review adversariale : lister CRITICAL + mitigations
|
||||||
|
4. Corriger avant `done`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -32,6 +121,7 @@ Dernière mise à jour : 2025-12-19
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-n8n-mini-systemes"></a>
|
||||||
## Workflows n8n complexes = mini-systèmes
|
## Workflows n8n complexes = mini-systèmes
|
||||||
|
|
||||||
- Date : 2025-12-19
|
- Date : 2025-12-19
|
||||||
@@ -67,6 +157,7 @@ Les considérer comme du code.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-frontend-production"></a>
|
||||||
## Le front-end est un logiciel en production
|
## Le front-end est un logiciel en production
|
||||||
|
|
||||||
- Date : 2026-01-25
|
- Date : 2026-01-25
|
||||||
@@ -119,6 +210,7 @@ Il est soumis aux mêmes principes que le backend :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-backend-production"></a>
|
||||||
## Le back-end est un logiciel en production (qualité, observabilité, sécurité)
|
## Le back-end est un logiciel en production (qualité, observabilité, sécurité)
|
||||||
|
|
||||||
- Date : 2026-01-25
|
- Date : 2026-01-25
|
||||||
@@ -168,6 +260,7 @@ Exigences minimales :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-contrats-api"></a>
|
||||||
## Contrats d’API explicites et versionnés
|
## Contrats d’API explicites et versionnés
|
||||||
|
|
||||||
- Date : 2026-01-25
|
- Date : 2026-01-25
|
||||||
@@ -208,6 +301,7 @@ Minimum attendu :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-erreurs-http"></a>
|
||||||
## Gestion standard des erreurs et des statuts HTTP
|
## Gestion standard des erreurs et des statuts HTTP
|
||||||
|
|
||||||
- Date : 2026-01-25
|
- Date : 2026-01-25
|
||||||
@@ -247,6 +341,7 @@ Les erreurs HTTP sont standardisées :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-migrations"></a>
|
||||||
## Migrations et évolution de schéma maîtrisées
|
## Migrations et évolution de schéma maîtrisées
|
||||||
|
|
||||||
- Date : 2026-01-25
|
- Date : 2026-01-25
|
||||||
@@ -287,6 +382,7 @@ Principes :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-observabilite"></a>
|
||||||
## Observabilité minimale obligatoire (logs, corrélation, signaux)
|
## Observabilité minimale obligatoire (logs, corrélation, signaux)
|
||||||
|
|
||||||
- Date : 2026-01-25
|
- Date : 2026-01-25
|
||||||
@@ -326,6 +422,7 @@ Observabilité minimale obligatoire :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-auth-central"></a>
|
||||||
## Authentification et autorisation comme responsabilités centrales
|
## Authentification et autorisation comme responsabilités centrales
|
||||||
|
|
||||||
- Date : 2026-01-25
|
- Date : 2026-01-25
|
||||||
@@ -368,6 +465,7 @@ Principes :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-idempotence-retries"></a>
|
||||||
## Idempotence et gestion des retries pour les opérations sensibles
|
## Idempotence et gestion des retries pour les opérations sensibles
|
||||||
|
|
||||||
- Date : 2026-01-25
|
- Date : 2026-01-25
|
||||||
@@ -409,6 +507,7 @@ Principes :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-structure-docker"></a>
|
||||||
## Convention de structure pour les projets Docker et les données persistantes
|
## Convention de structure pour les projets Docker et les données persistantes
|
||||||
|
|
||||||
- Date : 2026-03-06
|
- Date : 2026-03-06
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ Sinon `request.user` peut être undefined dans les guards suivants.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
_Aucune proposition en attente pour le moment._
|
||||||
|
|
||||||
# Rôle dans l'architecture
|
# Rôle dans l'architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user