Droit à l'image par signature électronique (membre + accompagnants)

Remplace la feuille à imprimer par un recueil électronique du consentement,
construit selon l'article 9 du Code civil (droit à l'image = droit de la
personnalité, personnel) :

- Le membre signe une fois, dans son espace, une autorisation GÉNÉRALE
  couvrant toute photo de lui — plus besoin de valider chaque publication.
  Capture d'une signature dessinée (pad canvas), nom, horodatage et IP :
  une signature électronique simple, preuve de consentement (art. 7 RGPD).
  Étape proposée au premier accès mais NON bloquante (« Plus tard »).
- Un adulte ne pouvant pas consentir pour un autre, l'image des
  accompagnants est recueillie PAR PERSONNE au moment de l'inscription à
  la rencontre : case « autorise / n'autorise pas » par participant +
  attestation du membre d'avoir informé chaque personne et obtenu son
  accord (mineur : représentant légal).
- La publication n'est plus bloquée par le statut de consentement (évite
  le blocage systématique) ; le consentement est la preuve conservée.
- Admin : statut d'autorisation dans la liste des membres (avec la
  signature consultable) et par participant dans la liste des inscrits
  (badges + exports Excel/impression).
- Table image_consents (journal append-only) et colonne
  inscriptions.image_consent, migrations idempotentes.
- Politique de confidentialité mise à jour (consentement par personne,
  fondement art. 9, cas des mineurs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fkg15RCxNgUys4ru73He2o
This commit is contained in:
Claude committed 2026-07-16 20:59:51 +00:00
1 parent a9e01de7a8
commit b34e361cbe
12 files changed
+516 -48

No files matched your search

+26 -1
View File
@@ -31,8 +31,15 @@ export const demandeSchema = z.object({
tel: trimmed(30, 6),
});
// Each participant carries their own image-rights decision (an adult can't
// consent for another — art. 9 Code civil), and the member attests they
// informed each accompanying person and obtained their agreement.
export const inscriptionPublicSchema = z.object({
participants: z.array(trimmed(120, 1)).min(1).max(100),
participants: z
.array(z.object({ nom: trimmed(120, 1), imageConsent: z.boolean() }))
.min(1)
.max(100),
attestation: z.literal(true, { errorMap: () => ({ message: "l'attestation est requise" }) }),
});
export const memberProfileSchema = z.object({
@@ -51,6 +58,24 @@ export const adminMemberSchema = memberProfileSchema.extend({
valide: z.boolean().optional(),
});
// Electronic image-rights consent submitted by the member. A drawn PNG
// signature and at least one publication scope are required to authorize;
// refusing needs neither. Signature kept small (canvas ~500x160) to stay
// well under the JSON body limit.
export const imageConsentSchema = z
.object({
decision: z.enum(['accepted', 'refused']),
scopes: z.array(z.enum(['site', 'social', 'print'])).max(3).optional().default([]),
signatoryName: trimmed(120, 1),
signaturePng: z.string().max(60000).optional().default(''),
})
.refine(
(d) =>
d.decision !== 'accepted' ||
(d.signaturePng.startsWith('data:image/png;base64,') && d.scopes.length > 0),
{ message: 'une signature et au moins un support sont requis pour autoriser', path: ['signaturePng'] }
);
export const rencontreSchema = z.object({
titre: trimmed(200, 1),
date_renc: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'format AAAA-MM-JJ'),