From bdaf6cb156d835205af48d8eefb66852d9a3c896 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 18:29:14 +0000 Subject: [PATCH] =?UTF-8?q?Pages=20mentions=20l=C3=A9gales=20et=20politiqu?= =?UTF-8?q?e=20de=20confidentialit=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nouvelles pages publiques /mentions-legales et /confidentialite, conformes aux obligations d'une association loi 1901 : LCEN (identité de l'éditeur, RNA, directeur de la publication, hébergeur), RGPD art. 13 (responsable de traitement, données/finalités/bases légales par formulaire, durées de conservation, destinataires, droits, réclamation CNIL), cookies (unique cookie de session exempté de consentement — pas de bandeau nécessaire), droit à l'image et propriété intellectuelle. Les pages sont alimentées par les paramètres de l'association existants, étendus des champs légalement requis : numéro RNA, hébergeur (nom, adresse, téléphone) et date de mise à jour des pages légales — nouvelle carte « Pages légales & hébergeur » dans l'onglet Paramètres, avec alerte listant les champs requis manquants. Un champ vide s'affiche « à compléter » sur la page publique plutôt que de disparaître. Également : liens cliquables Mentions légales / Confidentialité dans le pied de page, et mentions d'information RGPD sous les formulaires publics (demande d'adhésion, inscription à une rencontre). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Fkg15RCxNgUys4ru73He2o --- server/src/schemas.js | 6 + server/src/siteSettings.js | 6 + web/src/App.jsx | 4 + web/src/components/AdhesionForm.jsx | 6 + web/src/components/Footer.jsx | 6 +- web/src/components/admin/AdminContent.jsx | 85 +++++++++++--- web/src/lib/siteSettings.js | 6 + web/src/pages/Confidentialite.jsx | 135 ++++++++++++++++++++++ web/src/pages/Home.jsx | 4 + web/src/pages/MentionsLegales.jsx | 117 +++++++++++++++++++ 10 files changed, 360 insertions(+), 15 deletions(-) create mode 100644 web/src/pages/Confidentialite.jsx create mode 100644 web/src/pages/MentionsLegales.jsx diff --git a/server/src/schemas.js b/server/src/schemas.js index 954cad6..987e0a1 100644 --- a/server/src/schemas.js +++ b/server/src/schemas.js @@ -114,6 +114,12 @@ export const contentSchema = z.object({ association_treasurer: trimmed(160).optional(), association_secretary: trimmed(160).optional(), association_board_members: trimmed(3000).optional(), + // Legal pages (mentions légales & politique de confidentialité) + association_rna: trimmed(30).optional(), + association_host_name: trimmed(200).optional(), + association_host_address: trimmed(300).optional(), + association_host_tel: trimmed(30).optional(), + legal_updated: trimmed(60).optional(), }); // Invitation email composer: every text zone is optional — absent fields diff --git a/server/src/siteSettings.js b/server/src/siteSettings.js index 8ae36ca..e163d97 100644 --- a/server/src/siteSettings.js +++ b/server/src/siteSettings.js @@ -13,6 +13,12 @@ export const ASSOCIATION_DEFAULTS = { association_treasurer: '', association_secretary: '', association_board_members: '', + // Legal pages (mentions légales & politique de confidentialité) + association_rna: '', + association_host_name: '', + association_host_address: '', + association_host_tel: '', + legal_updated: 'Juillet 2026', }; export function associationSettings(content = {}) { diff --git a/web/src/App.jsx b/web/src/App.jsx index 2b5bf06..248b484 100644 --- a/web/src/App.jsx +++ b/web/src/App.jsx @@ -7,6 +7,8 @@ import Inscription from './pages/Inscription.jsx'; import Annuaire from './pages/Annuaire.jsx'; import Association from './pages/Association.jsx'; import RencontresPassees from './pages/RencontresPassees.jsx'; +import MentionsLegales from './pages/MentionsLegales.jsx'; +import Confidentialite from './pages/Confidentialite.jsx'; import Espace from './pages/Espace.jsx'; import Admin from './pages/Admin.jsx'; import { useAuth } from './lib/AuthContext.jsx'; @@ -38,6 +40,8 @@ export default function App() { } /> } /> } /> + } /> + } /> } /> } /> } /> diff --git a/web/src/components/AdhesionForm.jsx b/web/src/components/AdhesionForm.jsx index ead02d0..35d1f0b 100644 --- a/web/src/components/AdhesionForm.jsx +++ b/web/src/components/AdhesionForm.jsx @@ -1,4 +1,5 @@ import { useState } from 'react'; +import { Link } from 'react-router-dom'; import { api } from '../lib/api.js'; import Modal from './Modal.jsx'; @@ -66,6 +67,11 @@ export function AdhesionForm({ showTitle = true }) { +

+ Les informations recueillies servent uniquement à instruire votre demande d'adhésion. + Pour en savoir plus et exercer vos droits, consultez notre{' '} + politique de confidentialité. +

); } diff --git a/web/src/components/Footer.jsx b/web/src/components/Footer.jsx index 4751023..532f394 100644 --- a/web/src/components/Footer.jsx +++ b/web/src/components/Footer.jsx @@ -86,7 +86,11 @@ export default function Footer() { }} > © {new Date().getFullYear()} {settings.association_name} - Mentions légales · Confidentialité + + Mentions légales + {' · '} + Confidentialité + ); diff --git a/web/src/components/admin/AdminContent.jsx b/web/src/components/admin/AdminContent.jsx index f96dc7d..22d9652 100644 --- a/web/src/components/admin/AdminContent.jsx +++ b/web/src/components/admin/AdminContent.jsx @@ -229,6 +229,16 @@ export function ParametresTab() { } }; + // Fields legally required on the mentions légales page (LCEN). + const legalMissing = [ + [settings.association_name, "nom de l'association"], + [settings.association_address, 'adresse du siège'], + [settings.association_rna, 'numéro RNA'], + [settings.association_president, 'président·e'], + [settings.association_host_name, "nom de l'hébergeur"], + [settings.association_host_address, "adresse de l'hébergeur"], + ].filter(([v]) => !String(v || '').trim()).map(([, label]) => label); + return (
@@ -251,20 +261,35 @@ export function ParametresTab() {
- +
+ + +
+
+

Pages légales & hébergeur

+

+ Ces informations alimentent les pages Mentions légales et{' '} + Politique de confidentialité (liens en pied de page). La LCEN impose + d'identifier l'hébergeur du site ; tant qu'un champ requis est vide, la page publique + affiche « à compléter » à sa place. +

+ {legalMissing.length > 0 && ( +
+ ⚠ + Champs requis manquants pour des mentions légales conformes : {legalMissing.join(', ')}. +
+ )} +
+ + +
+ + +
+
+
+ {error &&

{error}

}
diff --git a/web/src/lib/siteSettings.js b/web/src/lib/siteSettings.js index 8ae36ca..e163d97 100644 --- a/web/src/lib/siteSettings.js +++ b/web/src/lib/siteSettings.js @@ -13,6 +13,12 @@ export const ASSOCIATION_DEFAULTS = { association_treasurer: '', association_secretary: '', association_board_members: '', + // Legal pages (mentions légales & politique de confidentialité) + association_rna: '', + association_host_name: '', + association_host_address: '', + association_host_tel: '', + legal_updated: 'Juillet 2026', }; export function associationSettings(content = {}) { diff --git a/web/src/pages/Confidentialite.jsx b/web/src/pages/Confidentialite.jsx new file mode 100644 index 0000000..8ec908c --- /dev/null +++ b/web/src/pages/Confidentialite.jsx @@ -0,0 +1,135 @@ +import { usePublicData } from '../lib/usePublic.js'; +import { associationSettings } from '../lib/siteSettings.js'; +import { LegalLayout, LegalSection, LegalValue } from './MentionsLegales.jsx'; + +// Privacy policy (art. 13 RGPD). The described processing matches exactly +// what this application actually does — update this page if a new +// collection or a third-party service (analytics, newsletter…) is added. +export default function Confidentialite() { + const { data } = usePublicData(); + const s = associationSettings(data?.content); + const email = s.association_email; + + const row = { display: 'grid', gridTemplateColumns: '190px 1fr', gap: 14, padding: '12px 0', borderBottom: '1px solid var(--border-soft)', fontSize: 14.5, lineHeight: 1.6 }; + const cellTitle = { fontWeight: 600, color: 'var(--ink)' }; + + return ( + + +

+ Le responsable du traitement des données personnelles collectées sur ce site est{' '} + , association loi 1901,{' '} + . +
+ Contact : + {s.association_phone && <> · {s.association_phone}} +

+
+ + +

Nous ne collectons que les données strictement nécessaires au fonctionnement du club :

+
+
+ Demande d'adhésion + + Nom et prénom, fonction, entreprise, email professionnel, téléphone. +
Finalité : instruire votre demande et vous recontacter. Base légale : mesures précontractuelles à votre demande. +
+
+
+ Inscription à une rencontre + + Noms et prénoms des participants, rattachés au compte membre qui les inscrit. +
Finalité : gérer les inscriptions et l'accueil des participants. Base légale : exécution de l'adhésion. +
+
+
+ Annuaire des membres + + Fiche entreprise : nom, secteur, dirigeant·e, coordonnées professionnelles, présentation, logo, photo du dirigeant·e. +
Finalité : annuaire public des entreprises membres. Base légale : exécution de l'adhésion ; la photo est publiée avec le consentement de la personne, qui peut la retirer à tout moment depuis son espace membre. +
+
+
+ Espace membre + + Email de connexion et mot de passe (stocké haché, jamais en clair). +
Finalité : accès sécurisé à votre espace. Base légale : exécution de l'adhésion. +
+
+
+

+ Aucune donnée n'est utilisée à des fins publicitaires, ni cédée ou vendue à des tiers. + Le site n'utilise aucun outil de mesure d'audience ni traceur tiers. +

+
+ + +

+ Les données des membres sont conservées pendant la durée de l'adhésion, puis au maximum + 3 ans après son terme (animation du réseau et relance d'adhésion), avant suppression. + Les demandes d'adhésion non abouties sont supprimées au plus tard 3 ans après leur dépôt. + Les inscriptions aux rencontres sont conservées le temps de la saison en cours puis archivées + à des fins de statistiques de fréquentation (nombre de participants uniquement). + Les comptes de connexion sont supprimés avec la fiche du membre. +

+
+ + +

+ Les données sont accessibles aux seuls administrateurs et modérateurs habilités de + l'association, soumis à une obligation de confidentialité. Les fiches de l'annuaire et les + photographies des rencontres sont, elles, publiées sur le site public. +

+

+ Les données sont hébergées par ,{' '} + . Aucun transfert de + données hors de l'Union européenne n'est réalisé. +

+
+ + +

+ Le site dépose un unique cookie de session, strictement nécessaire à l'authentification à + l'espace membre et à l'administration (cookie technique httpOnly, supprimé à l'expiration de la + session). Conformément aux lignes directrices de la CNIL, ce cookie est exempté de consentement. + Aucun cookie publicitaire, de mesure d'audience ou de réseau social n'est utilisé — c'est + pourquoi ce site n'affiche pas de bandeau cookies. +

