Frontend : consommation de l'API CRUD (matrice, affectations, validation)

Remplace le magasin d'état fabriqué par une vraie couche API typée, alignée
sur le back-end (Étape 5) :

- src/api/ : schema.ts (miroir de backend/app/api/schemas.py), client HTTP,
  implémentation mock en mémoire (même surface + portage du moteur de
  validation), sélection mock/http via VITE_API_MODE, hooks React Query
  (lectures + mutations avec invalidation).
- Grille des besoins ← GET /matrix ; treillis de colonnes dérivé des
  créneaux réels (plus de plages figées).
- Panneau d'affectation ← GET /assignments?shift_id, POST /assignments/validate
  par candidat (alertes bloquantes / avertissements du moteur),
  POST / PATCH / DELETE /assignments.
- Vue par bénévole ← volunteers + shifts + assignments (surcharge / oubliés
  calculés côté client).
- Confirmations (ex-« Publication ») ← affectations PROPOSED ; publication
  versionnée et emails signalés hors périmètre.
- Mobiles ← assignments filtrées ; confirmation = PATCH ; pointage référent
  local (hors périmètre).
- Configuration ← positions & shifts CRUD (min/idéal, ajout/retrait),
  volunteers CRUD dont suppression RGPD ; messages = maquette locale.
- i18n mis à jour, aucun texte d'interface en dur.
- Vérifs : build tsc + vite, eslint (0 problème), npm run smoke (API mock +
  rendu headless des 6 écrans avec données préchargées).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwswqSChc3Rwtu61pRXiY2
