Commit Graph
27 Commits
Author SHA1 Message Date
AdamThomasandClaude Opus 5.5 461742eb78 Email de test et ajout manuel sans champ obligatoire
ci-cd / build-backend (push) Successful in 1m25s
ci-cd / build-frontend (push) Successful in 21s
ci-cd / deploy (push) Successful in 13s
Étape 67 : adresse + bouton dans l'onglet « Messages » pour envoyer tout
de suite un email de test, résultat réel affiché (envoyé, désactivé,
connexion ou message refusé, réponse du serveur SMTP) —
POST .../notifications/test.

Étape 66 : prénom et nom facultatifs à l'ajout manuel d'un bénévole ;
un bénévole sans nom s'affiche « Sans nom » / « ? » partout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 19:34:24 +01:00
AdamThomasandClaude Opus 5.5 c57c70569c Pointage enregistré et statistiques de présence
ci-cd / build-backend (push) Successful in 29s
ci-cd / build-frontend (push) Successful in 19s
ci-cd / deploy (push) Successful in 12s
Étape 58 : le présent / absent du référent est enregistré sur
l'affectation (Assignment.attendance + heure, migration 0030,
PUT .../assignments/{id}/attendance) au lieu de disparaître au
rechargement.

Étape 59 : section « Présence » de l'écran Statistiques — créneaux en
cours et créneaux terminés, par poste, rafraîchie toutes les 30 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 08:06:32 +01:00
AdamThomasandClaude Opus 5.5 6892e0307d Photo du bénévole ajoutée par la coordination
ci-cd / build-backend (push) Successful in 33s
ci-cd / build-frontend (push) Successful in 20s
ci-cd / deploy (push) Successful in 14s
Section « Photo » sur la fiche bénévole (ajouter / remplacer / retirer),
PUT/DELETE /editions/{id}/volunteers/{vid}/photo (COORDINATION),
validation de l'image partagée avec le formulaire public (read_photo).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 18:17:25 +01:00
AdamThomasandClaude Opus 5.5 d0fa1e109c Logs de diagnostic et rapprochement SumUp ↔ bénévole
ci-cd / build-backend (push) Successful in 38s
ci-cd / build-frontend (push) Successful in 20s
ci-cd / deploy (push) Successful in 13s
- Une ligne de log par requête (route modèle, statut, durée, code d'erreur,
  compte), identifiant X-Request-ID repris dans chaque log et affiché à
  l'utilisateur sous une erreur, exceptions non gérées tracées (500 JSON)
