# Politique de rétention RGPD — MariageShare

**Date de mise en application :** 2026-05-29 (J-7)
**Base légale :** Art. 9 + recital 47 RGPD (mariage privé)

## Durée de conservation

| Catégorie | Durée | Mécanisme |
|-----------|-------|-----------|
| Photos / vidéos uploadées | 5 ans | R2 bucket-level lifecycle policy préfixe `events/` → Expiration.Days=1825 |
| Sauvegardes (R2 + B2 + USB) | 30 daily + 12 monthly + 1 yearly | Phase 0 BACKUP-05 retention rotation |
| Audit logs (`audit_log` table) | 5 ans | Pas de purge automatique avant 5 ans (preuve forensique RGPD-06) |
| Cookie deviceId (uuid v4) | 5 ans | RGPD-03 functional only, pas de tracking |

## Justification légale

**Art. 17 RGPD (droit à l'effacement)** — l'invité peut supprimer ses propres uploads via DELETE `/api/events/[token]/uploads/[mediaId]` (RGPD-05, livré Phase 3). Le soft-delete + cleanup async BullMQ retire le fichier des storage actifs ; les sauvegardes purgent automatiquement selon la rotation Phase 0 BACKUP-05.

**Recital 47 RGPD** — mariage privé = traitement Art. 9 (catégories particulières) avec base légale « intérêt légitime » + opt-out signage papier au lieu (cartons table). Aucun consent banner web (RGPD-02 décision Phase 2).

## Mécanisme d'expiration automatique

Le bucket R2 hot storage applique une règle lifecycle bucket-level :

- **Préfixe :** `events/`
- **Action :** Expiration
- **Délai :** 1825 jours (5 ans) à compter de la date d'objet (ObjectCreationDate)

Application via `bash scripts/r2-lifecycle.sh` (idempotent). Preuve d'application : `.planning/phases/09-plan-b-load-test-rgpd-hardening/r2-lifecycle-applied.json`.

## Procédure d'effacement à la demande

Toute personne identifiable (invité ayant uploadé une photo) peut demander l'effacement complet via :

- Bouton « Supprimer » sur `/mes-photos` (RGPD-05 livré Phase 3)
- Email DPO : (TODO Phase 10 OPS — DPO contact à finaliser)

Délai de réponse : 30 jours (Art. 12 RGPD).

## Référence technique

- **R2 endpoint :** variable d'environnement `R2_ENDPOINT` (Cloudflare S3-compatible API)
- **Bucket :** variable d'environnement `R2_BUCKET`
- **Script applicateur :** `scripts/r2-lifecycle.sh`
- **Implémentation :** Plan 09-03 RGPD-10 (Phase 9 durcissement J-7, 2026-05-29)

---

## Archivage cold storage post-1 an (Phase 11 / BACKUP-07)

À partir de 1 an post-event, les originaux (`original.{ext}`) sont automatiquement
déplacés vers Cloudflare R2 cold storage (`STANDARD_IA` storage class) sous le
préfixe `cold/events/`. Les variantes locales (thumbs, medium) restent disponibles
immédiatement pour la galerie.

| Catégorie | Localisation | Durée | Mécanisme |
|-----------|--------------|-------|-----------|
| Originaux 0–1 an | Disque local + R2 hot (`events/`) backup | 1 an local | `events/` lifecycle 1825 jours |
| Originaux 1–5 ans | R2 cold (`cold/events/` STANDARD_IA) uniquement | 5 ans depuis upload | `cold/events/` lifecycle 1825 jours |
| Thumbs + medium | Disque local | 5 ans | Pas d'expiration locale (galerie permanent) |
| Backups (R2 + B2 + USB) | Multi-destination | 30 daily + 12 monthly + 1 yearly | `scripts/backup.sh` rotation Phase 0 |

**Conformité Art. 17 RGPD (droit à l'effacement) — exemption CNIL 3 mois sur sauvegardes.**

Quand un invité invoque DELETE `/api/events/[token]/uploads/[mediaId]`, le système
actif retire immédiatement la photo (soft-delete + cleanup BullMQ). Si l'original
a été cold-archivé, le worker `media-cleanup-worker` exécute aussi un DeleteObject
sur l'objet R2 `cold/events/...`. Les sauvegardes rotationnelles (30 daily) purgent
naturellement les données supprimées dans un délai maximal de 30 jours, conforme
aux recommandations CNIL (« délai raisonnable » 3 mois maximum, cf. EDPB Guidelines
5/2019 sur le droit à l'effacement).

**Mécanisme automatique mensuel.**

- `scripts/archive-old-events.ts` exécuté par crontab host (1er du mois 02:00 UTC).
  Sélectionne `Event.createdAt < now - 1 an + status=ACTIVE`, copie chaque `original.*`
  vers `cold/events/{eventId}/{mediaId}/original.{ext}` en STANDARD_IA, vérifie la taille,
  met à jour `Media.coldArchivePath`, puis supprime le fichier local.
- `scripts/restore-test-cron.sh` exécuté par crontab host (1er du mois 05:30 UTC) —
  drill `restore.sh --drill --remote r2` + ping `healthchecks.io` dead-man-switch.
- Lifecycle rules R2 appliquées via `bash scripts/r2-lifecycle.sh` (idempotent, contient
  les DEUX règles : `events-5-year-retention` + `cold-events-5-year-retention`).

**Vérifier les règles lifecycle :** `bash scripts/check-r2-lifecycle-rules.sh` — exit 0 si les 2 règles sont présentes.

**Premier run cold archive :** 2027-06-13 (J + 1 an + 1 jour après 2026-06-12).
