mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-06-28 01:53:40 +02:00
capitalisation: triage 95_a_capitaliser + création domaine infra
Triage des 27 propositions du buffer de capitalisation (skill capitalisation-triage), avec vérification des doublons contre la base. Intégré dans knowledge/ (23 entrées): - backend: redis (compensation incrBy non-atomique), nestjs (injection cassée sous tsx watch; guard write mode dégradé), async (test rollback pipeline multi-fichiers), contracts (idempotence POST), auth (disclosure comptes soft-deleted), prisma (index partial soft-delete), llm-providers (nouveau: OAuth vs API key, prompt caching). - frontend: tests (garde-fous parking Later), navigation (fichiers non-route sous src/app Expo Router), general (type client vs payload backend), state (fallback catch-all mapping DB→UI). - workflow: story-tracking (statut BMAD vs narratif obsolète). - product: general (nouveau: doc feature store sans UI). - infra: NOUVEAU DOMAINE (traefik, tailscale, docker, docker-networking, reverse-proxy-paths, sidecar tailscale) + 00_INDEX.md. Autres: - 90_debug_et_postmortem.md: post-mortem réseau Docker partagé hors compose. - Rejeté 3 doublons (types enum contracts, getter PrismaService, $transaction). - Buffer 95_a_capitaliser.md purgé et restauré à son état initial. - _projects.conf: MAJ statuts epics + ajout app-rl799.
This commit is contained in:
@@ -9,12 +9,13 @@ Avant toute proposition backend, identifie le fichier dont le nom et la descript
|
||||
| Fichier | Domaine | Entrées clés |
|
||||
|---------|---------|--------------|
|
||||
| `auth.md` | Auth, sessions, tokens, erreurs API, corrélation | Format erreur standardisé, middleware requestId, anti-énumération, token usage unique, autorisation interne, opérations atomiques |
|
||||
| `contracts.md` | Contrats API, Zod, error codes, HTTP sémantique | Contracts-First/Zod-Infer/No-DTO, error codes comme contrat, HTTP 200 payload métier |
|
||||
| `contracts.md` | Contrats API, Zod, error codes, HTTP sémantique | Contracts-First/Zod-Infer/No-DTO, error codes comme contrat, HTTP 200 payload métier, idempotence POST = retour ressource existante |
|
||||
| `prisma.md` | Prisma, DB, migrations, pagination | Soft delete, pagination cursor, idempotency key, P2002 unique, Decimal sérialisation, migration manuelle P3014, filtrage métier dans service |
|
||||
| `stripe.md` | Stripe, paiements, webhooks entrants, subscriptions | Provider-Strategy, metadata subscription_data, parsing webhook unique, restauration achats, Trial vs Paid |
|
||||
| `nestjs.md` | NestJS, guards, Redis, quotas | Guard global APP_GUARD, RedisHealthService cache court, quota INCR+EXPIREAT atomique |
|
||||
| `multi-tenant.md` | Multi-tenant, isolation, feature flags | 403 vs 404, repository tenant-aware, tenantId dans updates, helper tenant partagé, feature flag tenant, EN enforcement |
|
||||
| `nextjs.md` | Next.js App Router, Server Actions, isolation | Runtime-only logique pure, server-only isolation, utilitaires purs sans server-only, réutiliser champ V1, validation URL externe |
|
||||
| `async.md` | Jobs async, webhooks sortants, queues | Exécution asynchrone outbox light, webhooks sortants HMAC + retries idempotents, hooks fire-and-forget après création DB, fanout notification avec filtre grade, auto-purge fenêtre temporelle SQL |
|
||||
| `async.md` | Jobs async, webhooks sortants, queues | Exécution asynchrone outbox light, webhooks sortants HMAC + retries idempotents, hooks fire-and-forget après création DB, fanout notification avec filtre grade, auto-purge fenêtre temporelle SQL, test de rollback pipeline multi-fichiers atomique |
|
||||
| `general.md` | Architecture générale, helpers, RBAC | Helper auth centralisé enrichissable, ordre canonique des gates HTTP, délégation agrégat → endpoint agrégé, anti-énumération DELETE 204, lazy init memoizé, cap LRU par-user, convention dot-notation audit, whitelist explicite audit, singleton DB config, invalidation cache avant mutation, pipeline CI/CD GitHub Actions → VPS |
|
||||
| `tests.md` | Tests d'intégration DB, isolation, atomicité | `cleanup.track()` LIFO, `globalSetup` purge, template database Postgres, helper `waitForX()` polling-borné, test d'atomicité transaction, convention `describe()` 2 niveaux, refactor itératif d'un fichier monolithe |
|
||||
| `llm-providers.md` | Fournisseurs LLM, auth, coûts | OAuth consumer ≠ API key, prompt caching system prompt stable, budget cap fournisseur |
|
||||
|
||||
@@ -251,3 +251,30 @@ export const listRecentXxxForMember = async (
|
||||
```
|
||||
|
||||
L'admin garde un endpoint distinct sans le filtre temporel pour l'accès historique complet.
|
||||
|
||||
---
|
||||
|
||||
<a id="pattern-test-rollback-pipeline-multi-fichiers"></a>
|
||||
## Pattern : Test de rollback pour pipelines multi-fichiers atomiques
|
||||
|
||||
- Objectif : garantir qu'un pipeline qui écrit N fichiers avec rollback nettoie réellement l'état partiel quand le Nème échoue.
|
||||
- Contexte : opération qui persiste plusieurs artefacts (ex : variantes/dérivés d'une image, fichiers d'un export) en gardant la liste des chemins déjà écrits pour pouvoir les supprimer en cas d'échec.
|
||||
- Quand l'utiliser : tout pipeline « tout ou rien » sur N écritures de fichiers avec compensation manuelle (pas de transaction native).
|
||||
- Quand l'éviter : écriture d'un seul fichier, ou stockage qui offre une vraie transactionnalité.
|
||||
- Avantage :
|
||||
- couvre le cas limite réel (échec en cours de pipeline) plutôt que le seul chemin nominal
|
||||
- détecte une compensation incomplète (fichiers orphelins) ou excessive (suppression d'un fichier non écrit par ce pipeline)
|
||||
- Limites / vigilance :
|
||||
- le test doit être mis à jour quand N change (ajout d'un variant) pour couvrir le nouveau cas limite
|
||||
- Validé le : 03-04-2026
|
||||
- Contexte technique : Node.js / écriture fichiers — app-template-resto story 4.3
|
||||
|
||||
### Règle
|
||||
|
||||
Tout pipeline qui écrit N fichiers avec rollback (suppression des déjà-écrits si un échec survient) doit avoir un test unitaire couvrant le cas **« N-1 fichiers écrits + le Nème échoue »**. Ce test vérifie :
|
||||
|
||||
- que les N-1 fichiers déjà écrits sont **exactement** supprimés (ni plus, ni moins) ;
|
||||
- que la phase de finalisation (`finalize()` ou équivalent) n'est **pas** appelée ;
|
||||
- que l'erreur est bien propagée à l'appelant.
|
||||
|
||||
Quand le nombre d'artefacts change (ajout d'un variant), mettre à jour ce test pour couvrir le nouveau N.
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
title: Backend — Patterns : Contracts
|
||||
domain: backend
|
||||
bucket: patterns
|
||||
tags: [contracts, zod, api, error-codes, monorepo]
|
||||
tags: [contracts, zod, api, error-codes, monorepo, idempotence, http-semantics]
|
||||
applies_to: [analysis, implementation, review, architecture]
|
||||
severity: high
|
||||
validated_on: 2026-04-07
|
||||
validated_on: 2026-06-25
|
||||
source_projects: [app-alexandrie, RL799_V2]
|
||||
---
|
||||
|
||||
@@ -150,6 +150,34 @@ return res.status(200).json({
|
||||
|
||||
---
|
||||
|
||||
<a id="pattern-idempotence-post-ressource-existante"></a>
|
||||
## Pattern : Idempotence POST = retour de la ressource existante
|
||||
|
||||
- Objectif : garantir qu'un POST dont l'AC demande l'idempotence produit le **même résultat quel que soit le nombre d'appels**.
|
||||
- Contexte : endpoint de création où une duplication est détectable (ressource déjà créée pour le même sujet, ex : demande d'export, déclenchement de job unique). Complément du pattern « HTTP 200 + payload métier » ci-dessus, appliqué au cas duplication.
|
||||
- Quand l'utiliser : POST déclaré idempotent (retries client, double-tap mobile, rejeu réseau).
|
||||
- Quand l'éviter : création stricte où une duplication est une vraie erreur métier que l'appelant doit traiter explicitement.
|
||||
- Validé le : 13-04-2026
|
||||
- Contexte technique : NestJS / contrat API — app-alexandrie story 9.2
|
||||
|
||||
### Règle
|
||||
|
||||
Un POST idempotent **retourne la ressource existante** (HTTP 200 / 201) quand une duplication est détectée, sans lever d'erreur. Un `409 CONFLICT` est un comportement de **blocage**, pas d'idempotence : il force l'appelant à gérer un cas d'erreur et casse le contrat « N appels = 1 résultat ».
|
||||
|
||||
```typescript
|
||||
// ✅ IDEMPOTENT — retourne la ressource existante
|
||||
if (existing) return this.serialize(existing);
|
||||
|
||||
// ❌ NON-IDEMPOTENT — lève une erreur de blocage
|
||||
if (existing) throw new HttpException({ error: { code: 'ALREADY_EXISTS' } }, 409);
|
||||
```
|
||||
|
||||
### Côté client
|
||||
|
||||
Dédupliquer par `id` avant d'insérer dans la liste/store local, pour éviter les doublons en cas de race condition (deux requêtes parallèles recevant la même ressource).
|
||||
|
||||
---
|
||||
|
||||
<a id="pattern-coherence-result-repository"></a>
|
||||
## Pattern : Cohérence du pattern Result dans un repository
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: "Backend — Patterns : Fournisseurs LLM"
|
||||
domain: backend
|
||||
bucket: patterns
|
||||
tags: [llm, anthropic, openai, api-key, oauth, prompt-caching, couts]
|
||||
applies_to: [analysis, implementation, architecture]
|
||||
severity: medium
|
||||
validated_on: 2026-06-25
|
||||
source_projects: [_Assistant_Cuisine]
|
||||
---
|
||||
|
||||
# Backend — Patterns : Fournisseurs LLM
|
||||
|
||||
> Extrait de la base de connaissance Lead_tech. Voir `knowledge/backend/patterns/README.md` pour l'index complet.
|
||||
|
||||
---
|
||||
|
||||
<a id="pattern-oauth-consumer-vs-api-key"></a>
|
||||
## OAuth abonnement consumer ≠ API key — ne pas mélanger les deux usages
|
||||
|
||||
Tous les fournisseurs LLM (Anthropic, OpenAI, Google) séparent strictement deux mondes :
|
||||
|
||||
| Type | Auth | Usage prévu | Coût |
|
||||
|---|---|---|---|
|
||||
| **Abonnement consumer** (Claude Pro/Max, ChatGPT Plus) | OAuth via app officielle | usage interactif personnel via clients officiels (desktop, web, plugin IDE) | forfait mensuel |
|
||||
| **API platform** | API key | usage programmatique, multi-users, services tiers, prod | pay-per-token |
|
||||
|
||||
### Règle
|
||||
|
||||
- Ne **jamais** utiliser les credentials OAuth d'un abonnement consumer pour servir une application à plusieurs utilisateurs. Anthropic l'interdit explicitement (ToS) ; les autres le tolèrent moins ouvertement mais le principe est identique. Risque concret : bannissement du compte si détecté.
|
||||
- Pour toute application applicative (chatbot, intégration produit), prendre une **API key séparée**, indépendante de l'abonnement consumer.
|
||||
|
||||
---
|
||||
|
||||
<a id="pattern-prompt-caching-system-prompt-stable"></a>
|
||||
## Prompt caching obligatoire dès qu'un gros system prompt est stable
|
||||
|
||||
Tout système ayant un system prompt volumineux et stable (knowledge base, format de sortie, persona) DOIT activer le prompt caching côté fournisseur. La portion cachée est facturée à une fraction du tarif normal (ordre de grandeur : ~10 %), ce qui divise le coût input par 5 à 10 sur un usage où le system prompt domine.
|
||||
|
||||
```ts
|
||||
// OpenAI : promptCacheKey via provider metadata
|
||||
streamText({
|
||||
model: openai("gpt-4.1-mini"),
|
||||
system: bigStaticPrompt,
|
||||
experimental_providerMetadata: {
|
||||
openai: { promptCacheKey: "myapp-system-v1" },
|
||||
},
|
||||
});
|
||||
|
||||
// Anthropic : marquage explicite des blocs cacheables dans messages (cache_control)
|
||||
```
|
||||
|
||||
### Conséquences sur les coûts
|
||||
|
||||
- Le **coût marginal** d'un nouvel utilisateur est quasi nul tant que le system prompt domine le volume de tokens.
|
||||
- Pour un usage léger (quelques conversations/jour, prompt caching actif), prévoir un budget mensuel de l'ordre de quelques euros.
|
||||
- Toujours poser un **budget cap** côté console fournisseur pour éviter toute dérive.
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user