- Journal d'accès d'uvicorn coupé : il exposait le jeton du formulaire public
- Logs métier : paiement SumUp, connexion, import, plannings, solveur
- Nom du bénévole dans la description du checkout SumUp
- Code et identifiant de transaction SumUp enregistrés au paiement
  (migration 0023), affichés sur la fiche et dans l'export Excel

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:54:35 +02:00
AdamThomasandClaude Opus 5.5 d722a81a87 Retrait des disponibilités et des limites de temps dans la journée
ci-cd / build-backend (push) Successful in 31s
ci-cd / build-frontend (push) Successful in 19s
ci-cd / deploy (push) Successful in 12s
Disponibilités déclarées supprimées (table `availability`, migration 0022,
API, éditeur de la fiche bénévole, badge de couverture du panneau
d'affectation, colonnes des statistiques) ainsi que les règles
OUTSIDE_AVAILABILITY, DAILY_HOURS_EXCEEDED et INSUFFICIENT_REST, les malus
de disponibilité et de repos du solveur et le filtre « Surchargés » de la
vue bénévoles. Seul le chevauchement reste contrôlé. La case « je suis
disponible » du formulaire public est conservée.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 21:29:58 +02:00
AdamThomasandClaude Opus 5.5 ee1f6ed72e Écran Statistiques : inscriptions, réponses, cotisations et besoins
ci-cd / build-backend (push) Successful in 33s
ci-cd / build-frontend (push) Successful in 19s
ci-cd / deploy (push) Successful in 12s
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>
2026-10-04 19:40:46 +02:00
AdamThomasandClaude Opus 5.5 c49ce520e3 Type de paiement à montant libre (pensé pour le mécénat)
ci-cd / build-backend (push) Successful in 33s
ci-cd / build-frontend (push) Successful in 18s
ci-cd / deploy (push) Successful in 12s
FormPaymentOption.free_amount (migration 0021) : case « Montant libre »
sur l'écran Inscriptions ; le montant configuré devient le minimum et le
bénévole saisit le sien sur le formulaire public (payment_amount, virgule
ou point, 2 décimales max, plafond 10 000 € contre une faute de frappe —
422 form.invalid_free_amount sinon). Validé côté client avant l'envoi,
le serveur restant seul juge. Le montant choisi est celui du checkout
SumUp, recopié sur la fiche, l'email de confirmation et le cerfa.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:49:27 +02:00
AdamThomasandClaude Sonnet 5 096b7cd26a Lien d'inscription protégé par jeton, reçus fiscaux mécénat, infobulles et revue de sécurité
ci-cd / build-backend (push) Successful in 1m12s
ci-cd / build-frontend (push) Successful in 18s
ci-cd / deploy (push) Successful in 12s
- 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>
2026-10-02 07:47:17 +02:00
AdamThomasandClaude Sonnet 5 a2b748566b Inscription en deux temps, emails de confirmation et export Excel des bénévoles
ci-cd / build-backend (push) Successful in 30s
ci-cd / build-frontend (push) Successful in 18s
ci-cd / deploy (push) Successful in 12s
Formulaire public — paiement en ligne :
- Le bénévole n'est plus compté en base tant qu'un paiement en ligne choisi
  n'est pas confirmé (PendingFormSubmission, promu en Volunteer à la
  confirmation, webhook ou vérification en direct).
- Type de paiement « mécénat » : étape d'adresse postale avant le paiement,
  conservée sur le bénévole pour un reçu fiscal (cerfa) ultérieur.
- Page de confirmation au retour de SumUp, avec relance possible après
  échec/expiration sans ressaisir le formulaire.
- « Je paierai sur place » remplace « je ne participe pas » ; tous les
  champs activés par la coordination sont désormais obligatoires.
- La fiche bénévole n'affiche plus l'état des cases à cocher, seulement le
  résultat réel du paiement (libellé, montant, statut).

Emails :
- Email de confirmation d'inscription à la création du bénévole (tient lieu
  de reçu de paiement quand une cotisation est payée en ligne).
- Mise en forme HTML au thème de l'application (logo de l'édition en
  en-tête) pour tous les emails envoyés, texte brut conservé en repli.

Export Excel des bénévoles (COORDINATION) : coordonnées, vœux résolus en
noms lisibles, cotisation et mécénat.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 07:41:58 +02:00
AdamThomasandClaude Sonnet 5 0bd38a6465 Formulaire public : paiement de la cotisation via l'API SumUp (remplace Yapla)
ci-cd / build-backend (push) Failing after 4m12s
ci-cd / build-frontend (push) Skipped
ci-cd / deploy (push) Skipped
Remplace le simple lien Yapla statique par une vraie intégration API SumUp :
checkout hébergé créé à la soumission du formulaire, statut de paiement
(PENDING/PAID/FAILED/EXPIRED) tenu à jour par un webhook SumUp et visible sur
la fiche du bénévole. La cotisation n'est plus un montant unique : la
coordination configure autant de types de paiement qu'elle veut (libellé +
montant, ex. « Cotisation classique », « Mécénat »), et le bénévole en
choisit un à l'inscription — le libellé et le montant choisis sont figés sur
le bénévole, indépendamment d'une modification ultérieure de la config.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 19:56:04 +02:00
AdamThomasandClaude Sonnet 5 957a004623 Formulaire public : logo et texte d'introduction personnalisables
FormTemplate porte désormais un logo (image, PUT/GET .../form/logo — GET
public comme .../form/public, affiché sur /inscription) et un texte
d'introduction libre (PATCH .../form, description désormais optionnelle
comme is_open). Écran de configuration (/inscriptions) : nouveau panneau
« Personnalisation » pour importer le logo et rédiger le texte. Le
formulaire public affiche le logo en grand au-dessus du panneau et le
texte juste sous le titre.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 20:46:52 +02:00
AdamThomasandClaude Sonnet 5 40127a2252 Étape 22 : feuilles de poste (PDF), complément des badges
Une page par poste et par jour, listant les créneaux avec les bénévoles
affectés et leur téléphone — à imprimer et afficher sur place. Aucune
nouvelle entité : dérivé de Position/Shift/Assignment/Volunteer
existants (contrairement aux badges, pas de personnalisation à
configurer). Un créneau à besoin 0/0 sans affectation n'apparaît pas.