This commit is contained in:
AdamThomas
2026-09-09 23:16:38 +02:00
co-authored by Claude Sonnet 5
parent ac469f0cd1
commit c9dda65361
38 changed files with 2930 additions and 2414 deletions
+51 -45
View File
@@ -2,63 +2,69 @@
React + Vite + TypeScript + Tailwind. Interface en français, code en anglais.
Intégration du design Claude Design « Bénévoles Festival »
(`Bénévoles Festival.dc.html`) : les 6 écrans du projet sont implémentés en
statique, pilotés par un **jeu de démonstration déterministe** (portage du
générateur du design). Le branchement sur l'API back-end est l'étape suivante.
Intègre le design Claude Design « Bénévoles Festival » et **consomme l'API
back-end** (`editions/{id}/volunteers · positions · shifts · assignments ·
assignments/validate · matrix`).
## Modes de données
`VITE_API_MODE` (voir `.env.example`) :
- **`mock`** (défaut) — jeu de démonstration déterministe **en mémoire**,
implémenté avec exactement la même surface que l'API (`src/api/mock/`).
Aucun back-end requis ; utile tant que le seed serveur n'existe pas.
- **`http`** — API réelle. `VITE_EDITION_ID` désigne l'édition ; en dev Vite
proxifie `/api` vers `VITE_API_TARGET` (défaut `http://localhost:8000`).
Le passage d'un mode à l'autre ne change **aucun** écran : tout passe par
`src/api/` (client HTTP ou mock) et les hooks React Query de `src/api/hooks.ts`.
## Écrans (onglets)
| # | Route | Écran |
|---|----------------------|----------------------------------------------------------|
| 01 | `/grille` | Grille des besoins (postes × jours × plages) + panneau d'affectation (candidats triés, alertes bloquantes / avertissements) |
| 02 | `/benevoles` | Vue par bénévole (affectations + disponibilités déclarées, surcharge / oubliés) |
| 03 | `/publication` | Différentiel brouillon ↔ version publiée, aperçu du message, publication |
| 04 | `/mobile-benevole` | Maquette mobile : planning personnel, confirmation de créneau |
| 05 | `/mobile-referent` | Maquette mobile : pointage de l'équipe sur le créneau en cours |
| 06 | `/configuration` | Grille des besoins, bénévoles & import, messages & envois, règles du festival |
| # | Route | Source de données | Actions |
|---|-------|-------------------|---------|
| 01 | `/grille` | `GET /matrix` | clic cellule → panneau : `GET /assignments?shift_id`, `POST /assignments/validate` par candidat, `POST` / `PATCH` / `DELETE /assignments` |
| 02 | `/benevoles` | `volunteers` + `shifts` + `assignments` | lecture (surcharge / oubliés calculés côté client) |
| 03 | `/publication` | `assignments` (statut `PROPOSED`) | lecture — publication versionnée & emails **hors périmètre** (CLAUDE.md §4) |
| 04 | `/mobile-benevole` | `assignments?volunteer_id` | `PATCH /assignments/{id}` (confirmer) |
| 05 | `/mobile-referent` | `assignments?shift_id` | pointage **local** (hors périmètre) |
| 06 | `/configuration` | | `positions` CRUD, `shifts` CRUD (min/idéal, ajout/retrait), `volunteers` CRUD (dont suppression RGPD). Messages = maquette locale. |
## Commandes
| Action | Commande |
|------------------------|-----------------------------|
| Installer | `npm install` |
| Dev (hot reload) | `npm run dev` → http://localhost:5173 |
| Build de production | `npm run build` |
| Lint | `npm run lint` |
| Vérif. de types | `npm run typecheck` |
| Rendu headless des 6 écrans | `npm run smoke` |
En dev, Vite proxifie `/api` vers le backend (`VITE_API_TARGET`, défaut
`http://localhost:8000`).
| Action | Commande |
|--------|----------|
| Installer | `npm install` |
| Dev | `npm run dev` → http://localhost:5173 |
| Build | `npm run build` |
| Lint | `npm run lint` |
| Types | `npm run typecheck` |
| Rendu headless + vérifs API mock | `npm run smoke` |
## Conventions
- **Aucun texte d'interface en dur.** Tout passe par `src/i18n` (`t(key, params)`)
et `src/i18n/locales/fr.json`. Les libellés *de données* (nom d'un poste,
d'une plage, d'une journée) sont portés par l'entité — ils viendront de l'API.
- Code, noms de fichiers et de variables en anglais. Alias `@/` → `src/`.
- Vocabulaire métier : glossaire FR ↔ EN de `CLAUDE.md`.
- Le moteur de validation (`src/domain/rules.ts`) reprend le contrat du back-end
(CLAUDE.md §3) : violations typées `BLOCKING` / `WARNING`, jamais de phrase.
- **Aucun texte d'interface en dur** : `src/i18n` (`t(key, params)`) + `locales/fr.json`.
- Les libellés *de données* (nom de poste, etc.) viennent de l'API.
- `src/api/schema.ts` est le miroir de `backend/app/api/schemas.py` — à garder synchrone.
- `violationText()` (`src/lib/planning.ts`) rend les violations du moteur ;
les `params` suivent le contrat de `backend/app/validation/engine.py`.
- Alias `@/` → `src/`.
## Arborescence
```
src/
├── main.tsx # point d'entrée (Router + PlanningProvider)
├── app/
│ ├── AppShell.tsx # en-tête + onglets + badge brouillon
│ ├── router.tsx # routes (tableau réutilisable)
│ └── planning-store.tsx # état + actions (reducer) sur le jeu de démo
├── domain/
│ ├── types.ts # modèle (aligné CLAUDE.md)
│ ├── festival.ts # jours, plages, helpers temps
│ ├── rules.ts # moteur de validation (portage back-end)
│ ├── selectors.ts # index des affectations, surcharge
│ └── publication.ts # différentiel de publication
├── mock/ # jeu de démonstration déterministe
├── components/ui.tsx # primitives visuelles (bordures/ombres franches)
├── pages/ # un fichier par écran (+ sous-dossiers grille/, config/, mobile/)
└── i18n/ # t() + locales/fr.json
├── main.tsx
├── api/
│ ├── schema.ts # types miroir du back-end
│ ├── types.ts # interface PlanningApi + ApiError
│ ├── http-client.ts # implémentation HTTP
│ ├── mock/ # implémentation mémoire (dataset + client + moteur)
│ ├── index.ts # sélection mock / http, EDITION_ID
│ └── hooks.ts # hooks React Query (lectures + mutations)
├── app/ AppShell (onglets) · router
├── pages/ un fichier par écran (+ grille/, config/, mobile/)
├── components/ ui.tsx (primitives) · state.tsx (Loading / ErrorNote)
├── lib/ time.ts · planning.ts (treillis, heures, surcharge, violationText) · env.ts · cx.ts
└── i18n/ t() + locales/fr.json
```