+
+ + +

+ L'association met en œuvre des mesures techniques et organisationnelles adaptées : mots de + passe stockés sous forme hachée, connexions chiffrées, accès à l'administration restreint et + protégé, validation des fichiers déposés. En cas de violation de données susceptible + d'engendrer un risque pour vos droits, vous en serez informé·e conformément à la réglementation. +

+
+ + +

+ Des photographies sont prises lors des rencontres du club et peuvent être publiées sur ce site + (section « Rencontres passées »). Elles ne sont publiées qu'avec l'accord des personnes + identifiables. Si vous apparaissez sur une photographie et souhaitez son retrait, écrivez à{' '} + : elle sera retirée dans les meilleurs délais. +

+
+ + +

+ Conformément au Règlement général sur la protection des données (RGPD) et à la loi + Informatique et Libertés, vous disposez d'un droit d'accès, de rectification, d'effacement, + de limitation, d'opposition et de portabilité sur vos données. +

+

+ Pour exercer ces droits, contactez-nous à . + Une réponse vous sera apportée dans un délai d'un mois. Si vous estimez, après nous avoir + contactés, que vos droits ne sont pas respectés, vous pouvez adresser une réclamation à la + CNIL (www.cnil.fr — + 3 place de Fontenoy, TSA 80715, 75334 Paris Cedex 07). +

