# Plan d'exécution — Migration HR CONSULTING & CO vers Laravel

> Réécriture du site Next.js actuel en **Laravel Blade full-stack + Livewire**, avec backoffice **Filament v3**.
> Le site Next.js actuel sert de référence visuelle/fonctionnelle (voir [STRUCTURE.md](STRUCTURE.md)).

## Décisions d'architecture (arrêtées)

| Sujet | Choix | Justification |
|---|---|---|
| Frontend | Laravel **Blade** + **Livewire** + Alpine.js | Un seul projet, hébergement simple, pas d'API séparée |
| Backoffice | **Filament v3** | CRUD + média + settings quasi automatiques |
| Stockage CV | **Cloudflare R2** (driver `s3`), bucket privé + URLs signées | Gratuit (10 Go), egress gratuit, hors serveur, sécurisé |
| Images/logos | **Spatie Media Library** + conversions (recadrage auto) | Normalisation dimension uniforme automatique |
| E-mails | SMTP via `.env` (**Mailpit** en local), destinataires en base (backoffice) | Souplesse sans redéploiement ; mails capturés/testables en dev |
| Auth admin | Filament (Laravel Breeze/Fortify sous le capot) | Standard, sécurisé |

---

## Modèle de données (migrations)

| Table | Champs principaux | Géré dans backoffice |
|---|---|---|
| `users` | name, email, password, is_admin | — (seed admin) |
| `settings` | key, value (clé/valeur typée) | ✅ destinataires e-mail, params divers |
| `testimonials` | author_name, role, company, content, avatar, rating, is_published, sort_order | ✅ CRUD |
| `clients` (logos) | name, logo (media), website_url, is_active, sort_order | ✅ CRUD + upload |
| `services` | title, slug, description, image, href, is_active, sort_order | ✅ CRUD |
| `formations` | title, slug, description, image, price?, is_active | ✅ CRUD |
| `instructors` | name, role, bio, photo, is_active | ✅ CRUD |
| `news` (posts) | title, slug, excerpt, **content (HTML, WYSIWYG)**, featured_image, category, author_id, published_at, status (draft/published), meta_title, meta_description | ✅ CRUD éditeur riche |
| `newsletter_subscribers` | email, status (pending/confirmed), subscribed_at, ip | ✅ liste/export |
| `contact_messages` | first_name, last_name, email, phone, message, read_at | ✅ liste |
| `resume_applications` | first_name, last_name, email, phone, study_field, formation_field, file_path (R2), file_disk, created_at | ✅ liste + lien signé |
| `formation_orders` | name, email, phone, formation_id, message | ✅ liste |
| `cookie_consents` | consent_id, ip_hash, necessary, analytics, marketing, consented_at, user_agent | ✅ journal des consentements |
| `visits` (page views) | session_id, visitor_id, ip, country, city, region, device, browser, os, url, page_title, referrer, utm_source, is_bot, visited_at | ✅ analytics visiteurs |
| `training_sessions` | title, starts_at, ends_at, trainers, contact_email, certificate_template, **intermediary_first_name, intermediary_last_name, intermediary_job_title, intermediary_phone, intermediary_email** (Phase 12) | ✅ CRUD (certificats) |
| `participants` | training_session_id, first_name, last_name, company, job_title, phone, **email (obligatoire dès Phase 12)** | ✅ CRUD (par session) |
| `certificates` | participant_id, code (unique, non devinable), template, status, issued_at, revoked_at | ✅ génération + révocation |
| `training_reports` (Phase 12) | training_session_id (1–1), context, objectives, program (JSON modules/durées), methods, logistics, attendance_notes, evaluation_summary (JSON critères/notes), verbatims, strengths, difficulties, recommendations, conclusion, status (draft/sent), sent_at, sent_to | ✅ rédaction + envoi à l'intermédiaire |
| `media` | (table Spatie Media Library) | — |

---

## Phases d'exécution

