- Lien d'inscription protégé par un jeton (FormTemplate.access_token, /inscription/<token>), avec régénération depuis l'écran de configuration. - Reçus fiscaux mécénat (cerfa 11580*05) : un PDF par bénévole ayant payé en mécénat, donateur/montant (chiffres et toutes lettres en français, app/mecenat/number_words.py)/date complétés par-dessus le modèle officiel. - Jeu de démonstration : bénévoles avec cotisation classique ou mécénat payée. - Infobulles (HelpTip et détail de cellule de la grille des besoins) repositionnées en position: fixed via JS, bornées à l'écran. - Revue de sécurité : logo des emails en pièce jointe inline au lieu d'une URL (fuyait le jeton d'inscription), sujet retiré du log de remise des emails (pouvait porter un nom de bénévole), photo du formulaire public revalidée par décodage réel avant stockage, export Excel protégé contre l'injection de formule, sondage du statut de paiement limité en fréquence, pyjwt mis à jour. Co-Authored-By: Claude Sonnet 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