docs: ajouter ONBOARDING, SECURITY, CHANGELOG, ADR 001-006

This commit is contained in:
Hermann_Kitio 2026-04-17 18:35:15 +03:00
parent 28c9c08d31
commit 52b8e9d011
9 changed files with 1380 additions and 0 deletions

View file

@ -0,0 +1,68 @@
# ADR 001 — Hébergement frontend : Cloudflare Pages
**Statut :** Accepté
**Date :** 2026-04-17
**Décideur :** Hermann
---
## Contexte
Le frontend Expria V2 doit être hébergé sur une plateforme de distribution statique. Trois options étaient envisagées : Vercel, Cloudflare Pages, et un VPS.
Contraintes à prendre en compte :
- L'audience cible est majoritairement en Afrique du Nord (Algérie, Maroc) et en Afrique centrale (Cameroun), avec une part importante au Canada. Presque 100% mobile.
- Le DNS de `expria.app` est actuellement géré chez Vercel.
- Le backend tourne déjà sur Render Frankfurt (EU).
- Le projet est maintenu par un fondateur non-technique, avec assistance IA.
- Les revenus sont encore nuls ou quasi nuls — les coûts d'infrastructure doivent rester à zéro.
## Options envisagées
### Option A — Vercel
- Avantages : DNS déjà configuré chez Vercel, auto-deploy GitHub natif sans config, edge nodes à Paris et Francfort.
- Inconvénients : tarif gratuit limité en bande passante si le produit décolle, verrouillage progressif dans l'écosystème Vercel (edge functions, middleware), fondateur a déjà exprimé un veto personnel contre Vercel suite à frictions passées.
### Option B — Cloudflare Pages
- Avantages : CDN mondial (287+ points de présence, y compris Casablanca et Le Caire), tier gratuit généreux (builds illimités, bande passante illimitée), cohérent avec la recommandation initiale d'`ARCHITECTURE.md` backend §2, découplé du DNS (on peut migrer le DNS sans changer l'hébergement).
- Inconvénients : déploiement via Wrangler CLI légèrement moins transparent que Vercel, auto-deploy GitHub nécessite une config initiale.
### Option C — VPS (dans la continuité du backend)
- Avantages : un seul fournisseur, contrôle total.
- Inconvénients : fait perdre tout le bénéfice CDN (les utilisateurs africains rapatrient les assets depuis Frankfurt), charge opérationnelle (nginx, certificats, mise à jour OS), gaspille les ressources VPS.
## Décision
**Cloudflare Pages** pour l'hébergement frontend.
Configuration cible :
- Source : dépôt GitHub `germannoff/expria-frontend`
- Build command : `npm run build`
- Output directory : `dist`
- Domaine : `expria.app` (CNAME depuis le DNS Vercel vers Cloudflare Pages, le DNS reste chez Vercel jusqu'à nouvel ordre)
- Déploiement : auto-deploy à chaque push sur `main` (configuration Cloudflare Pages ↔ GitHub)
## Conséquences
**Positives :**
- Coût zéro quelle que soit la montée en charge initiale.
- Latence optimisée pour l'audience cible (CDN proche des utilisateurs africains).
- Cohérent avec le document de référence backend `ARCHITECTURE.md` §2.
- Indépendance vis-à-vis de Vercel (DNS reste séparé de l'hébergement).
**Négatives :**
- Une commande CLI supplémentaire (`wrangler`) à connaître pour les déploiements manuels d'urgence. Mitigation : l'auto-deploy GitHub résout ce point à 95%.
- Si le fondateur doit un jour déployer manuellement sans accès au terminal, il devra passer par le dashboard Cloudflare Pages.
**À revisiter si :**
- L'audience bascule massivement vers un continent non couvert par Cloudflare (improbable).
- Cloudflare Pages impose des limites qui contraignent le produit (scénarios edge à étudier si on ajoute du server-side rendering plus tard).
## Références
- `ARCHITECTURE.md` backend §2 et §9 (recommandation initiale Cloudflare Pages)
- `TECH_DEBT.md` TD-04 (déploiement manuel — rendu caduc par la réactivation du compte GitHub le 2026-04-17)

View file

@ -0,0 +1,78 @@
# ADR 002 — Découplage auth-client et api-client
**Statut :** Accepté
**Date :** 2026-04-17
**Décideur :** Hermann
---
## Contexte
Le frontend doit :
1. Obtenir un token JWT auprès de Supabase (authentification).
2. Envoyer ce token au backend Hono sur chaque requête API (autorisation).
L'approche initiale proposée était un seul fichier `api-client.ts` contenant un intercepteur qui appelle directement le SDK Supabase pour récupérer le token avant chaque requête. Cette approche couple fortement le client HTTP à Supabase.
## Options envisagées
### Option A — API client avec intercepteur Supabase intégré
```typescript
// api-client.ts
import { supabase } from './supabase'
async function apiFetch(path: string) {
const { data } = await supabase.auth.getSession()
return fetch(`${API_URL}${path}`, {
headers: { Authorization: `Bearer ${data.session?.access_token}` }
})
}
```
- Avantages : code court, un seul fichier, familier aux développeurs juniors.
- Inconvénients : couple définitivement l'HTTP layer à Supabase, rend impossible le test du client API sans mocker Supabase entier, bloque toute migration future d'auth (ex : passage à Auth0, Clerk, auth maison).
### Option B — Deux fichiers distincts
```typescript
// auth-client.ts (connaît Supabase, rien d'autre)
export async function getAccessToken(): Promise<string | null> { ... }
// api-client.ts (connaît HTTP, rien d'autre)
export async function apiFetch<T>(path: string, options: RequestOptions = {}): Promise<T> {
const token = options.token ?? await getAccessToken()
// fetch avec Bearer token
}
```
- Avantages : séparation des responsabilités claire (auth vs HTTP), chaque fichier testable indépendamment, migration d'auth = modifier un seul fichier, respecte le principe d'inversion de dépendance.
- Inconvénients : deux fichiers au lieu d'un (impact négligeable).
## Décision
**Option B** — deux fichiers séparés :
- `src/shared/lib/auth-client.ts` : gère exclusivement Supabase Auth (login, logout, register, récupération du token, refresh de session).
- `src/shared/lib/api-client.ts` : gère exclusivement les appels HTTP vers `api.expria.app` (fetch, retry, timeout, logging, parsing d'erreurs).
L'api-client appelle `getAccessToken()` depuis l'auth-client, mais n'importe aucun type ni fonction Supabase directement.
## Conséquences
**Positives :**
- Un dev qui arrive comprend en 30 secondes : "ici l'auth, ici l'HTTP".
- Le test de `api-client.ts` ne nécessite pas de mocker Supabase — on injecte un token factice.
- Si Supabase est remplacé un jour (peu probable mais possible), seul `auth-client.ts` change. Aucun fichier feature n'est touché.
- Cohérent avec la Règle 1 de `DEVELOPMENT_PRINCIPLES.md` : séparation stricte des responsabilités.
**Négatives :**
- Un fichier supplémentaire. Coût négligeable.
**À revisiter si :**
- Un besoin de couplage fort émerge (ex : un token custom généré par le backend plutôt que Supabase). Dans ce cas, la séparation reste valide — on change juste l'implémentation interne de `getAccessToken()`.
## Références
- `DEVELOPMENT_PRINCIPLES.md` Règle 1 (séparation stricte)
- `ARCHITECTURE.md` §10 Règle 1 (le frontend ne contient aucune logique métier)

View file

@ -0,0 +1,62 @@
# ADR 003 — Pas de Zustand pour la V2
**Statut :** Accepté
**Date :** 2026-04-17
**Décideur :** Hermann
---
## Contexte
Question posée : faut-il introduire un store global (Zustand, Jotai, Redux Toolkit) dès le scaffold du frontend, en prévision de la complexité future du produit ?
Arguments en faveur d'une intégration précoce :
- La T2 Live a une state machine complexe (idle → connecting → listening → speaking → processing → ended/error).
- Plusieurs composants pourraient devoir lire le plan utilisateur actuel.
- Un produit "scalable" justifierait une gestion d'état "moderne".
## Options envisagées
### Option A — Zustand dès le départ
- Avantages : prêt le jour où on en aura besoin, un seul endroit pour l'état global.
- Inconvénients : dépendance supplémentaire à maintenir, code plus abstrait pour des cas qui ne la nécessitent pas, risque que les devs "poussent" de l'état dans le store par réflexe même quand `useState` suffit.
### Option B — Pas de store global, stratégie en trois couches
- **État serveur** → TanStack Query (cache, refetch, invalidation après webhook Stripe).
- **État T2 Live**`useReducer` local avec une state machine explicite, dans `features/t2-live/hooks/useT2LiveSession.ts`.
- **État UI local**`useState` / `useContext` pour les cas simples (ex : ouverture d'une modal).
- Avantages : zéro dépendance supplémentaire, chaque composant gère son propre état, TanStack Query couvre 90% des besoins (tout ce qui vient du serveur).
- Inconvénients : si plusieurs composants non-parents ont besoin de partager un état client complexe (non-serveur), il faudra passer par React Context ou migrer vers Zustand à ce moment-là.
## Décision
**Option B** — pas de store global pour la V2.
Règle d'introduction future : Zustand (ou équivalent) ne sera introduit que si un cas concret apparaît où plusieurs composants non-parents partagent un état client complexe qui ne peut pas être géré par TanStack Query ni par un Context React local. Jusque là, on s'en passe.
## Conséquences
**Positives :**
- Une dépendance en moins dans `package.json`.
- Un nouveau dev ne se demande pas "pourquoi Zustand pour un produit aussi simple ?".
- Évite le piège classique : dès qu'un store global existe, les devs y poussent tout, y compris ce qui devrait rester local. Le résultat est un store-spaghetti.
- TanStack Query gère déjà la synchronisation serveur → UI, ce qui couvre le plan utilisateur, les productions, les rapports, l'historique.
**Négatives :**
- Si un besoin complexe de partage d'état client apparaît tôt, il faudra migrer. Mitigation : TanStack Query + Context suffisent dans 95% des cas prévisibles.
**À revisiter si :**
- Un composant du header doit réagir en temps réel à un événement du composant de simulation (sans passer par le serveur).
- La state machine T2 Live devient partagée entre plusieurs écrans (peu probable).
- L'application a plus de 10 écrans avec de l'état client partagé complexe.
Dans ces cas, introduire Zustand sera une session dédiée avec migration progressive — pas une réécriture.
## Références
- ADR 002 (API client découplé)
- TanStack Query docs — stratégie de cache
- `ARCHITECTURE.md` §4 (structure `features/` + `shared/`)

View file

@ -0,0 +1,93 @@
# ADR 004 — Types partagés par duplication contrôlée
**Statut :** Accepté
**Date :** 2026-04-17
**Décideur :** Hermann
---
## Contexte
Le frontend Expria et le backend Expria sont dans deux dépôts GitHub séparés (`expria-frontend` et `expria-backend`). Plusieurs types TypeScript doivent exister à l'identique des deux côtés :
- `Plan` (`'free' | 'standard' | 'premium'`)
- `PlanPermissions` (l'objet de l'objet `PLANS`)
- `Production` (enregistrement d'une simulation)
- `Report` (rapport de correction)
- `ApiResponse<T>` (contrat de réponse normalisé)
Sans synchronisation, ces types divergent, ce qui cause des bugs subtils (ex : un champ renommé dans le backend mais pas dans le frontend).
## Options envisagées
### Option A — Monorepo avec pnpm workspaces ou Turborepo
- Avantages : un seul dépôt, types partagés via un package `@expria/types`, refactor global en une seule PR.
- Inconvénients : restructuration massive (les dépôts actuels sont indépendants, chacun avec son propre CI/CD sur Render et Cloudflare Pages), courbe d'apprentissage pour un fondateur non-technique, complexité des commandes (`pnpm --filter frontend run dev`), incompatibilité avec le workflow Claude Code actuel (une session = un dépôt).
### Option B — Package npm publié (`@expria/types`)
- Avantages : types versionnés, installable comme n'importe quelle dépendance.
- Inconvénients : publication sur npm (privé = $7/mois/dev, public = expose la structure du produit), versioning à gérer, friction de workflow (publier une nouvelle version à chaque changement).
### Option C — Génération automatique via `tsc --declaration`
- Avantages : les types sont dérivés directement du code backend, pas de divergence possible.
- Inconvénients : pipeline de build à maintenir entre les deux dépôts, chaque modification backend nécessite un commit dans frontend pour régénérer les types, fragile au démarrage.
### Option D — Duplication manuelle avec commentaire source
- Avantages : zéro infrastructure, chaque dépôt reste autonome, compatible avec le workflow Claude Code actuel.
- Inconvénients : discipline humaine requise pour synchroniser à chaque changement backend.
## Décision
**Option D** — duplication manuelle, avec règle de discipline stricte.
### Format imposé
Chaque fichier de types dupliqué commence par :
```typescript
// SOURCE OF TRUTH: expria-backend/src/types/<fichier>.ts
// Synchronisé le : YYYY-MM-DD
// Si ce fichier diverge du backend, le frontend doit être mis à jour immédiatement.
```
### Règle de synchronisation
Tout changement de type dans le backend **doit** être répercuté dans le frontend dans le même commit logique (même jour, même session de travail). Cette règle est intégrée à `DEVELOPMENT_PRINCIPLES.md` frontend.
### Liste des fichiers concernés
- `src/entities/user/types.ts``expria-backend/src/types/plan.ts`
- `src/entities/production/types.ts``expria-backend/src/types/production.ts`
- `src/entities/report/types.ts``expria-backend/src/types/report.ts`
- `src/shared/types/api.ts``expria-backend/src/types/api.ts`
### Fichier critique particulier
`src/entities/user/lib/access.ts` doit être **identique au bit près** à `expria-backend/src/lib/access.ts`. Cette règle est inscrite dans `ARCHITECTURE.md` §10 Règle 2 backend — on l'étend au frontend.
## Conséquences
**Positives :**
- Zéro infrastructure, zéro outillage à maintenir.
- Chaque dépôt reste autonome (cohérent avec le choix de dépôts séparés — `ARCHITECTURE.md` backend §3).
- Workflow Claude Code inchangé (une session = un dépôt).
- Coût zéro.
**Négatives :**
- Discipline humaine requise. Si la règle n'est pas respectée, divergence silencieuse possible.
- Mitigation : ajouter dans `GOLDEN_DATASET.md` frontend un test de cohérence minimal — appeler `/plans/status` et vérifier que la structure retournée correspond aux types frontend.
**À revisiter si :**
- Un dev senior rejoint l'équipe et préfère un monorepo pnpm (décision à prendre avec lui).
- Le projet stabilise ses types (6-12 mois de production sans changement de schéma). À ce moment, un package `@expria/types` devient viable.
- Les divergences silencieuses causent plus de 2 bugs en production.
## Références
- `ARCHITECTURE.md` backend §3 (dépôts séparés)
- `ARCHITECTURE.md` backend §10 Règle 2 (source de vérité unique pour `access.ts`)
- `DEVELOPMENT_PRINCIPLES.md` frontend (règle de synchronisation à ajouter)

View file

@ -0,0 +1,149 @@
# ADR 005 — Fonctions d'accès : alias frontend-idiomatiques sur l'API backend
**Statut :** Accepté
**Date :** 2026-04-17
**Décideur :** Hermann
**Révision :** 2 (après audit backend du 2026-04-17)
---
## Contexte
La vérification des permissions selon le plan utilisateur est la logique la plus critique du frontend. Une erreur ici = une feature Premium accessible gratuitement, ou à l'inverse un utilisateur payant bloqué.
La Règle D de `DEVELOPMENT_PRINCIPLES.md` l'énonce clairement : **jamais de `if (plan === 'premium')` dans le code**. Toute vérification passe par un helper centralisé.
L'audit backend du 2026-04-17 a confirmé que `src/lib/access.ts` expose trois fonctions :
```typescript
export function getPlanPermissions(plan: Plan): Permissions
export function canUserSimulate(user: { plan: string; simulations_used: number }): { allowed, reason? }
export function checkFeatureAccess(plan: Plan, feature: Feature): boolean
```
## Contrainte dictée par l'ADR 004
Le fichier `src/entities/user/access.ts` côté frontend **doit être identique au bit près** à `expria-backend/src/lib/access.ts`. Cette règle est non négociable : elle garantit qu'un changement de permission dans le backend est impossible à rater côté frontend.
## Options envisagées
### Option 1 — Noms strictement identiques partout
Frontend utilise directement `canUserSimulate()` et `checkFeatureAccess()` dans tout le code.
- **Avantages :** un seul nom par fonction dans tout le projet, pas d'indirection, grep universel.
- **Inconvénients :** `checkFeatureAccess` est verbeux en JSX, le nom `canUserSimulate` est backend-coloré (prend un `user`, pas un plan), ces noms ne sont pas les standards React (`hasRole`, `hasPermission`, `hasAccess`).
### Option 2 — Alias frontend-idiomatiques dans `entities/user/lib.ts`
`access.ts` reste identique au backend. Un fichier séparé `lib.ts` ré-exporte les fonctions sous des noms plus courts et idiomatiques React.
```typescript
// src/entities/user/access.ts — IDENTIQUE au backend
export function getPlanPermissions(plan) { /* ... */ }
export function canUserSimulate(user) { /* ... */ }
export function checkFeatureAccess(plan, feature) { /* ... */ }
// src/entities/user/lib.ts — alias pour le frontend
import {
canUserSimulate,
checkFeatureAccess,
getPlanPermissions,
} from './access'
/**
* Alias frontend-idiomatique de checkFeatureAccess.
* Vérifie si un plan a accès à une feature booléenne donnée.
*/
export const hasAccess = checkFeatureAccess
/**
* Alias frontend-idiomatique de canUserSimulate.
* Signature ergonomique (plan, used) au lieu de ({ plan, simulations_used }).
*/
export function canSimulate(plan: Plan, simulationsUsed: number) {
return canUserSimulate({ plan, simulations_used: simulationsUsed })
}
/**
* Ré-export direct — même nom qu'au backend.
*/
export { getPlanPermissions }
```
- **Avantages :** `access.ts` strictement identique au backend (ADR 004 respecté à 100%), le code frontend utilise `hasAccess` et `canSimulate` (standards React), signature ergonomique côté frontend.
- **Inconvénients :** une légère indirection (`Ctrl+click` sur `hasAccess` mène à un ré-export). Bénéfice net : la lisibilité des composants React.
## Décision
**Option 2** — alias frontend-idiomatiques dans `entities/user/lib.ts`, par-dessus un `access.ts` strictement identique au backend.
### Emplacement du code
```
src/entities/user/
├── access.ts # COPIE BIT-À-BIT de expria-backend/src/lib/access.ts
└── lib.ts # Alias et helpers frontend-spécifiques
```
### Règle d'utilisation dans le code frontend
**Interdit :**
```typescript
if (plan === 'premium') { ... }
if (PLANS[plan].exam_mode) { ... }
if (!user.plan === 'free' && simulations_used > 5) { ... }
```
**Obligatoire :**
```typescript
import { hasAccess, canSimulate } from '@/entities/user/lib'
if (hasAccess(plan, 'exam_mode')) { ... }
const { allowed, reason } = canSimulate(plan, simulationsUsed)
if (!allowed) {
if (reason === 'quota_reached') openUpgradeModal()
}
```
### Règle de maintenance
Toute modification de `access.ts` doit être faite **simultanément** dans les deux dépôts (backend et frontend) dans le même commit logique. Si une fonction est ajoutée ou renommée côté backend, un alias équivalent peut être ajouté dans `lib.ts` **seulement si** le nom backend est inconfortable en contexte React. Sinon, import direct.
### Tests associés (obligatoires)
```
src/entities/user/__tests__/access.test.ts # teste les 3 fonctions backend (parité)
src/entities/user/__tests__/lib.test.ts # teste hasAccess et canSimulate (alias)
```
Au minimum :
- `checkFeatureAccess` / `hasAccess` : 14+ assertions
- `canUserSimulate` / `canSimulate` : 7+ assertions
- `getPlanPermissions` : 4 assertions (3 plans + plan invalide)
Ces tests calquent leur structure sur `TESTS_AUTOMATISES.md` backend pour garantir la parité des comportements.
## Conséquences
**Positives :**
- `access.ts` strictement identique au backend : impossible de diverger par accident.
- Code frontend lisible et idiomatique : `hasAccess(plan, 'exam_mode')` dans un composant React se lit naturellement.
- Un dev React qui arrive trouve les noms qu'il cherche.
- Extension automatique : ajouter une permission dans `PLANS` la rend immédiatement accessible via `hasAccess`.
- `canSimulate` a une signature plus ergonomique côté frontend.
**Négatives :**
- Indirection légère : `Ctrl+click` sur `hasAccess` mène à `lib.ts`, puis un deuxième clic est nécessaire pour arriver à `access.ts`. Mitigation : documenté dans `ONBOARDING.md` + commentaire JSDoc sur chaque alias.
**À revisiter si :**
- Une troisième catégorie de valeurs apparaît dans `PLANS` (ni booléen ni quota).
- Un dev senior trouve que les alias ajoutent plus de friction que de valeur.
## Références
- `PLANS_TARIFAIRES.md` §3 (objet `PLANS` source de vérité)
- ADR 004 (règle de duplication de `access.ts`)
- `TESTS_AUTOMATISES.md` backend §3, §4, §5 (tests de parité)
- Audit backend du 2026-04-17 (confirmation du contenu de `access.ts`)

View file

@ -0,0 +1,160 @@
# ADR 006 — Stack frontend : versions 2026 (React 19, Vite 8, TypeScript 6, Tailwind 4, RR7)
**Statut :** Accepté
**Date :** 2026-04-17
**Décideur :** Hermann
**Contexte :** Révélé par l'état des lieux Claude Code au démarrage du Sprint 0 frontend
---
## Contexte
La première version d'`ARCHITECTURE.md` §2 listait une stack basée sur les versions "connues stables" :
- React 18
- Vite 5
- TypeScript 5
- Tailwind 3
- React Router v6
L'état des lieux effectué par Claude Code au démarrage du Sprint 0 (2026-04-17) a révélé que le scaffold installé plusieurs semaines auparavant utilisait des versions plus récentes :
- React 19.2.4
- Vite 8.0.4
- TypeScript 6.0.2
- Tailwind 4.2.2
- React Router v7.14.1
Cette divergence doit être résolue : soit downgrader le scaffold, soit mettre à jour la documentation.
## Options envisagées
### Option A — Downgrader vers les versions de la doc originale
Aligner le scaffold sur React 18, Vite 5, TypeScript 5, Tailwind 3, React Router v6.
- **Avantages :** documentation historique respectée, versions "éprouvées" en production.
- **Inconvénients :**
- Casse un `node_modules` qui fonctionne
- Perd l'optimisation du compilateur React 19 (Actions, useOptimistic)
- Perd le moteur Oxide de Tailwind 4 (builds 3,5x plus rapides)
- Perd le typage strict amélioré de TypeScript 6
- Downgrade effectué pour des raisons qui n'existent plus (les versions récentes sont matures en avril 2026)
### Option B — Mettre à jour la documentation
Accepter les versions installées et mettre à jour `ARCHITECTURE.md §2` pour refléter la réalité.
- **Avantages :**
- Préserve le travail de scaffold déjà fait
- Bénéficie des améliorations de performance des versions récentes
- Écosystème mature : shadcn/ui supporte complètement Tailwind 4 et React 19 depuis début 2025
- Alignement avec l'écosystème 2026 (les nouveaux tutoriels, docs, et ressources communautaires supposent ces versions)
- **Inconvénients :**
- Versions légèrement plus récentes = moins de StackOverflow disponible pour les cas exotiques
- Mitigation : Claude Opus 4.7 connaît bien ces versions (cf. knowledge cutoff janvier 2026)
### Option C — Hybride
Garder React 19, Vite 8, TypeScript 6 mais downgrader Tailwind 4 → 3 pour "compatibilité shadcn/ui classique".
- **Avantages :** apparemment plus prudent.
- **Inconvénients :** injustifié depuis que shadcn/ui supporte complètement Tailwind 4 avec configuration CSS-first via `@theme`. Ajoute de la complexité sans bénéfice.
## Décision
**Option B** — accepter les versions installées et mettre à jour la documentation.
### Stack frontend officielle au 2026-04-17
| Couche | Version | Notes |
|---|---|---|
| React | 19.2.x | Server Components N/A (SPA pur), Actions et useOptimistic disponibles |
| React DOM | 19.2.x | |
| Vite | 8.0.x | Moteur Rolldown stable, config simplifiée |
| TypeScript | 6.0.x | Typage strict activé (voir tsconfig.app.json) |
| Tailwind CSS | 4.2.x | Configuration CSS-first via `@theme`, pas de `tailwind.config.ts` |
| `@tailwindcss/vite` | 4.2.x | Plugin Vite officiel (préféré au plugin PostCSS) |
| React Router | v7.14.x | Compatible API v6, data loaders disponibles |
| Supabase JS | 2.103.x | |
### Dépendances à ajouter lors du scaffold
| Package | Rôle | Cf. ADR |
|---|---|---|
| `@tanstack/react-query` | Cache serveur, refetch, mutations | ARCHITECTURE.md §2 |
| `zod` | Validation des inputs formulaires | SECURITY.md SEC-04 |
| `react-markdown` | Rendu sécurisé des rapports IA | SECURITY.md SEC-05 |
| `class-variance-authority`, `clsx`, `tailwind-merge` | Utilitaires shadcn/ui | — |
| `lucide-react` | Icônes (standard shadcn/ui) | — |
| Packages `@radix-ui/react-*` | Primitives shadcn/ui (installés à la demande) | — |
| `@sentry/react` | Monitoring | TECH_DEBT.md FTD-07 (après MVP) |
### Dépendances de développement
| Package | Rôle |
|---|---|
| `vitest` | Tests unitaires |
| `@vitest/coverage-v8` | Couverture |
| `@testing-library/react` | Tests React |
| `@testing-library/jest-dom` | Matchers DOM |
| `@testing-library/user-event` | Simulation user |
| `jsdom` | Environnement DOM pour Vitest |
| `prettier` | Formatage |
| `eslint-config-prettier` | Intégration ESLint ↔ Prettier |
### Configuration Tailwind 4
Pas de `tailwind.config.ts`. La configuration se fait exclusivement dans `src/index.css` via les directives :
```css
@import "tailwindcss";
@theme {
--color-primary: #1B4FD8; /* Couleur brand Expria */
--font-sans: "Plus Jakarta Sans", system-ui, sans-serif;
/* Autres variables de thème */
}
```
### shadcn/ui avec Tailwind 4
La CLI shadcn/ui supporte Tailwind 4 depuis début 2025 :
```bash
npx shadcn@latest init
npx shadcn@latest add button dialog form
```
Les composants générés utilisent les conventions Tailwind 4 (pas de `forwardRef`, attributs `data-slot`). Le fichier de configuration reste `components.json` à la racine.
## Conséquences
**Positives :**
- Pas de perte de travail sur le scaffold existant
- Performances optimales (build Tailwind 4 : microsecondes sur builds incrémentaux)
- Stack aligné sur l'écosystème 2026 — facile pour un dev externe qui arrivera
- Compilateur React 19 apporte des optimisations gratuites
**Négatives :**
- Les versions récentes peuvent avoir quelques bugs non encore découverts. Mitigation : mise à jour ponctuelle vers la dernière version patch en cas de bug signalé (ex : 19.2.4 → 19.2.5).
- Si un dev arrive avec une expertise sur React 17/18 uniquement, courbe d'apprentissage légère. Mitigation : `ONBOARDING.md` liste les ressources officielles pour React 19 et Tailwind 4.
**À revisiter si :**
- Une faille de sécurité critique apparaît dans une version spécifique
- Une incompatibilité bloquante est découverte entre deux packages (peu probable en avril 2026)
## Actions de mise en cohérence
1. Mettre à jour `ARCHITECTURE.md §2` avec les versions ci-dessus (réalisé en session actuelle)
2. Mettre à jour `ONBOARDING.md` pour référencer React 19 et Tailwind 4 dans les ressources (à faire)
3. Aucune action sur `TESTS_AUTOMATISES.md` — Vitest fonctionne identiquement
4. Aucune action sur les ADRs 001-005 — ils ne référencent pas de versions précises
## Références
- État des lieux Claude Code du 2026-04-17
- [shadcn/ui Tailwind v4](https://ui.shadcn.com/docs/tailwind-v4) — support officiel confirmé
- [React 19 Upgrade Guide](https://react.dev/blog/2024/04/25/react-19)
- [Tailwind CSS v4.0](https://tailwindcss.com/blog/tailwindcss-v4)
- `ARCHITECTURE.md` §2 (mis à jour en parallèle)