Backend : app/sheets/pdf.py (ReportLab, Platypus — SimpleDocTemplate/
Table plutôt que le canvas bas niveau des badges, plus adapté à un
rapport texte multi-pages), POST /editions/{id}/position-sheets/generate
(COORDINATION, {position_ids?} — absent = tous les postes).

Frontend : bouton « Feuilles de poste » dans la grille des besoins,
respecte le filtre de catégorie déjà actif à l'écran.

Vérifié : pytest (284 passés), ruff, alembic check, tsc --noEmit,
eslint, vite build, smoke (flux de bout en bout en mode démonstration)
— tous verts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 21:27:01 +02:00
AdamThomasandClaude Sonnet 5 82088f3b0c Étape 21 : formulaire public d'inscription des bénévoles
Retire « constructeur de formulaire » des exclusions du CLAUDE.md (§ 5) —
décision explicite prise en conversation.

Un formulaire par édition (COORDINATION choisit les champs actifs parmi
neuf : email, téléphone, vœux de poste — max 2, vœux d'artiste — un par
soir de festival, vœu de compagnon en texte libre, disponibilité/
cotisation déclaratives, photo, commentaire ; nom/prénom toujours
collectés) ouvert/fermé à volonté, avec un lien à partager
(/inscription, aucun compte requis).

Backend : FormTemplate/FormField (migration 0013), quatre nouveaux champs
sur Volunteer (photo, companion_wish_note, self_declared_available,
willing_to_pay_fee), app/api/forms.py — les deux seuls endpoints publics
de toute l'API (GET .../form/public, POST .../form/public/submit),
protégés par hCaptcha (app/forms/captcha.py, désactivé sans
HCAPTCHA_SECRET_KEY) et un filet de sécurité global par édition
(form_submission_limiter). resolve_owned_ids/set_artists/
set_wished_positions déplacés vers app/api/_common.py, partagés avec
volunteers.py.

Frontend : écran de configuration (/inscriptions) avec lien copiable et
bascule ouvert/fermé, formulaire public (/inscription, hors RequireAuth)
avec widget hCaptcha chargé dynamiquement, capture photo native
(<input capture>), vœux de poste/artiste avec les mêmes règles que le
back-end. Réponses du formulaire visibles et éditables depuis la fiche
bénévole existante (ConfigVolunteers.tsx).

