feat(events): inscription (RSVP) événement + page admin Ops — Fête Targo 20 ans
Nouvelle fonctionnalité « Événements » (aucun courriel envoyé — moteur d'envoi prêt mais gaté).
Hub (services/targo-hub) :
- lib/events.js : config événement semée (fete-20-ans, bilingue FR/EN) ; page
PUBLIQUE festive GET /rsvp/:id[?t=<jwt>&lang] (n° client · combien · courriel ·
allergies ; ?t pré-remplit + rattache via magic-link) ; POST /rsvp/:id/submit
(résout le client au mieux via portal-auth.lookupCustomer, valide, stocke clé-par-
client → re-soumission = mise à jour, pas de doublon) ; endpoints STAFF GET /events,
GET /events/:id/rsvps (+ décompte total de personnes), DELETE ; helpers lien perso
(generateCustomerToken) + courriel d'invitation bilingue. Réutilise les patrons rating.js.
- server.js : dispatch /rsvp + /events → lib/events ; /rsvp/ ajouté à PUBLIC (page +
soumission anonymes) ; /events ajouté à ALWAYS_ENFORCE (vue staff = PII → token requis).
Ops (apps/ops) :
- pages/EventsPage.vue (/evenements) : bandeau événement, KPIs (inscriptions / personnes
attendues = total food truck / à vérifier), lien public copiable (affiche/QR/réseaux),
carte invitation courriel (envoi gaté), table filtrable (DynamicFilter) + export CSV +
suppression. Réutilise PageHeader/StatCard/DataTable/DynamicFilter/useCsvExport.
- api/events.js (client hub), route /evenements, entrée menu « Événements » (PartyPopper).
Vérifié : 30/30 tests unitaires hub (offline) ; page Ops rend proprement à 375px+desktop,
0 erreur console, dégradation gracieuse tant que le hub n'est pas déployé.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>