Nouvel onglet « Statistiques » (/statistiques, COORDINATION), alimenté
par GET /editions/{id}/stats (app/api/stats.py, recalculé à chaque appel,
aucune nouvelle entité) :
- inscriptions : total, 7 derniers jours, évolution cumulée par jour
- réponses : part des bénévoles ayant renseigné chaque information,
artistes les plus demandés
- cotisations : en ligne / sur place / aucune, montants par type,
mécénat, formulaires remplis sans paiement abouti
- besoins face aux bénévoles, par journée de festival : heures × personnes
demandées vs disponibilités déclarées vs affectées ; par poste, places
pourvues (plafonnées à l'effectif idéal de chaque créneau) et rapport
vœux / place
Graphiques SVG maison (components/charts.tsx) avec infobulles au survol
et au clavier, vue tableau pour chacun, palette validée (daltonisme,
contraste), mise en page vérifiée sur ordinateur et mobile. Le mock
calcule les mêmes chiffres et étale les inscriptions du jeu de démo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Frontend — Gestion des bénévoles
React + Vite + TypeScript + Tailwind. Interface en français, code en anglais.
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_IDdésigne l'édition ; en dev Vite proxifie/apiversVITE_API_TARGET(défauthttp://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.
Authentification & rôles
Toutes les pages métier sont derrière <RequireAuth> (src/auth/).
- Coordination →
/connexion/coordination: email + mot de passe (POST /editions/{id}/auth/login). - Référents / bénévoles →
/connexion: lien magique (POST …/auth/magic-linkpuis…/auth/verify). L'email étant stubé, le modemockaffiche directement le lien de démo à cliquer. - Le jeton JWT est stocké en
localStorage, envoyé enAuthorization: Bearersur chaque requête ; une réponse 401 déconnecte. - Comptes de démo (mode
mock) : coordinationcoordination@lessonsdautomne.fr/demo; référentsreferent1..3@lessonsdautomne.fr; chaque bénévole ayant un email.
Visibilité des onglets par rôle :
| Onglet | Coordination | Référent | Bénévole |
|---|---|---|---|
| 01 Grille · 02 Vue bénévole · 06 Configuration | ✅ | — | — |
| 04 Bénévole · mobile | — | — | ✅ |
| 05 Référent · mobile | — | ✅ | — |
L'accueil après connexion dépend du rôle (homePath).
Écrans (onglets)
Depuis l'Étape 9 back-end, une affectation n'a plus de statut : elle est valide dès sa création, la retirer = supprimer la ligne. Il n'y a donc plus d'écran « Confirmations » (ancien onglet 03).
| # | Route | Source de données | Actions |
|---|---|---|---|
| 01 | /grille |
GET /matrix (assigned / ideal) |
clic cellule → panneau : GET /assignments?shift_id, POST /assignments/validate par candidat, POST / DELETE /assignments |
| 02 | /benevoles |
volunteers + shifts + assignments |
lecture (surcharge / oubliés calculés côté client) |
| 04 | /mobile-benevole |
assignments?volunteer_id (du compte) |
lecture¹ |
| 05 | /mobile-referent |
poste du référent → assignments?shift_id |
pointage local (hors périmètre) |
| 06 | /configuration |
positions · shifts · volunteers |
CRUD postes / créneaux (min/idéal) / bénévoles (dont suppression RGPD) ; onglet Messages → POST /notifications/planning (récapitulatif + lien de connexion) |
¹ En mode http, l'API n'expose pas encore aux bénévoles le détail des
créneaux : l'écran dégrade proprement (créneaux sans détail, message d'info).
Fonctionne intégralement en mode mock.
Commandes
| 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 :
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.tsest le miroir debackend/app/api/schemas.py— à garder synchrone.violationText()(src/lib/planning.ts) rend les violations du moteur ; lesparamssuivent le contrat debackend/app/validation/engine.py.- Alias
@/→src/.
Arborescence
src/
├── main.tsx
├── api/
│ ├── schema.ts # types miroir du back-end (dont auth)
│ ├── types.ts # interface PlanningApi + ApiError
│ ├── session.ts # jeton Bearer partagé + callback 401
│ ├── http-client.ts # implémentation HTTP
│ ├── mock/ # implémentation mémoire (dataset + client + comptes + moteur)
│ ├── index.ts # sélection mock / http, EDITION_ID
│ └── hooks.ts # hooks React Query (lectures + mutations)
├── auth/ auth-context (AuthProvider/useAuth) · RequireAuth · roles
├── app/ AppShell (onglets filtrés par rôle) · router
├── pages/ un fichier par écran (+ auth/, 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