Vérifié : pytest (273 passés), ruff, alembic check, tsc --noEmit, eslint,
vite build, smoke (rendu SSR de chaque écran + flux de bout en bout du
formulaire en mode démonstration) — tous verts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 20:24:32 +02:00
AdamThomasandClaude Sonnet 5 55c5d539a8 Badges : permettre d'agrandir le badge proportionnellement à l'image
Le format déduit de l'image importée (300 dpi supposés, étape
précédente) donne un badge minuscule pour une image à résolution web —
ajout d'un contrôle « largeur du badge (mm) » dans l'écran de
personnalisation : la hauteur suit proportionnellement (ratio de
l'image). PUT /editions/{id}/badges/template/size écrase la taille
déduite de l'image ; la réimporter la recalcule à nouveau.

Vérifié : pytest (250 passés), ruff, tsc --noEmit, eslint, vite build,
smoke — tous verts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 20:51:01 +02:00
AdamThomasandClaude Sonnet 5 b7fc80a7dc Étape 20 : planches de badges bénévoles (PDF)
Recto personnalisable (fond image + champs positionnés : nom, poste(s)
affectés, catégorie, rôle) via un éditeur visuel glisser-déposer ; verso
fixe, la même image pour tous les bénévoles. Nouvel écran « Badges »
(COORDINATION uniquement, /badges).

Backend : modèle BadgeTemplate/BadgeField (migration 0011), génération
PDF isolée (app/badges/pdf.py, ReportLab — planches recto suivies des
planches verso correspondantes pour une impression recto-verso), route
POST /editions/{id}/badges/generate, tests (module pur + API).

Frontend : client HTTP (upload multipart, réponses binaires images/PDF),
client mock (mode démonstration), éditeur de positionnement en
millimètres (coordonnées partagées avec le backend), écran de génération
avec sélection des bénévoles et téléchargement.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 20:05:03 +02:00
AdamThomasandClaude Sonnet 5 a78aad58e2 Vue bénévole mobile : responsable, téléphone et repère « maintenant »
La vue bénévole reprenait les infos essentielles (poste, jour, horaire,
lieu) mais affichait un badge de validation factice (« TU ES ATTENDU
SUR CE CRÉNEAU ») sans plus-value, sans jamais donner le nom ni le
téléphone du référent du poste à contacter — pourtant déjà modélisés
(`Position.lead_account_id`) depuis la gestion des référents.

Un compte VOLUNTEER n'a pas accès à `positions`/`shifts` (403, cf. § 2
matrice des accès) : ces infos ne pouvaient donc pas être jointes côté
front à partir des listes existantes. Nouvel endpoint dédié et
minimal, réservé à la lecture du planning propre du bénévole :

  GET /editions/{id}/volunteers/{vid}/planning

Renvoie, par affectation : poste, lieu, et référent (nom + téléphone,
`null` si le poste n'a pas de référent ou si son compte n'est pas
rattaché à une fiche bénévole) — sans exposer la liste complète des
postes/créneaux de l'édition. Tests : accès (soi-même / autre
bénévole 403 / COORD+LEAD), présence/absence du référent, tri par
heure de début.

Front : retrait du badge de validation, ajout des lignes responsable/
téléphone par créneau, et un repère horizontal « MAINTENANT » qui se
positionne dans la liste triée des créneaux selon l'heure réelle (juste
avant le prochain créneau à venir) pour situer le bénévole dans son
planning.

Non inclus dans ce commit (édités en parallèle par l'utilisateur,
laissés en l'état) : backend/app/seed.py, frontend/tailwind.config.js.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-15 23:33:06 +02:00
AdamThomasandClaude Sonnet 5 8fcc22115f Gestion des référents depuis la fiche bénévole
Un poste avait bien un `lead_account_id`, lu par l'écran référent
(`/mobile-referent`) et par les droits d'écriture (`ensure_can_write_position`),
mais rien ne permettait de le renseigner : aucun écran ne l'exposait, et
l'API ne validait même pas que la valeur envoyée désignait un compte référent
existant de la bonne édition.

Backend :
- `PATCH /editions/{id}/accounts/{account_id}` (nouveau) : change le `role`
  d'un compte, seulement entre LEAD et VOLUNTEER (lien magique dans les deux
  cas) — 422 `account.role_change_not_allowed` dès que COORDINATOR est
  impliqué (mot de passe en jeu, jamais touché ici). C'est ce qui permet de
  faire passer le compte d'un bénévole en référent.
- `POST`/`PATCH /positions` : `lead_account_id` vérifié — doit désigner un
  compte `Role.LEAD` de la même édition, sinon 422
  `position.lead_must_be_referent_account` (silencieusement accepté
  jusqu'ici, y compris un compte d'une autre édition ou du mauvais rôle).

