expria-frontend/docs/ONBOARDING.md

345 lines
11 KiB
Markdown

# ONBOARDING.md — Expria Frontend
> **Temps de lecture : 25 minutes.**
> Ce document te permet de prendre en main le projet et de commencer à contribuer.
> Si tu ne l'as pas encore lu, commence par `ARCHITECTURE.md`.
---
## 1. Contexte produit (2 min)
Expria est une application web de coaching pour l'examen TCF Canada, destinée aux francophones qui préparent leur immigration au Canada via Express Entry. Les utilisateurs viennent principalement d'Algérie, du Maroc, du Cameroun et sont quasi exclusivement sur mobile.
**Fonctionnalités clés :**
- Simulation des 6 tâches de l'examen (EE T1/T2/T3 + EO T1/T2/T3)
- Correction automatique par IA (DeepSeek pour les textes, Gemini pour l'audio)
- Rapport détaillé selon le plan de l'utilisateur (free / standard / premium)
- Dialogue oral temps réel avec un examinateur IA (feature Premium exclusive)
- Mode examen chronométré (Premium)
**Monétisation :** abonnement via Stripe (Standard 19,90€/4 semaines, Premium 39,90€/4 semaines).
---
## 2. Installation (5 min)
### Prérequis
- Node.js 20 LTS ou supérieur
- npm 10+ (ou pnpm 9+ si tu préfères)
- Git
- Un compte GitHub avec accès au dépôt `germannoff/expria-frontend`
### Étapes
```bash
git clone https://github.com/germannoff/expria-frontend.git
cd expria-frontend
npm install
cp .env.example .env
# Remplis .env avec les vraies valeurs (voir section 3)
npm run dev
```
L'application devrait être accessible sur `http://localhost:5173`.
### Commandes principales
```bash
npm run dev # dev server avec HMR
npm run build # build production (sortie dans dist/)
npm run preview # preview du build de production
npm run typecheck # vérification TypeScript stricte
npm run test # tests Vitest (une passe)
npm run test:watch # tests Vitest en mode watch
npm run lint # ESLint
npm run format # Prettier (écriture)
```
---
## 3. Variables d'environnement
Crée un fichier `.env` à la racine en copiant `.env.example` :
```
VITE_API_URL=https://api.expria.app
VITE_SUPABASE_URL=https://<project>.supabase.co
VITE_SUPABASE_ANON_KEY=<clé publique Supabase>
VITE_ENABLE_T2_LIVE=false
VITE_SENTRY_DSN= (optionnel)
```
Les valeurs de développement te seront transmises par Hermann ou via un coffre-fort (1Password, Bitwarden).
**Ne JAMAIS committer `.env`.** Le fichier est dans `.gitignore`.
**Ne JAMAIS mettre de clé privée** (Supabase Service Role, Stripe Secret, Gemini API Key) côté frontend. Ces clés n'existent que dans le backend.
---
## 4. Structure du projet (5 min)
La règle essentielle : **trois couches hiérarchiques**, et les dépendances ne remontent jamais.
```
app/ ← peut importer de : entities, features, shared
features/ ← peut importer de : entities, shared
entities/ ← peut importer de : shared
shared/ ← ne doit RIEN importer d'autre
```
### Où mettre quoi ?
| Tu écris... | Ça va dans... |
|---|---|
| Un type métier (`Plan`, `Production`, `Report`) | `src/entities/<domaine>/types.ts` |
| Une fonction pure métier (`hasAccess`, `canSimulate`, `applyFloutage`) | `src/entities/<domaine>/lib.ts` |
| Un appel API vers le backend | `src/entities/<domaine>/api.ts` |
| Un composant de page | `src/features/<feature>/pages/` |
| Un composant UI spécifique à une feature | `src/features/<feature>/components/` |
| Un hook React spécifique à une feature | `src/features/<feature>/hooks/` |
| Un composant UI générique (`Button`, `Modal`) | `src/shared/components/ui/` |
| Un helper technique (`apiFetch`, `getAccessToken`) | `src/shared/lib/` |
| Un hook utilitaire (`useDebounce`) | `src/shared/hooks/` |
### Exemple concret
Tu veux ajouter une feature "historique des paiements". Tu crées :
```
src/entities/billing/types.ts # type Payment
src/entities/billing/api.ts # GET /billing/payments
src/features/billing/pages/PaymentHistoryPage.tsx
src/features/billing/hooks/usePaymentHistory.ts
```
Tu n'importes rien de `features/` dans `entities/`. Jamais. C'est la règle d'or.
---
## 5. Règles absolues (5 min)
### Règle A — Permissions
**Interdit :**
```typescript
if (plan === 'premium') { ... }
if (user.plan !== 'free') { ... }
if (PLANS[plan].exam_mode) { ... }
```
**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()
}
```
Pourquoi ? Voir ADR 005.
### Règle B — Appels API
**Interdit :**
```typescript
fetch('https://api.expria.app/simulations') // oubli du token, pas de retry
supabase.from('productions').select() // contourne le backend
```
**Obligatoire :**
```typescript
import { apiFetch } from '@/shared/lib/api-client'
const response = await apiFetch<Production[]>('/simulations', { method: 'GET' })
if (response.error) {
// gérer l'erreur selon response.error.code
}
```
### Règle C — Logique métier
**Interdit :** mettre des règles métier dans un composant React.
```typescript
// ❌ Dans une page
{user.plan === 'free' && productions.length >= 5 && <Paywall />}
```
**Obligatoire :** extraire dans `entities/` :
```typescript
// entities/user/lib.ts
export function canSimulate(plan: Plan, used: number) { ... }
// features/dashboard/pages/DashboardPage.tsx
const { allowed } = canSimulate(plan, simulationsUsed)
{!allowed && <Paywall reason={reason} />}
```
### Règle D — Clés privées
Aucune clé privée dans le frontend. Aucune. Si tu as un doute, c'est que c'est privé.
### Règle E — Supabase côté frontend
Supabase est utilisé **uniquement** pour l'auth :
- `supabase.auth.signInWithPassword()`
- `supabase.auth.signOut()`
- `supabase.auth.getSession()` (via `auth-client.ts`)
Toute lecture/écriture de données métier passe par le backend Hono. **Jamais** de `supabase.from('productions')` côté frontend.
### Règle F — Workflow de dev
1. **Lire** `ARCHITECTURE.md` + `DEVELOPMENT_PRINCIPLES.md` + `PLANS_TARIFAIRES.md`
2. **Plan** avant code — tu produis un plan détaillé, tu attends validation
3. **Code** — maximum 3 fichiers par étape
4. **Test**`npm run typecheck && npm run test` vert
5. **Golden Dataset** — rejouer les tests manuels concernés
6. **Commit** — message clair (`feat:`, `fix:`, `refactor:`)
---
## 6. Points d'entrée à connaître (5 min)
### Fichiers que tu liras en premier
| Fichier | Rôle |
|---|---|
| `src/app/main.tsx` | Entry point React |
| `src/app/providers.tsx` | Wrappers globaux (QueryClient, Router, etc.) |
| `src/app/router.tsx` | Toutes les routes de l'app |
| `src/entities/user/access.ts` | Source de vérité des plans — **copie exacte du backend** |
| `src/entities/user/lib.ts` | `hasAccess()` et `canSimulate()` |
| `src/shared/lib/api-client.ts` | Wrapper fetch avec retry, timeout, logging |
| `src/shared/lib/auth-client.ts` | Gestion du token Supabase |
| `src/features/dashboard/hooks/usePlan.ts` | Hook central pour le plan utilisateur |
### Comptes de test
Voir `docs/TEST_ENVIRONMENT.md` (copie du backend). Résumé :
| Email | Plan | Usage |
|---|---|---|
| test.free@gmail.com | free | Parcours Free normal |
| test.standard@gmail.com | standard | Parcours Standard |
| test.premium@gmail.com | premium | Parcours Premium |
| test.quota@gmail.com | free (5/5) | Blocage quota |
Mot de passe commun : `Expria2025!test`.
---
## 7. Workflow Claude Code (3 min)
Le projet est développé avec assistance IA (Claude Code, Cursor). Le fondateur Hermann est non-technique — le workflow est strict pour éviter les dérives.
### Début de session
```
"Je commence une session sur expria-frontend.
Lis dans l'ordre :
1. docs/ARCHITECTURE.md
2. docs/DEVELOPMENT_PRINCIPLES.md
3. docs/PLANS_TARIFAIRES.md
4. docs/PARCOURS_UTILISATEURS.md (section du plan concerné)
Puis annonce : 'Documents lus, voici mon plan pour cette session.'
Ne commence à coder qu'après validation du plan."
```
### Pendant la session
- L'IA propose un plan → Hermann valide → l'IA code → l'IA lance les tests → l'IA présente un résumé.
- Maximum 3 fichiers par étape. Si plus : découper.
- Tests rouges = on arrête et on corrige avant de continuer.
### Fin de session
- Résumé des modifications
- Tests Golden Dataset manuels rejoués
- Mise à jour de `docs/CHANGELOG.md`
- Commit Git avec message clair
---
## 8. Quand tu ne sais pas quoi faire
### Ordre de recherche
1. Lire le document de référence concerné (`ARCHITECTURE.md`, `DEVELOPMENT_PRINCIPLES.md`, ADRs)
2. Chercher un pattern existant dans le code (grep sur le nom de la feature)
3. Vérifier les parcours utilisateurs (`PARCOURS_UTILISATEURS.md`)
4. Demander à Hermann avant d'inventer une solution
### Les pièges classiques
| Piège | Solution |
|---|---|
| "Je vais mettre cette règle dans le composant, c'est plus simple" | Non. Ça va dans `entities/<domaine>/lib.ts`. |
| "Je vais appeler Supabase directement pour éviter l'appel backend" | Non. Le backend est l'autorité. |
| "Je vais tester avec `if (plan === 'premium')` juste pour déboguer" | Non, même temporairement. Utilise `hasAccess`. |
| "Je vais ajouter Zustand, ce sera plus propre" | Non, voir ADR 003. Discute-en avant. |
| "Je vais modifier `access.ts` sans toucher au backend" | Non. `access.ts` doit rester identique des deux côtés. |
---
## 9. Ressources
### Documents de référence (dans ce dépôt)
- `docs/ARCHITECTURE.md` — architecture technique
- `docs/DEVELOPMENT_PRINCIPLES.md` — règles de dev
- `docs/SECURITY.md` — sécurité + patterns interdits
- `docs/PLANS_TARIFAIRES.md` — source de vérité des plans
- `docs/PARCOURS_UTILISATEURS.md` — parcours détaillés par plan
- `docs/GOLDEN_DATASET.md` — tests manuels
- `docs/adr/` — décisions architecturales motivées
### Documents backend (dans `expria-backend/docs/`)
Les documents de référence du backend existent en miroir. Les règles y sont les mêmes, adaptées au contexte serveur.
### Docs externes
- [React Router v6](https://reactrouter.com/en/main)
- [TanStack Query](https://tanstack.com/query/latest)
- [shadcn/ui](https://ui.shadcn.com/)
- [Tailwind CSS](https://tailwindcss.com/)
- [Vitest](https://vitest.dev/)
- [Vite](https://vitejs.dev/)
---
## 10. Premier ticket pour te faire la main
Quand tu arrives sur le projet, voici une suggestion de premier ticket pour te familiariser :
> **Ajouter un affichage du nombre de simulations restantes pour un utilisateur Free dans le header du Dashboard.**
>
> Critères d'acceptation :
> - Utiliser `usePlan()` pour obtenir le plan et `simulations_used`
> - Utiliser `canSimulate()` pour déterminer s'il en reste
> - Afficher "X/5 simulations restantes" pour les free, rien pour les standard/premium
> - Pas de `if (plan === 'free')` dans le code
> - Test unitaire de la logique
>
> Ce ticket touche : `entities/user/lib.ts`, `features/dashboard/components/`, `features/dashboard/pages/`. Trois fichiers — parfait pour une session.
---
Bienvenue dans Expria. Bonne route !
---
## 11. Historique
| Version | Date | Changements |
|---|---|---|
| 1.0 | 2026-04-17 | Création initiale |