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’environnement | Défaut | Rôle |
|---|---|---|
ACCOUNT_DELETION_GRACE_DAYS | 30 | Jours pendant lesquels un compte soft-deleted reste restaurable avant purge irréversible. |
ACCOUNT_DELETION_TOKEN_TTL_HOURS | 24 | Validité du token e-mail de confirmation (comptes OAuth sans mot de passe). |
ACCOUNT_PURGE_BATCH_SIZE | 50 | Comptes traités par tick de bin/account-purge.php. |
ACCOUNT_PURGE_MEDIA_BATCH_SIZE | 100 | Mé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.
GET /api/users/me/export
Section titled “GET /api/users/me/export”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-8Content-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": "…" } ]}DELETE /api/users/me
Section titled “DELETE /api/users/me”Demande de suppression du compte authentifié.
- Auth : requise (Bearer)
- Action : RequestAccountDeletionAction
- Corps (optionnel, plat ou JSON:API) :
{ "currentPassword": "<mot de passe actuel>" }- Comportement selon le type de compte :
- Compte avec mot de passe :
currentPasswordest 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.
- Compte avec mot de passe :
- 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 Unauthorized—currentPasswordmanquant (meta.code = "account.passwordRequired") ou invalide (meta.code = "account.invalidPassword").
POST /api/account/deletion/confirm
Section titled “POST /api/account/deletion/confirm”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 Entity—tokenabsent du corps.