feat(corrections/eo): évaluation phonologique Gemini — 5 critères × /4 (Sprint 4.8)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
34b4bcdd82
commit
ec0598d122
15 changed files with 2086 additions and 290 deletions
509
docs/ARCHITECTURE-backend.md
Normal file
509
docs/ARCHITECTURE-backend.md
Normal file
|
|
@ -0,0 +1,509 @@
|
|||
# ARCHITECTURE.md — Expria / Coach TCF Canada
|
||||
|
||||
> **Document de référence — Version 1.2**
|
||||
> Ce document décrit l'architecture technique complète du projet.
|
||||
> Toute décision architecturale majeure doit être documentée ici avant d'être implémentée.
|
||||
> À lire conjointement avec PLANS_TARIFAIRES.md et PARCOURS_UTILISATEURS.md.
|
||||
|
||||
---
|
||||
|
||||
## 1. Vue d'ensemble
|
||||
|
||||
Expria est une application web SaaS de coaching TCF Canada, construite sur une architecture
|
||||
frontend / backend séparés, avec une pièce dédiée pour la fonctionnalité temps réel (T2 EO live).
|
||||
|
||||
```
|
||||
Utilisateur (navigateur)
|
||||
↓
|
||||
┌─────────────────────────────┐
|
||||
│ FRONTEND │
|
||||
│ React + Vite │
|
||||
│ Cloudflare Pages (gratuit) │
|
||||
└─────────────┬───────────────┘
|
||||
│ appels API REST
|
||||
┌─────────────▼───────────────┐
|
||||
│ BACKEND │
|
||||
│ Hono.js (Node.js) │
|
||||
│ Render (Frankfurt) │
|
||||
│ — toutes les routes API │
|
||||
│ — WebSocket proxy T2 EO │
|
||||
└──────┬──────────────┬───────┘
|
||||
│ │
|
||||
┌──────▼──────┐ ┌────▼────────────────┐
|
||||
│ Supabase │ │ APIs externes │
|
||||
│ PostgreSQL │ │ — DeepSeek (EE/EO) │
|
||||
│ Auth │ │ — Gemini (audio) │
|
||||
│ Storage │ │ — Stripe (paiement)│
|
||||
└─────────────┘ └─────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Décisions architecturales
|
||||
|
||||
### Pourquoi frontend séparé (React + Vite) et non Next.js
|
||||
|
||||
Next.js est un framework full-stack qui mélange frontend et backend dans le même projet.
|
||||
Ce mélange a été la principale source de chaos dans la version précédente d'Expria :
|
||||
régressions fréquentes, difficultés à tester, couplage fort entre affichage et logique métier.
|
||||
|
||||
React + Vite est un frontend pur — il ne fait qu'afficher et appeler des API.
|
||||
Il ne connaît pas Supabase, ne connaît pas Gemini, ne connaît pas Stripe.
|
||||
Il reçoit des données depuis le backend et les affiche. C'est tout.
|
||||
|
||||
### Pourquoi Hono.js pour le backend
|
||||
|
||||
Hono est un framework backend moderne, léger, TypeScript natif, conçu pour Node.js.
|
||||
Il offre une structure claire de routes, middlewares, et contrôleurs — similaire à Express
|
||||
mais plus moderne et mieux typé. Il tourne sur Render sans configuration particulière.
|
||||
|
||||
### Pourquoi Render pour le backend (et non Cloudflare Workers)
|
||||
|
||||
La T2 EO live nécessite une connexion WebSocket persistante entre le serveur et Gemini Live API,
|
||||
pouvant durer plusieurs minutes. Cloudflare Workers impose une durée d'exécution maximale
|
||||
incompatible avec cette contrainte. Render supporte nativement les connexions WebSocket longue durée.
|
||||
|
||||
### Pourquoi Cloudflare Pages pour le frontend
|
||||
|
||||
Le frontend est un ensemble de fichiers statiques (HTML, CSS, JS). Cloudflare Pages les distribue
|
||||
depuis un CDN mondial — latence minimale pour les utilisateurs en Algérie, Maroc, Cameroun.
|
||||
Tier gratuit, déploiement automatique depuis GitHub.
|
||||
|
||||
### Pourquoi Supabase est conservé
|
||||
|
||||
Supabase fournit trois services critiques déjà en production :
|
||||
- Authentification complète (email, OAuth Google/Apple, sessions JWT)
|
||||
- Base de données PostgreSQL avec Row Level Security
|
||||
- Stockage de fichiers (enregistrements audio EO)
|
||||
|
||||
Remplacer Supabase par une Render DB nue demanderait de recoder l'authentification
|
||||
et les politiques de sécurité de zéro — un coût disproportionné sans bénéfice.
|
||||
|
||||
---
|
||||
|
||||
## 3. Structure des dépôts
|
||||
|
||||
Deux dépôts GitHub séparés :
|
||||
|
||||
```
|
||||
expria-frontend/ → React + Vite
|
||||
expria-backend/ → Hono.js
|
||||
```
|
||||
|
||||
Supabase est géré via son propre dashboard et CLI (migrations SQL versionnées).
|
||||
|
||||
### Pourquoi deux dépôts séparés
|
||||
|
||||
- Claude Code travaille sur un périmètre clair : frontend OU backend, jamais les deux en même temps
|
||||
- Une modification frontend ne peut pas casser le backend par accident
|
||||
- Déploiements indépendants : on peut déployer le frontend sans toucher au backend
|
||||
|
||||
---
|
||||
|
||||
## 4. Structure des dossiers
|
||||
|
||||
### Frontend — expria-frontend/
|
||||
|
||||
```
|
||||
expria-frontend/
|
||||
├── public/ # Assets statiques (favicon, images)
|
||||
├── src/
|
||||
│ ├── api/ # Fonctions d'appel API (une par domaine)
|
||||
│ │ ├── auth.ts # Appels auth (login, logout, register)
|
||||
│ │ ├── simulations.ts # Appels simulations (créer, récupérer)
|
||||
│ │ ├── corrections.ts # Appels corrections (rapport, score)
|
||||
│ │ ├── plans.ts # Appels plans (upgrade, status)
|
||||
│ │ └── stripe.ts # Appels paiement (checkout, prorata)
|
||||
│ ├── components/ # Composants React réutilisables
|
||||
│ │ ├── ui/ # Composants génériques (Button, Modal, Badge)
|
||||
│ │ ├── simulation/ # Composants spécifiques aux simulations
|
||||
│ │ ├── rapport/ # Composants d'affichage des rapports
|
||||
│ │ ├── dashboard/ # Composants du dashboard utilisateur
|
||||
│ │ └── paywall/ # Composants de blocage / upgrade
|
||||
│ ├── pages/ # Pages de l'application (une par route)
|
||||
│ │ ├── Home.tsx # Page d'accueil (visiteur non connecté)
|
||||
│ │ ├── Login.tsx # Connexion / inscription
|
||||
│ │ ├── Dashboard.tsx # Dashboard utilisateur (tous plans)
|
||||
│ │ ├── Simulation.tsx # Interface de simulation (EE + EO)
|
||||
│ │ ├── Rapport.tsx # Affichage d'un rapport de correction
|
||||
│ │ ├── Methodologie.tsx # Page méthodologie
|
||||
│ │ ├── Tarifs.tsx # Page tarifaire
|
||||
│ │ └── T2Live.tsx # Interface T2 EO live (Premium uniquement)
|
||||
│ ├── hooks/ # Hooks React personnalisés
|
||||
│ │ ├── useAuth.ts # Gestion de l'authentification
|
||||
│ │ ├── usePlan.ts # Lecture du plan actuel + permissions
|
||||
│ │ ├── useSimulation.ts # Logique de simulation
|
||||
│ │ └── useT2Live.ts # Connexion WebSocket T2 live
|
||||
│ ├── lib/
|
||||
│ │ ├── access.ts # Source de vérité des permissions par plan
|
||||
│ │ ├── supabase.ts # Client Supabase (auth uniquement côté frontend)
|
||||
│ │ └── constants.ts # Constantes globales (URLs, config)
|
||||
│ ├── types/ # Types TypeScript partagés
|
||||
│ │ ├── plans.ts # Types Plan, Permission
|
||||
│ │ ├── simulation.ts # Types Simulation, Tache, Production
|
||||
│ │ └── rapport.ts # Types Rapport, Critere, Score
|
||||
│ ├── App.tsx # Router principal
|
||||
│ └── main.tsx # Point d'entrée
|
||||
├── .env.example # Variables d'environnement (sans valeurs)
|
||||
├── vite.config.ts
|
||||
├── tsconfig.json
|
||||
└── package.json
|
||||
```
|
||||
|
||||
### Backend — expria-backend/
|
||||
|
||||
```
|
||||
expria-backend/
|
||||
├── src/
|
||||
│ ├── routes/ # Définition des routes API (une par domaine)
|
||||
│ │ ├── auth.ts # POST /auth/verify-token
|
||||
│ │ ├── simulations.ts # POST /simulations, GET /simulations/:id
|
||||
│ │ ├── corrections.ts # POST /corrections/ee, POST /corrections/eo
|
||||
│ │ ├── plans.ts # GET /plans/status, POST /plans/upgrade
|
||||
│ │ ├── stripe.ts # POST /stripe/checkout, POST /stripe/webhook
|
||||
│ │ └── t2live.ts # WebSocket /t2/live (T2 EO proxy Gemini)
|
||||
│ ├── controllers/ # Logique métier (une par domaine)
|
||||
│ │ ├── simulationController.ts
|
||||
│ │ ├── correctionController.ts
|
||||
│ │ ├── planController.ts
|
||||
│ │ ├── stripeController.ts
|
||||
│ │ └── t2LiveController.ts
|
||||
│ ├── middleware/ # Middlewares Hono
|
||||
│ │ ├── auth.ts # Vérification JWT Supabase
|
||||
│ │ ├── plan.ts # Vérification des permissions par plan
|
||||
│ │ └── rateLimit.ts # Limitation des appels API
|
||||
│ ├── lib/
|
||||
│ │ ├── supabase.ts # Client Supabase admin (service role)
|
||||
│ │ ├── deepseek.ts # Client DeepSeek (corrections EE/EO)
|
||||
│ │ ├── gemini.ts # Client Gemini (transcription audio)
|
||||
│ │ ├── stripe.ts # Client Stripe
|
||||
│ │ └── access.ts # Copie de la source de vérité des plans
|
||||
│ ├── types/ # Types TypeScript partagés
|
||||
│ └── index.ts # Point d'entrée Hono
|
||||
├── .env.example
|
||||
├── tsconfig.json
|
||||
└── package.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Tables Supabase
|
||||
|
||||
### Table : profiles
|
||||
|
||||
Créée automatiquement à l'inscription. Liée à `auth.users`.
|
||||
|
||||
```sql
|
||||
CREATE TABLE profiles (
|
||||
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
email TEXT NOT NULL,
|
||||
plan TEXT NOT NULL DEFAULT 'free'
|
||||
CHECK (plan IN ('free', 'standard', 'premium')),
|
||||
simulations_used INTEGER NOT NULL DEFAULT 0,
|
||||
stripe_customer_id TEXT,
|
||||
stripe_subscription_id TEXT,
|
||||
plan_expires_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Trigger : mise à jour automatique de updated_at
|
||||
CREATE OR REPLACE FUNCTION update_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN NEW.updated_at = NOW(); RETURN NEW; END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER profiles_updated_at
|
||||
BEFORE UPDATE ON profiles
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
|
||||
|
||||
-- RLS : chaque utilisateur ne voit que son propre profil
|
||||
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY "Utilisateur voit son profil"
|
||||
ON profiles FOR SELECT
|
||||
USING (auth.uid() = id);
|
||||
|
||||
CREATE POLICY "Utilisateur modifie son profil"
|
||||
ON profiles FOR UPDATE
|
||||
USING (auth.uid() = id);
|
||||
```
|
||||
|
||||
### Table : productions
|
||||
|
||||
Enregistrement de chaque simulation soumise pour correction.
|
||||
|
||||
```sql
|
||||
CREATE TABLE productions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
|
||||
tache TEXT NOT NULL
|
||||
CHECK (tache IN ('EE_T1','EE_T2','EE_T3','EO_T1','EO_T3','EO_T2_LIVE')),
|
||||
mode TEXT NOT NULL
|
||||
CHECK (mode IN ('entrainement', 'examen')),
|
||||
contenu TEXT, -- texte pour EE, transcript pour EO
|
||||
audio_url TEXT, -- URL Supabase Storage (EO uniquement)
|
||||
score NUMERIC(4,1), -- score /20
|
||||
nclc INTEGER, -- niveau NCLC estimé
|
||||
rapport JSONB, -- rapport complet (critères, erreurs, tips)
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Index pour les requêtes fréquentes
|
||||
CREATE INDEX productions_user_id_idx ON productions(user_id);
|
||||
CREATE INDEX productions_created_at_idx ON productions(created_at DESC);
|
||||
|
||||
-- RLS
|
||||
ALTER TABLE productions ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY "Utilisateur voit ses productions"
|
||||
ON productions FOR SELECT
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
CREATE POLICY "Utilisateur crée ses productions"
|
||||
ON productions FOR INSERT
|
||||
WITH CHECK (auth.uid() = user_id);
|
||||
```
|
||||
|
||||
### Table : pattern_analyses
|
||||
|
||||
Résultats de l'analyse des patterns (Premium — 5 dernières productions).
|
||||
|
||||
```sql
|
||||
CREATE TABLE pattern_analyses (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
|
||||
productions_ids UUID[] NOT NULL, -- IDs des 5 productions analysées
|
||||
patterns JSONB NOT NULL, -- erreurs récurrentes détectées
|
||||
exercises JSONB NOT NULL, -- exercices long terme générés
|
||||
preparation_index INTEGER, -- indice de préparation 0-100
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
ALTER TABLE pattern_analyses ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY "Utilisateur voit ses analyses"
|
||||
ON pattern_analyses FOR SELECT
|
||||
USING (auth.uid() = user_id);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Routes API backend
|
||||
|
||||
### Authentification
|
||||
```
|
||||
POST /auth/verify-token Vérifie le JWT Supabase, retourne le profil + plan
|
||||
```
|
||||
|
||||
### Simulations
|
||||
```
|
||||
POST /simulations Crée une simulation, vérifie les quotas selon le plan
|
||||
GET /simulations/:id Récupère une simulation par ID
|
||||
GET /simulations Liste les simulations de l'utilisateur connecté
|
||||
```
|
||||
|
||||
### Corrections
|
||||
```
|
||||
POST /corrections/ee Soumet une production EE pour correction (DeepSeek)
|
||||
POST /corrections/eo Soumet une production EO pour correction (Gemini)
|
||||
```
|
||||
|
||||
### Plans
|
||||
```
|
||||
GET /plans/status Retourne le plan actuel + permissions de l'utilisateur
|
||||
POST /plans/upgrade Crée une session Stripe Checkout (nouveau abonnement)
|
||||
POST /plans/upgrade-prorata Upgrade en cours d'abonnement (prorata Stripe)
|
||||
```
|
||||
|
||||
### Stripe
|
||||
```
|
||||
POST /stripe/checkout Crée une Checkout Session Stripe
|
||||
POST /stripe/webhook Reçoit les events Stripe (checkout, invoice, deleted)
|
||||
```
|
||||
|
||||
### T2 EO Live
|
||||
```
|
||||
WS /t2/live WebSocket — proxy Gemini Live API (Premium uniquement)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Flux de données clés
|
||||
|
||||
### Flux : Simulation EE (mode entraînement)
|
||||
|
||||
```
|
||||
1. Frontend → POST /simulations (créer la simulation, vérifier quota)
|
||||
2. Backend → Supabase profiles (vérifier plan + simulations_used)
|
||||
3. Backend → POST /corrections/ee (envoyer à DeepSeek)
|
||||
4. DeepSeek → Backend (rapport JSON)
|
||||
5. Backend → Supabase productions (enregistrer production + rapport)
|
||||
6. Backend → Frontend (retourner le rapport)
|
||||
7. Frontend → Afficher selon le plan (rapport complet ou flouté)
|
||||
```
|
||||
|
||||
### Flux : Paiement nouveau abonnement
|
||||
|
||||
```
|
||||
1. Frontend → POST /stripe/checkout (créer Checkout Session)
|
||||
2. Backend → Stripe API (session avec price_id)
|
||||
3. Stripe → Frontend (redirect vers page paiement Stripe)
|
||||
4. Utilisateur paie
|
||||
5. Stripe → POST /stripe/webhook (checkout.session.completed)
|
||||
6. Backend → Supabase profiles (plan = 'standard' ou 'premium')
|
||||
7. Frontend → Redirect dashboard (plan mis à jour)
|
||||
```
|
||||
|
||||
### Flux : Upgrade Standard → Premium (prorata)
|
||||
|
||||
```
|
||||
1. Frontend → POST /plans/upgrade-prorata
|
||||
2. Backend → Stripe API (subscription.update + preview invoice)
|
||||
3. Backend → Frontend (montant prorata calculé)
|
||||
4. Frontend → Confirmation utilisateur (affiche le montant exact)
|
||||
5. Frontend → POST /plans/upgrade-prorata (confirmation)
|
||||
6. Backend → Stripe API (subscription.update confirmé)
|
||||
7. Stripe → POST /stripe/webhook (invoice.paid)
|
||||
8. Backend → Supabase profiles (plan = 'premium')
|
||||
9. Frontend → Dashboard Premium (accès immédiat)
|
||||
```
|
||||
|
||||
### Flux : T2 EO Live (WebSocket)
|
||||
|
||||
```
|
||||
1. Frontend → WS /t2/live (connexion WebSocket, JWT vérifié)
|
||||
2. Backend → Vérification plan (premium uniquement)
|
||||
3. Backend → WS Gemini Live API (ouverture connexion avec GEMINI_API_KEY)
|
||||
4. Frontend → Backend → Gemini (audio candidat en temps réel)
|
||||
5. Gemini → Backend → Frontend (audio examinateur IA en temps réel)
|
||||
6. Fin dialogue
|
||||
7. Backend → POST Gemini REST (évaluation de la session)
|
||||
8. Backend → Supabase productions (enregistrement production + rapport)
|
||||
9. Backend → Frontend (rapport complet)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Variables d'environnement
|
||||
|
||||
### Frontend (.env)
|
||||
```
|
||||
VITE_API_URL=https://api.expria.app # URL du backend Render
|
||||
VITE_SUPABASE_URL=https://xxx.supabase.co
|
||||
VITE_SUPABASE_ANON_KEY=xxx # Clé publique uniquement
|
||||
```
|
||||
|
||||
### Backend (.env)
|
||||
```
|
||||
# Supabase
|
||||
SUPABASE_URL=https://xxx.supabase.co
|
||||
SUPABASE_SERVICE_ROLE_KEY=xxx # Clé privée — ne jamais exposer
|
||||
|
||||
# APIs
|
||||
DEEPSEEK_API_KEY=xxx
|
||||
GEMINI_API_KEY=xxx # Ne jamais exposer côté frontend
|
||||
|
||||
# Stripe
|
||||
STRIPE_SECRET_KEY=xxx # Clé privée Stripe
|
||||
STRIPE_WEBHOOK_SECRET=xxx # Secret webhook Stripe
|
||||
STRIPE_PRICE_STANDARD=price_xxx # price_id plan Standard
|
||||
STRIPE_PRICE_PREMIUM=price_xxx # price_id plan Premium
|
||||
|
||||
# Config
|
||||
PORT=3000
|
||||
APP_URL=https://expria.app
|
||||
API_URL=https://api.expria.app
|
||||
NODE_ENV=production
|
||||
```
|
||||
|
||||
> **Règle absolue :** aucune clé privée (SUPABASE_SERVICE_ROLE_KEY, GEMINI_API_KEY,
|
||||
> STRIPE_SECRET_KEY) ne doit jamais se retrouver dans le frontend ou dans un commit Git.
|
||||
|
||||
---
|
||||
|
||||
## 9. Déploiement
|
||||
|
||||
### Hébergement Git — GitHub
|
||||
|
||||
- Plateforme : github.com
|
||||
- Dépôt frontend : `https://github.com/germannoff/expria-frontend`
|
||||
- Dépôt backend : `https://github.com/germannoff/expria-backend`
|
||||
- Note : compte GitHub réactivé le 17 avril 2026 après restriction OFAC levée
|
||||
- Auto-deploy : disponible via Render (connecté à GitHub)
|
||||
|
||||
### Frontend — Cloudflare Pages
|
||||
|
||||
- Source : dépôt GitHub `expria-frontend`
|
||||
- Build command : `npm run build`
|
||||
- Output directory : `dist`
|
||||
- Domaine : `expria.app` (DNS pointé depuis Vercel vers Cloudflare Pages)
|
||||
- Déploiement : **manuel via Cloudflare Pages CLI**
|
||||
|
||||
```bash
|
||||
# Commande de déploiement frontend
|
||||
npm run build
|
||||
npx wrangler pages deploy dist --project-name=expria
|
||||
```
|
||||
|
||||
### Backend — Render
|
||||
|
||||
- Source : dépôt GitHub `expria-backend`
|
||||
- Type : Web Service (Node.js)
|
||||
- Région : Frankfurt (EU) — proximité utilisateurs Afrique du Nord
|
||||
- Build command : `npm run build`
|
||||
- Start command : `npm start`
|
||||
- Domaine : `api.expria.app` (certificat SSL actif)
|
||||
- URL Render : `https://expria-backend.onrender.com` (alias)
|
||||
- WebSocket : activé nativement sur Render
|
||||
- Déploiement : **automatique à chaque push sur main (GitHub → Render)**
|
||||
|
||||
### Base de données — Supabase
|
||||
|
||||
- Région : Frankfurt (EU)
|
||||
- Migrations : versionnées dans `supabase/migrations/`
|
||||
- Déploiement : `supabase db push` (manuel, après validation)
|
||||
|
||||
### Procédure de déploiement complète
|
||||
|
||||
```
|
||||
1. Tester localement (npm run test — tous les tests verts)
|
||||
2. Rejouer le Golden Dataset
|
||||
3. Commit + push sur GitHub (branche main)
|
||||
4. Backend : auto-deploy Render déclenché automatiquement
|
||||
5. Déployer le frontend : npm run build && npx wrangler pages deploy dist
|
||||
6. Vérifier les URLs de production (expria.app + api.expria.app)
|
||||
7. Rejouer le Smoke Test (Groupe Z du Golden Dataset)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Règles de développement
|
||||
|
||||
### Règle 1 — Séparation stricte
|
||||
Le frontend ne contient aucune logique métier.
|
||||
Il appelle le backend et affiche ce qu'il reçoit.
|
||||
Toute vérification de plan, de quota, de droit d'accès se fait côté backend.
|
||||
|
||||
### Règle 2 — Source de vérité unique des plans
|
||||
`lib/access.ts` existe dans les deux dépôts (frontend et backend).
|
||||
Le fichier doit être identique dans les deux.
|
||||
Toute modification des plans tarifaires met à jour ce fichier en premier,
|
||||
dans les deux dépôts, avant tout autre changement de code.
|
||||
|
||||
### Règle 3 — Jamais plus de 3 fichiers touchés par session Claude
|
||||
Si une modification nécessite de toucher plus de 3 fichiers,
|
||||
elle doit être découpée en plusieurs sessions avec validation intermédiaire.
|
||||
|
||||
### Règle 4 — Plan avant code
|
||||
Claude Code ne commence jamais à coder sans avoir d'abord produit
|
||||
un plan détaillé (fichiers impactés, risques, étapes).
|
||||
Le plan est validé par Hermann avant l'exécution.
|
||||
|
||||
### Règle 5 — Tests manuels après chaque session
|
||||
Après chaque session Claude Code, rejouer le golden dataset
|
||||
(voir GOLDEN_DATASET.md) avant de passer à la session suivante.
|
||||
|
||||
### Règle 6 — Variables d'environnement
|
||||
Aucune valeur de variable d'environnement n'est jamais écrite en dur dans le code.
|
||||
Toujours lire depuis `process.env` (backend) ou `import.meta.env` (frontend).
|
||||
Loading…
Add table
Add a link
Reference in a new issue