+
+
+ ); +} diff --git a/web/src/pages/Home.jsx b/web/src/pages/Home.jsx index 1d64a5c..af1db9a 100644 --- a/web/src/pages/Home.jsx +++ b/web/src/pages/Home.jsx @@ -157,6 +157,10 @@ export function InscriptionModal({ rencontre, onClose, onDone }) {

Vous pourrez rouvrir ce formulaire pour modifier les noms enregistrés.

+

+ Les noms recueillis servent uniquement à gérer les inscriptions à cette rencontre —{' '} + politique de confidentialité. +

)} diff --git a/web/src/pages/MentionsLegales.jsx b/web/src/pages/MentionsLegales.jsx new file mode 100644 index 0000000..ebec8ce --- /dev/null +++ b/web/src/pages/MentionsLegales.jsx @@ -0,0 +1,117 @@ +import { Link } from 'react-router-dom'; +import { usePublicData } from '../lib/usePublic.js'; +import { associationSettings } from '../lib/siteSettings.js'; + +// Shared bits for the two legal pages. Values come from the association +// parameters maintained in the admin backend (Paramètres) ; an empty +// value renders a visible "à compléter" marker so a missing legal mention +// never fails silently. +export function LegalValue({ value, label, multiline = false }) { + if (value) { + return multiline ? {value} : <>{value}; + } + return ( + + à compléter — {label} + + ); +} + +export function LegalLayout({ kicker, title, updated, children }) { + return ( +
+
+
+
{kicker}
+

