Skip to content

RGPD / suppression de compte

Trois endpoints couvrent les droits RGPD self-service de l’utilisateur : portabilité (export de ses données) et droit à l’effacement (suppression de compte). La suppression suit un modèle soft-delete + période de grâce : le compte est marqué supprimé immédiatement (et désactivé), puis effacé physiquement par un cron au-delà de la fenêtre de grâce. Tant que la grâce n’est pas écoulée, se reconnecter réactive automatiquement le compte (la réactivation est centralisée dans SessionService::create()).

Variable d’environnementDéfautRôle
ACCOUNT_DELETION_GRACE_DAYS30Jours pendant lesquels un compte soft-deleted reste restaurable avant purge irréversible.
ACCOUNT_DELETION_TOKEN_TTL_HOURS24Validité du token e-mail de confirmation (comptes OAuth sans mot de passe).
ACCOUNT_PURGE_BATCH_SIZE50Comptes traités par tick de bin/account-purge.php.
ACCOUNT_PURGE_MEDIA_BATCH_SIZE100Médias effacés par page lors de la purge d’un compte.

Purge (bin/account-purge.php, à planifier quotidiennement) : pour chaque compte dont la grâce est écoulée, tous les médias possédés sont supprimés (fichiers + DB + Meilisearch via MediaDeleteService), la ligne user est anonymisée (e-mail/username scrambés, champs PII nullés, purged_at horodaté) plutôt que physiquement supprimée — pour éviter un CASCADE FK non maîtrisé sur une table user seedée en externe — et le document Meilisearch users est retiré. L’opération est idempotente.

Limitation connue : pendant la période de grâce, le document Meilisearch users n’est pas retiré (il appartient à un pipeline externe et ne pourrait pas être recréé en cas de réactivation) ; seul l’authentification est bloquée. Le document n’est supprimé qu’à la purge définitive.


Export de portabilité RGPD : renvoie l’intégralité des données de l’utilisateur authentifié sous forme de fichier JSON téléchargeable (et non une ressource JSON:API — la charge utile est une archive, pas une entité d’API).

  • Auth : requise (Bearer)
  • Action : ExportMyDataAction
  • Réponse 200 OK :
    • Content-Type: application/json; charset=utf-8
    • Content-Disposition: attachment; filename="hydrogen-export-<userHex>-<YYYYMMDD>.json"
  • Structure du corps :
{
"generatedAt": "2026-06-16T12:00:00+00:00",
"profile": { "id": "", "username": "", "email": "", "...": "tous les champs du profil" },
"activity": { "followers": 0, "following": 0, "medias": 0, "albums": 0, "comments": 0 },
"medias": [ { "id": "", "name": "", "type": "image", "isPublished": true, "latitude": null, "longitude": null, "shotAt": null, "createdAt": "" } ]
}

Demande de suppression du compte authentifié.

{ "currentPassword": "<mot de passe actuel>" }
  • Comportement selon le type de compte :
    • Compte avec mot de passe : currentPassword est obligatoire. Le compte est soft-deleted immédiatement et toutes ses sessions sont révoquées.
    • Compte OAuth-only (sans mot de passe) : aucun mot de passe à vérifier ; un e-mail de confirmation contenant un lien à usage unique est envoyé. La suppression n’est effective qu’après POST /api/account/deletion/confirm.
  • Réponses :
    • 200 OK — compte soft-deleted (status: "deleted"). Si déjà en attente de suppression : meta.alreadyPending = true.
    • 202 Accepted — e-mail de confirmation envoyé (compte OAuth-only).
    • 401 UnauthorizedcurrentPassword manquant (meta.code = "account.passwordRequired") ou invalide (meta.code = "account.invalidPassword").

Confirme une suppression de compte via le token reçu par e-mail — chemin de fallback pour les comptes OAuth-only sans mot de passe.

  • Auth : aucune (le token autorise l’action). POST volontaire (jamais GET) afin qu’un prefetch de lien par un scanner d’e-mail ne déclenche pas une suppression irréversible.
  • Action : ConfirmAccountDeletionAction
  • Corps (plat ou JSON:API) :
{ "token": "<token base64url issu du lien e-mail>" }
  • Réponses :
    • 200 OK — compte soft-deleted, période de grâce démarrée (status: "deleted", confirmedAt).
    • 410 Gone — token inconnu, expiré ou déjà utilisé (meta.code = "account.deletionTokenInvalid").
    • 422 Unprocessable Entitytoken absent du corps.