Acheteur Account Deletion
Summary
An authenticated acheteur can permanently delete their account by submitting their current password and an optional reason. The system verifies the password, then performs a RGPD-compliant soft-delete and anonymization via a shared anonymizeAndSoftDelete() helper — the same code path used by admin-initiated deletion. All personal data is overwritten, related records cascade-deleted, and an audit entry is created. A SHA-256 hash of the pre-anonymization email is sent to Slack for traceability without storing PII. The session cookie is cleared.
State Diagram
stateDiagram-v2 state "Suppression demandée" as DeleteRequested state "Mot de passe invalide" as PasswordInvalid state "Anonymisation en cours" as Anonymizing state "Données anonymisées" as DataAnonymized state "Enregistrements liés supprimés" as RelatedRecordsDeleted state "Dossiers prêt anonymisés" as MortgageAppsAnonymized state "Audit créé" as AuditCreated state "Fichiers supprimés" as FilesDeleted state "Slack notifié" as SlackNotified state "Cookie effacé" as CookieCleared [*] --> DeleteRequested: acheteur requests account deletion DeleteRequested --> PasswordInvalid: password does not match PasswordInvalid --> [*]: 401 UNAUTHORIZED DeleteRequested --> Anonymizing: password verified Anonymizing --> DataAnonymized: acheteur row PII wiped, deletedAt set DataAnonymized --> RelatedRecordsDeleted: refresh tokens, favorites, mortgage docs, co-borrowers, broker assignments deleted RelatedRecordsDeleted --> MortgageAppsAnonymized: profileData/financialData cleared on applications MortgageAppsAnonymized --> AuditCreated: AcheteurAccountAction logged AuditCreated --> FilesDeleted: physical mortgage document files removed (best-effort) FilesDeleted --> SlackNotified: SHA-256 email hash posted to Slack (fire-and-forget) SlackNotified --> CookieCleared: acheteurRefreshToken cookie expired CookieCleared --> [*]: 200 returned, account deleted
Steps
1. Submit Deletion Request (Actor: acheteur)
Client sends DELETE /acheteur/profile with { password, reason? }.
Rate limit: 10 requests per minute, keyed on acheteurId.
Outcome: Request reaches the handler.
2. Password Verification (Actor: system)
The acheteur row is fetched. If not found → 404 NOT_FOUND. The submitted password is verified against passwordHash. Google-only accounts (passwordHash: null) → 401 UNAUTHORIZED (they cannot self-delete via this route as-is).
A SHA-256 hash of acheteur.email is computed before anonymization wipes it — used for the Slack notification.
Outcome: emailHash computed, acheteur identity confirmed.
3. Anonymize & Soft-Delete (Actor: system)
anonymizeAndSoftDelete(acheteurId, null, reason ?? "Demande de l'utilisateur", logger) is called. This is the RGPD invariant — diverging from this shared helper is a data-leak risk.
Inside a single Prisma transaction:
acheteurrow:firstName → "",lastName/phone/passwordHash/googleId → null,email → "deleted-<uuid>@removed.local",deletedAtanddeletedBy: "self"set.acheteurRefreshTokenrows deleted.favoriterows deleted.mortgageDocumentrows deleted.coBorrowerrows deleted.brokerAssignmentrows deleted.mortgageApplicationrows:profileDataandfinancialDatacleared to{}.AcheteurAccountActionaudit entry created:action: "deleted",reason,performedBy: null(self-service).
After the transaction: physical mortgage document files are deleted from disk concurrently via Promise.allSettled (best-effort — failures are logged but do not roll back the transaction).
Outcome: Account fully anonymized, all sensitive data removed.
4. Slack Notification (Actor: system)
notifyAcheteurDeleted(emailHash, reason) is called (fire-and-forget). Errors are logged but do not affect the response. The hash allows internal identification without exposing PII in Slack.
Outcome: Slack notification posted (or silently failed).
5. Clear Session (Actor: system)
The acheteurRefreshToken cookie is overwritten with an empty value and maxAge: 0, expiring it immediately.
Outcome: 200 { data: { message: "Compte supprimé." } }.
Error States
- Wrong password → 401
UNAUTHORIZED— “Mot de passe incorrect.” - Account not found (race condition) → 404
NOT_FOUND - Slack notification failure → logged, non-blocking
- Physical file deletion failure → logged per file, non-blocking (transaction already committed)
Related Processes
- registration-email-verification — starts the lifecycle that this process terminates
- profile-management — for non-destructive account changes