{title}

+ {updated && ( +
Dernière mise à jour : {updated}
+ )} +
+
+
+
+
{children}
+
+
+
+ ); +} + +export function LegalSection({ title, children }) { + return ( +
+

{title}

+
+ {children} +
+
+ ); +} + +export default function MentionsLegales() { + const { data } = usePublicData(); + const s = associationSettings(data?.content); + + return ( + + +

+ Le présent site est édité par , + association régie par la loi du 1er juillet 1901 et le décret du 16 août 1901. +

+

+ Siège social : +
+ Numéro RNA : + {s.association_siret && (<>
SIRET : {s.association_siret})} +
+ Email : +
+ Téléphone : +

+
+ + +

+ Le directeur de la publication est , + en qualité de président·e de l'association. +

+
+ + +

+ Le site est hébergé par +
+ Adresse : +
+ Téléphone : +

+
+ + +

+ L'ensemble des contenus du site (textes, photographies, logos, identité visuelle) est la + propriété de l'association ou de ses partenaires, et est protégé par le droit de la propriété + intellectuelle. Toute reproduction, représentation ou diffusion, totale ou partielle, sans + autorisation écrite préalable est interdite. Les logos et marques des entreprises membres + demeurent la propriété de leurs titulaires respectifs. +

+
+ + +

+ Le traitement des données personnelles collectées sur ce site est décrit dans la{' '} + politique de confidentialité. +

+
+ + +

+ Le présent site est soumis au droit français. En cas de litige et à défaut de résolution + amiable, les tribunaux français seront seuls compétents. +

+
+
+ ); +}