Frontend (`ConfigVolunteers.tsx`) : nouvelle section « Référent des postes »
sur la fiche du bénévole, juste après l'accès de connexion — mêmes badges à
cocher que les vœux de poste/artiste. Cocher un poste crée ou met à niveau
(LEAD) l'accès de connexion du bénévole automatiquement ; décocher retire
seulement le poste, sans jamais rétrograder l'accès. Un bénévole dont le
compte est déjà COORDINATOR ne peut pas être désigné référent (il a déjà
accès à tout). Miroir complet côté mock (`accounts.update`,
`checkLeadAccount`) pour que la démonstration se comporte pareil.

Vérifié : 204 tests backend pertinents (14 nouveaux : 6 sur `PATCH accounts`,
8 sur la validation `lead_account_id`), ruff, alembic check ; typecheck/
lint/build/smoke frontend ; parcours complet testé en direct sur le jeu de
démo (création de compte, promotion LEAD, rejet COORDINATOR, affectation
référent) avant nettoyage des données de test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-15 23:19:56 +02:00
AdamThomasandClaude Sonnet 5 e405590bbc Front : donner un accès de connexion à un bénévole (comptes manquants)
Root cause du « je n'ajoute un bénévole avec son mail, je ne reçois aucun
mail » : renseigner un email sur la fiche d'un bénévole ne crée jamais de
compte (`Account`). `POST .../auth/magic-link` cherche un compte par email
et ne fait rien s'il n'en trouve pas (202 quoi qu'il arrive, par conception,
pour ne jamais révéler si un compte existe) — silencieusement, sans erreur.
L'API `POST/GET/DELETE /editions/{id}/accounts` existait déjà côté backend
(testée) mais n'avait jamais été branchée au frontend.

- `api/schema.ts` / `types.ts` / `http-client.ts` / `hooks.ts` : nouvelle
  surface `accounts` (list/create/remove) + `useAccounts`, `useCreateAccount`,
  `useDeleteAccount`.
- `mock-client.ts` : même surface (règles miroir du backend : email unique,
  mot de passe interdit hors COORDINATOR) ; la suppression d'un bénévole
  supprime aussi son compte (cascade RGPD, alignée sur le backend).
- `ConfigVolunteers.tsx` : section « Accès de connexion » sur la fiche du
  bénévole — bouton pour donner l'accès (crée un compte VOLUNTEER, lien
  magique) si un email est renseigné, ou le révoquer si un accès existe déjà.
- Corrigé au passage : `config.vol.addHint` affirmait qu'un email donnait
  l'accès automatiquement — c'était faux, texte mis à jour.
- CLAUDE.md à jour (section authentification).

Vérifié : typecheck, lint, build, smoke (7 routes) OK.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-15 20:22:56 +02:00
AdamThomasandClaude Sonnet 5 e47c29d35b Front : suggestions du solveur en tête de liste dans la grille
- Surface API `solver.run(editionId)` (HTTP + mock) et hooks
  `useRunSolver` (mutation, alimente le cache) / `useSolverSuggestions`
  (lecture seule du cache, ne déclenche jamais de calcul).
- Grille des besoins : bouton « Suggestions (solveur) », affiche le
  nombre de suggestions calculées.
- Panneau d'affectation d'un créneau : les bénévoles suggérés par le
  solveur passent en tête de la liste des candidats (avant le tri par
  disponibilité / charge), avec un badge « Suggéré ». Ne pré-affecte
  jamais personne — la coordination choisit et confirme comme avant.
- Mock : portage glouton (par créneau, du plus urgent au moins urgent)
  du scoring du moteur back-end, pour une démonstration cohérente sans
  CP-SAT côté navigateur.

typecheck / lint / build / smoke au vert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-11 08:16:29 +02:00
AdamThomasandClaude Sonnet 5 36d108b47d Front : retrait des compétences, disponibilités en fenêtres horaires
Aligne le frontend sur le back-end (étape 14).

- Types : suppression de `skill_codes` / `required_skill_codes` /
  `AvailabilityStatus` / `MISSING_REQUIRED_SKILL` ; ajout de
  `AvailabilityRead` / `AvailabilitySet` et de la surface API
  `availability` (list / replace / listEdition) + hooks associés.
- Fiche bénévole : bloc « compétences » remplacé par un éditeur de
  disponibilités (plages date + heures libres, `PUT` en bloc).