### Phase 0 — Initialisation (fondations) ✅
- [x] `composer create-project laravel/laravel` → **Laravel 12** (PHP 8.2+, **MySQL 8**), nouveau projet à la racine.
- [x] Installer **Filament v3**, **Livewire 3**, **Spatie Media Library**, **league/flysystem-aws-s3-v3** (R2), **filament-tiptap-editor** (WYSIWYG News), **geoip2/geoip2** (analytics — base GeoLite2 `.mmdb` reportée Phase 8), **mews/purifier** (sanitization HTML). *Cloudflare Turnstile reporté Phase 5 (validation serveur via client HTTP natif, clés déjà en `.env`).*
- [x] Configurer `.env` : **DB MySQL**, MAIL (**Mailpit** en local — `MAIL_MAILER=smtp`, SMTP `127.0.0.1:1025`, UI http://localhost:8025), disque `r2` (S3-compatible, privé), clés `TURNSTILE_*`.
- [x] Layout Blade de base + intégration Tailwind (v4, tokens DESIGN.md ; remplace Chakra UI).
- [x] Seed d'un utilisateur admin (gate `is_admin`).

**Livrable :** ✅ projet Laravel qui démarre, `/admin` Filament accessible. Voir [docs/phases/phase-0-rapport.md](docs/phases/phase-0-rapport.md).

### Phase 1 — Schéma de données & migrations ✅
- [x] Créer toutes les migrations + modèles Eloquent (tableau ci-dessus).
- [x] Relations (formation_orders → formations, etc.).
- [x] Seeders pour migrer les données statiques actuelles (`old/src/data/*.js` → seeders) et les coordonnées du footer.
- [x] Table `settings` + helper `setting('key')`.

**Livrable :** ✅ base de données complète + données initiales seedées. Voir [docs/phases/phase-1-rapport.md](docs/phases/phase-1-rapport.md).

### Phase 2 — Site public (Blade) — pages statiques ✅
Recréer les pages/menus de [STRUCTURE.md](STRUCTURE.md) :
- [x] Layout : Navbar (7 liens + CTA « Déposer un CV »), Footer (4 colonnes), responsive + menu mobile.
- [x] Pages : `/`, `/about`, `/services`, `/formations`, `/formations/{slug}`, `/instructors`, `/news`, `/news/{slug}`.
- [x] Page d'accueil : Hero, Welcome, WhyChooseUs, Services, **Témoignages**, News, Statistiques, Resume CTA, **Carrousel logos clients**.

**Livrable :** ✅ site public navigable affichant les données de la base. Voir [docs/phases/phase-2-rapport.md](docs/phases/phase-2-rapport.md).

### Phase 3 — Backoffice Filament (contenu) ✅
- [x] Resources Filament : Testimonials, Clients/Logos, Services, Formations, Instructors, News.
- [x] Page **Settings** (destinataires e-mail contact/CV/newsletter, coordonnées, réseaux sociaux).
- [x] Authentification + rôles admin.

**Livrable :** ✅ tout le contenu éditable depuis `/admin`. Voir [docs/phases/phase-3-rapport.md](docs/phases/phase-3-rapport.md).

#### Focus News (éditeur WYSIWYG riche) ⭐
- [x] Resource Filament **News** avec champ **`RichEditor`** (ou TipTap via `filament-tiptap-editor` pour : titres, gras/italique, listes, citations, liens, **images/médias intégrés**, tableaux, code, alignement, vidéos embed).
- [x] Champs : titre, slug auto, **catégorie**, extrait, image à la une, statut **brouillon/publié**, date de publication planifiable, **SEO** (meta title/description, Open Graph).
- [x] Upload des images de l'éditeur vers le disque média (pas en base64).
- [x] Page publique `/news` (liste paginée + filtre catégorie) et `/news/{slug}` (rendu HTML, articles liés).
- [x] Sécurité : **purifier le HTML** (HTMLPurifier / `mews/purifier`) au rendu pour éviter le XSS.

### Phase 4 — Fonctionnalité Témoignages + Logos clients ⭐ ✅
- [x] **Témoignages** : resource Filament (publication, ordre, note) → affichés en section + carrousel sur l'accueil.
- [x] **Logos clients** :
  - [x] Resource Filament avec upload logo.
  - [x] **Recadrage/normalisation auto** : conversion Spatie Media Library `->fit(Manipulations::FIT_CONTAIN, W, H)` sur fond transparent → tous les logos à dimension uniforme (ex. 200×100), format webp.
  - [x] Composant Blade/Livewire **marquee défilant** (CSS animation, pause au survol, défilement infini).

**Livrable :** ✅ témoignages + logos gérés en backoffice, logos normalisés et défilants sur l'accueil. Voir [docs/phases/phase-4-rapport.md](docs/phases/phase-4-rapport.md).

### Phase 5 — Formulaires + E-mails ✅
- [x] **Anti-robot** : intégrer **Cloudflare Turnstile** (widget front + validation serveur du token) + **honeypot** + rate-limiting sur les formulaires Contact et Dépôt de CV (clés `TURNSTILE_*` dans `.env`).
- [x] **Contact** (`/contact`) : Livewire form (avec Turnstile) → enregistre `contact_messages` + Mailable vers destinataires (settings).
- [x] **Formation sur-mesure** (`/custom-formation`) + **Commande formation** (`/formations/{slug}`) : enregistrent + e-mail.
- [x] **Newsletter** (footer) :
  - [x] Enregistre l'inscription (`newsletter_subscribers`).
  - [x] Envoie une notification e-mail aux **destinataires paramétrés dans le backoffice**.
  - [ ] (Option) double opt-in / confirmation. *(reporté — simple opt-in implémenté, `token` conservé)*
- [x] Mailables Blade (remplacent les `*.template.js` actuels).
- [x] **Test e-mails en dev** : vérifier chaque notification (contact, formation, newsletter) dans **Mailpit** (http://localhost:8025) — aucun mail réel n'est envoyé en local.

**Livrable :** ✅ tous les formulaires fonctionnent, enregistrent en base et notifient par e-mail (vérifiables dans Mailpit en dev). Voir [docs/phases/phase-5-rapport.md](docs/phases/phase-5-rapport.md).

### Phase 6 — Dépôt de CV + stockage R2 sécurisé ⭐ ✅
- [x] Form `/send-resume` (Livewire) avec **Cloudflare Turnstile** + honeypot et validation stricte : `mimes:pdf,doc,docx`, `max:8192`.
- [x] Upload vers disque **`r2`** (bucket **privé**, visibilité `private`) — jamais en local, jamais public.
- [x] Enregistre `resume_applications` (chemin + métadonnées).
- [x] E-mail de notification aux destinataires (avec lien, **sans** exposer le fichier publiquement).
- [x] Backoffice : liste des candidatures + bouton **télécharger** via **URL signée temporaire** (`Storage::disk('r2')->temporaryUrl(...)`).

**Livrable :** ✅ CV stockés en sécurité sur R2, accessibles uniquement aux admins via liens signés. Voir [docs/phases/phase-6-rapport.md](docs/phases/phase-6-rapport.md).

### Phase 7 — Cookies & consentement (RGPD) ⭐ ✅
- [x] **Bandeau de consentement** (composant Blade + Alpine.js) en bas de page : *Accepter tout* / *Refuser* / *Personnaliser*.
- [x] **Catégories** : Nécessaires (toujours actifs), **Analytics**, Marketing.
- [x] Stockage du choix : cookie `cookie_consent` (durée 6 mois) + journal en base (`cookie_consents`).
- [x] **Le tracking analytics (Phase 8) ne s'active QUE si consentement « analytics »** ; helper `cookie_consent('analytics')` prêt pour le conditionnement (Phase 8).
- [x] Page publique **Politique de cookies** + **Politique de confidentialité** (texte éditable en backoffice / settings).
- [x] Backoffice : texte du bandeau paramétrable + journal/export des consentements.

**Livrable :** ✅ bandeau cookies conforme, choix respecté et journalisé, lié à l'analytics (helper de conditionnement). Voir [docs/phases/phase-7-rapport.md](docs/phases/phase-7-rapport.md).

### Phase 8 — Statistiques des visiteurs (backoffice) ⭐ ✅
- [x] **Middleware de tracking** : enregistre chaque page vue (hors `/admin`, hors bots) dans `visits` — IP (pseudonymisée), **pays/ville (GeoIP)**, date/heure, URL, titre de page, referrer, device/navigateur/OS, UTM, session/visiteur.
- [x] **GeoIP** : MaxMind **GeoLite2** via `geoip2/geoip2` (base `.mmdb` à fournir en prod ; dégradation gracieuse en dev) ; détection bots (parser UA maison).
- [x] **Respect cookies** : tracking conditionné au consentement analytics (Phase 7) ; sans consentement, **aucun enregistrement** ; IP toujours **pseudonymisée (HMAC)**.
- [x] **Visiteur / session** : cookie `visitor_id` (1 an) + `session_id` pour reconstituer le **parcours** d'une session.
- [x] Performances : écriture **asynchrone** (`dispatchAfterResponse`) pour ne pas ralentir les pages + rate-limit anti-abus.
- [x] **Tableau de bord Filament** (widgets) :
  - [x] Visites & visiteurs uniques (jour/semaine/mois) — vue d'ensemble + graphe temporel 30 j.
  - [x] **Top pays** (GeoIP), top pages.
  - [x] **Pages les plus visitées**.
  - [x] Sources de trafic (referrers, UTM), répartition device/navigateur (colonnes/filtres VisitResource).
  - [x] Liste des **visites récentes** + détail du **parcours** d'une session.
  - [x] Filtres par période/pays/appareil + **export CSV**.
- [x] Rétention/purge des anciennes données (RGPD) via tâche planifiée (`analytics:purge`, quotidienne).

> Alternative légère si besoin : intégrer un outil self-hosted (Plausible/Umami) en complément. Ici on privilégie la solution **interne au backoffice** comme demandé.

**Livrable :** ✅ statistiques de fréquentation complètes (IP pseudonymisée, pays, date/heure, pages, parcours) dans `/admin`. Voir [docs/phases/phase-8-rapport.md](docs/phases/phase-8-rapport.md).

### Phase 9 — Finitions & mise en production ✅
- [x] SEO (meta + canonical, **sitemap.xml** dynamique, **robots.txt**, Open Graph + Twitter Card), **pages d'erreur custom** (404/403/500/503/419/429), favicon/logo (Phase 0).
- [x] Optimisation : cache (config/route/view documentés), images (conversions Spatie — Phase 4), file de mails **documentée** (option prod, `DEPLOYMENT.md` §6 ; envoi sync résilient en l'état). Tracking visites déjà asynchrone.
- [x] Tests des parcours critiques (formulaires, upload CV, e-mails, cookies, tracking) — **144 tests verts**.
- [x] Sécurité : rate-limiting des formulaires + tracking, CSRF, validation, **scan type réel** des fichiers (Phases 5/6/7/8).
- [x] Déploiement : guide complet + checklist `.env` production / queue / R2 / GeoIP / cron — voir [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md).

**Livrable :** ✅ site prêt pour la mise en production (SEO, erreurs, sécurité, guide de déploiement). Voir [docs/phases/phase-9-rapport.md](docs/phases/phase-9-rapport.md).

### Phase 10 — Slider d'accueil géré en backoffice ✅
- [x] Modèle `HeroSlide` + table `hero_slides` (image Spatie Media Library, conversion « slide » WebP, pattern Phase 4) ; `is_active`/`sort_order` indexés.
- [x] Resource Filament `HeroSlideResource` (réordonnable, 2 mises en page : **2 colonnes** / **plein écran**, carte flottante optionnelle, CTA validés contre les schémas dangereux, image sans SVG).
- [x] Composant `<x-hero-slider>` Alpine.js : **défilement automatique** (intervalle réglable dans Settings), **transition en fondu**, pause au survol/focus + **bouton lecture/pause** (WCAG 2.2.2), `prefers-reduced-motion`, **puces** accessibles (ARIA), images hors-écran en `lazy`.
- [x] Fallback `<x-hero-static>` (Hero d'origine) si aucun slide + seeder du slide n°1.
- [x] Tests : modèle, accueil (slider/fallback/ordre/overlay), seeder, resource Filament (liste/création/édition/validation CTA) — **suite verte**.

**Livrable :** ✅ slider d'accueil entièrement éditable depuis `/admin`, affichage amélioré (autoplay, fondu, contrôles accessibles). Voir [docs/phases/phase-10-rapport.md](docs/phases/phase-10-rapport.md).

### Phase 11 — Certificats de formation (PDF + authentification QR) ✅
- [x] **Modèle de données** : `training_sessions` (titre, **date début**, **date fin**, **formateurs**, e-mail de contact, modèle de certificat par défaut), `participants` (nom/prénom, **entreprise**, **fonction**, **téléphone**, e-mail optionnel), `certificates` (code unique **non devinable**, modèle, émis le, révocable).
- [x] **Backoffice Filament** : resource « Sessions de formation » (CRUD) + gestion des **participants** (relation manager), **sélection du modèle de certificat** parmi les modèles proposés, actions **générer le certificat** (par participant) et **générer tout** (en masse), téléchargement PDF.
- [x] **Modèles de certificats** : 3 modèles paysage A4 (classique / moderne / premium) conformes à [DESIGN.md](DESIGN.md) (navy/vert/gold), avec logo, titre de formation, dates, formateurs, nom/entreprise/fonction du participant.
- [x] **Génération PDF** : `barryvdh/laravel-dompdf`, **paysage A4 haute résolution** (DPI élevé, polices embarquées, QR vectoriel/PNG haute densité), un PDF **par participant**.
- [x] **QR code d'authentification** : `chillerlan/php-qrcode` — le QR imprimé sur le certificat pointe vers la **page publique de vérification** `/certificats/verifier/{code}` qui confirme l'authenticité (participant, formation, dates, statut), avec **formulaire de saisie manuelle** du code.
- [x] **Sécurité** : code aléatoire long (non séquentiel, non devinable), **rate-limiting** sur la page de vérification, pas d'énumération possible, page de vérification ne divulguant que le strict nécessaire, révocation possible depuis le backoffice.
- [x] Tests : modèles, génération PDF/QR, page de vérification (valide / inconnu / révoqué), resource Filament.
- [x] Améliorations post-livraison : période sur **1 jour** (« le … » vs « du … au … »), **signature/cachet numérisés** sur les certificats, **Turnstile** sur la vérification manuelle, **envoi du certificat par e-mail** au participant.

**Livrable :** ✅ sessions de formation + participants gérés dans `/admin`, certificats PDF paysage haute résolution générés par participant, authentifiables publiquement via QR code. Voir [docs/phases/phase-11-rapport.md](docs/phases/phase-11-rapport.md).

### Phase 12 — Rapport de formation & intermédiaire de session ✅
- [x] **E-mail du participant obligatoire** : `email` requis (`required|email`) dans le relation manager Filament, le formulaire d'ajout et la factory ; migration passant la colonne en `NOT NULL` avec **garde-fou** interrompant la migration (message clair) si des participants sans e-mail subsistent. *Choix retenu : règle imposée à la fois en base et au niveau applicatif (aucune donnée existante avec e-mail null).*
- [x] **Intermédiaire de la session** (interlocuteur client ayant commandé/organisé la formation) : 5 champs sur `training_sessions` (`intermediary_first_name`, `intermediary_last_name`, `intermediary_job_title`, `intermediary_phone`, `intermediary_email`) + booléen `intermediary_is_participant`. Formulaire Filament : case « **L'intermédiaire participe à la formation** » → création **automatique** du participant correspondant, **sans doublon** (dédup `LOWER(email)` sur la session, idempotent) ; décocher ne supprime jamais le participant (helper text + garde-fou).
- [x] **Modèle `training_reports`** : un rapport **par session** (relation 1–1) ; seules les parties qualitatives stockées (factuel dérivé). Statut `draft`/`sent`, horodatage et destinataire d'envoi journalisés.
- [x] **Backoffice Filament** : **page dédiée** `ManageReport` (`/{record}/report`), **pré-remplissage** des données factuelles en lecture seule (titre, période, formateurs, effectif, présents, certifiés) ; action « **Envoyer le rapport à l'intermédiaire** » avec confirmation, sous garde-fous (session **terminée** + **e-mail intermédiaire** renseigné + rapport **non vide**) ; **renvoi** possible (nouvel horodatage).
- [x] **E-mail HTML soigné** (charte [DESIGN.md](DESIGN.md) navy/vert/gold, styles inline) : en-tête, salutation personnalisée, **synthèse** (formation, période, formateurs, participants/présents/certifiés, satisfaction moyenne), mention de la pièce jointe, signature ; **copie** (cc) optionnelle à l'e-mail de contact de la session.
- [x] **PDF du rapport complet** (dompdf, **portrait A4**, polices Poppins embarquées, pagination `counter(page)`) joint à l'e-mail — 14 sections.
- [x] Tests : migrations/modèles, e-mail participant obligatoire, auto-ajout intermédiaire (avec/sans doublon), garde-fous d'envoi, génération PDF, envoi e-mail (`Mail::fake`), page Filament, non-régression mass-assignment — **268 tests verts**.

**Contenu type du rapport de formation (PDF) :**
1. **Page de garde** — logo, « Rapport de formation », intitulé de la formation, période, lieu (optionnel), référence de session, destinataire (entreprise/intermédiaire), date d'émission.
2. **Synthèse exécutive** — l'essentiel en quelques lignes : objectifs atteints, participation, satisfaction globale, recommandation principale.
3. **Contexte & objectifs pédagogiques** — pourquoi la formation, objectifs visés (savoir / savoir-faire / savoir-être).
4. **Programme dispensé** — modules/séquences avec durées, écarts éventuels par rapport au programme prévu.
5. **Équipe pédagogique** — formateurs (nom, qualité/expertise).
6. **Participants & assiduité** — effectif inscrit/présent, taux de présence, observations.
7. **Méthodes & moyens pédagogiques** — exposés, ateliers, cas pratiques, supports remis, logistique.
8. **Évaluation des acquis** — modalités (quiz amont/aval, exercices, mises en situation) et résultats.
9. **Évaluation à chaud (satisfaction)** — moyennes par critère (contenu, animation, supports, organisation, note globale, ex. /5) + verbatims marquants.
10. **Certificats délivrés** — nombre, modalité de vérification (QR / page publique).
11. **Points forts & difficultés rencontrées**.
12. **Recommandations & plan d'action** — axes de progrès, formations complémentaires, suivi proposé.
13. **Conclusion** — et signature du formateur référent / de l'organisme.
14. **Annexe** — liste nominative des participants (nom, entreprise, fonction, statut certificat).

**Livrable :** ✅ e-mail participant obligatoire, intermédiaire géré sur la session (avec ajout automatique aux participants), rapport de formation professionnel rédigé en backoffice et envoyé à l'intermédiaire (e-mail HTML + PDF complet en pièce jointe). Voir [docs/phases/phase-12-rapport.md](docs/phases/phase-12-rapport.md).

---

## Variables `.env` à prévoir

```dotenv
# Base
APP_NAME="HR Consulting & Co"
APP_URL=https://...

# SMTP (envoi e-mails)
# --- Dev local : MAILPIT (capture tous les mails, UI http://localhost:8025) ---
MAIL_MAILER=smtp
MAIL_HOST=127.0.0.1
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="no-reply@hrconsultingco.ci"
# --- Production : remplacer par un vrai serveur SMTP ---
# MAIL_HOST=mail.test.net
# MAIL_PORT=465
# MAIL_USERNAME=example@test.net
# MAIL_PASSWORD=secret
# MAIL_SCHEME=smtps    # Laravel 12 utilise MAIL_SCHEME (smtps/tls), pas MAIL_ENCRYPTION

# Cloudflare R2 (S3-compatible) — stockage CV privé
FILESYSTEM_CLOUD=r2
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
R2_BUCKET=hr-cv
R2_ENDPOINT=https://<accountid>.r2.cloudflarestorage.com
R2_REGION=auto
```

> Les **destinataires** des e-mails (contact, CV, newsletter) ne sont **pas** dans `.env` mais dans la table `settings` (modifiables en backoffice).

---

## Points de sécurité (CV)

1. Bucket R2 **privé** — `visibility => 'private'`, jamais d'URL publique.
2. Accès admin **uniquement** via `temporaryUrl()` (expiration ex. 5 min).
3. Validation MIME réelle (pas seulement l'extension) + taille max.
4. Nom de fichier randomisé (pas le nom d'origine en chemin public).
5. Rate-limiting sur le formulaire d'upload.
6. (Option) scan antivirus avant stockage.

---

## Ordre de priorité recommandé

`Phase 0 → 1 → 2 → 3` (fondations + site visible + backoffice, **News WYSIWYG incluse**) puis les fonctionnalités demandées **4 (témoignages + logos) → 5 (newsletter/e-mails) → 6 (CV/R2) → 7 (cookies/RGPD) → 8 (analytics visiteurs)**, et enfin **9 (prod)**.

> ⚠️ La **Phase 7 (cookies) doit précéder ou accompagner la Phase 8 (analytics)** : le tracking dépend du consentement.