- Assistant d'import : plus de colonnes compétences ni disponibilités
  (mapping réduit à l'identité) ; rapport simplifié.
- Grille des besoins : chaque candidat porte un badge de couverture
  (disponible / partiel / non déclaré) calculé sur ses fenêtres, et la
  liste est triée « disponibles d'abord ». Nouvel util
  `availabilityCoverage` / `uncoveredMinutes` dans `lib/planning`,
  portage du moteur back-end.
- Mock : `state.availability` passe à des fenêtres `AvailabilityRead[]`,
  validation `OUTSIDE_AVAILABILITY` recalculée sur l'union des fenêtres,
  jeu de démo et import CSV adaptés.

typecheck / lint / build / smoke au vert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-10 23:01:59 +02:00
AdamThomasandClaude Sonnet 5 81609eecc5 Front : programmation des artistes et vœux des bénévoles
Aligne le frontend sur le back-end (étape 13).

- Types : retrait de `tshirt_size` / `diet` (Volunteer et mapping
  d'import) ; ajout de `ArtistRead/Create/Update` et des champs
  `artist_ids` / `wished_position_ids` sur la fiche bénévole.
- Surface API `artists` (HTTP + mock) et hooks
  `useArtists` / `useCreateArtist` / `useUpdateArtist` / `useDeleteArtist`.
- Nouvel onglet Configuration « Programmation » : liste d'artistes
  éditable, colonne par jour de l'édition (création, renommage,
  suppression ; 409 doublon, 422 nom vide).
- Fiche bénévole & formulaire d'ajout manuel : champs t-shirt / régime
  retirés, sélecteurs « Artistes à voir » et « Postes souhaités »
  (puces retirables, 422 si id étranger).
- Mock : jeu de démo enrichi (2 artistes par jour, vœux aléatoires),
  cascade sur suppression d'artiste / de poste, import CSV sans
  t-shirt / régime.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-10 22:22:45 +02:00
AdamThomasandClaude Sonnet 5 df8d6733db Import bénévoles : couche API (analyse + exécution) et mock CSV
- `PlanningApi.imports.analyze/execute` : envoi `multipart/form-data`
  (le client HTTP laisse le navigateur poser le Content-Type).
- Types miroir des schémas back-end (`ImportAnalyzeResponse`,
  `ImportMapping`, `ImportReport`, `ImportRowReport`, `ImportIssue`…).
- Hooks `useAnalyzeImport` / `useExecuteImport` ; l'exécution réelle
  invalide les bénévoles et le planning.
- Implémentation mock (mode démo) : lecture CSV, suggestion de mapping,
  simulation/exécution avec rapport ligne par ligne. Excel renvoie
  `import.error.xlsx_demo_only`.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-10 21:55:50 +02:00
AdamThomasandClaude Sonnet 5 f58ec00e30 Créneaux types : paramétrage + génération auto des créneaux
Le paramétrage des créneaux se fait dans « Règles & édition » : la coordination
définit des créneaux types (DayPart). À la création d'un poste, un créneau à
besoin 0/0 est généré pour chaque jour de l'édition et chaque créneau type ;
les coordinateurs ajustent ensuite min/idéal.

Back-end :
- DayPart CRUD (GET/POST/PATCH/DELETE /editions/{id}/day-parts). Code figé
  après création (slugifié depuis le libellé si absent), unique par édition.
- Shift.day_part_id (nullable, SET NULL) + migration 0004.
- create_position génère les créneaux ; POST .../positions/{pid}/generate-shifts
  recrée les manquants (idempotent, ne touche pas aux besoins déjà réglés).
- 13 tests (day-parts, génération, extension d'édition, ajout de type).

Front-end :
- api/hooks/mock : dayParts CRUD + positions.generateShifts.
- ConfigRules : panneau « Créneaux types » (libellé + horaires éditables,
  ajout, suppression).
- ConfigGrid : bouton « Générer les créneaux » sur l'en-tête du poste.
- GrillePage : case « à définir » (gris, glyphe ·) quand min=idéal=0, avec
  entrée de légende.

155 tests back OK ; typecheck + lint + build + smoke front OK.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-10 20:57:51 +02:00
AdamThomasandClaude Sonnet 5 e0a0c56307 Édition éditable (dates) + robustesse de l'écran Postes & créneaux
Back-end :
- GET /editions/{id} (tout compte de l'édition) et PATCH /editions/{id}
  (COORDINATION) : name, year, start_date, end_date, retention_days.
  Refus si end_date < start_date (edition.dates_inconsistent). Tests.

Front-end :
- api : EditionRead/Update, editions.get/update (http + mock), hooks
  useEdition / useUpdateEdition.
- ConfigGrid : le bouton « ajouter un poste » sélectionne le poste créé et
  affiche l'état (pending) + les erreurs (ErrorNote) — avant, un échec ou
  même un succès passaient inaperçus. Renommage du poste + choix de la
  catégorie + suppression dans l'en-tête. Une colonne par jour de l'édition
  (même vide) → on peut ajouter un créneau n'importe quel jour.
- ConfigRules : formulaire d'édition (nom + dates) → c'est là qu'on ajoute
  ou retire des jours ; compteur de jours ; retour d'enregistrement.
- i18n mis à jour.

144 tests back OK ; typecheck + lint + build + smoke front OK.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-10 20:02:50 +02:00
AdamThomasandClaude Sonnet 5 6b08dcc953 Frontend : écran Messages branché sur l'envoi d'emails
- api : PlanningNotificationRequest/Result dans schema.ts, méthode
  notifications.sendPlanning (http + mock), hook useSendPlanningNotification
- mock : compte les destinataires avec/sans email, émet des liens magiques
  quand {lien_connexion} est présent
- ConfigMail : plus une maquette. Éditeur objet/corps, variables cliquables
  ({prenom} {nom} {nb_creneaux} {nb_heures} {creneaux} {lien_connexion}),
  boutons « Envoyer le récapitulatif » et « Envoyer avec lien de connexion »,
  retour d'envoi (queued / sans adresse) et ErrorNote
- i18n config.mail.* mis à jour ; onglet « MESSAGES » (plus « (MAQUETTE) »)

typecheck + lint + build + smoke : OK

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-10 08:13:28 +02:00
AdamThomasandClaude Sonnet 5 6e16db4b7e Frontend : connexion (mot de passe + lien magique) et onglets par rôle
Authentification alignée sur le back-end (Étapes 7/8) :
- src/api : schema auth (AccountRead, TokenResponse…), session.ts (jeton
  Bearer partagé + callback 401), méthodes auth du client HTTP
  (POST .../auth/login, .../auth/magic-link, .../auth/verify, GET /auth/me)
  et du mock (comptes coordination + référents + bénévoles, tokens magiques,
  sessions).
- src/auth : AuthProvider/useAuth (jeton en localStorage, réhydratation via
  /auth/me, déconnexion sur 401), RequireAuth (garde + contrôle de rôle),
  HomeRedirect, table ROUTE_ROLES.
- Pages : /connexion (lien magique, avec lien de démo affiché en mode mock),
  /connexion/coordination (email + mot de passe).
- Router : toutes les routes métier passées derrière <RequireAuth> ;
  redirection vers l'accueil du rôle.
- AppShell : onglets filtrés par rôle (01/02/03/06 coordination, 04 bénévole,
  05 référent), email + rôle + bouton Déconnexion.
- Mobile bénévole : cible le bénévole du compte connecté ; dégradation
  propre quand l'API refuse le détail des créneaux à un bénévole.
- Mobile référent : cible le poste dont le compte est référent.
- i18n : clés auth / rôles.
- Vérifs : build tsc + vite, eslint (0 problème), npm run smoke (flux
  login / lien magique + rendu des 6 écrans par rôle et des pages publiques).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwswqSChc3Rwtu61pRXiY2
2026-09-10 07:43:00 +02:00
AdamThomasandClaude Sonnet 5 c9dda65361 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
2026-09-09 23:16:38 +02:00