Reintroduce the user-facing erasure endpoint + route wiring, orchestrated over the provider registry (no static cross-module imports).
Scope — users.data.controller.js + routes
Erasure orchestration (DELETE /api/users/me/data):
- Re-auth proof required (see re-auth hardening sub-issue) + strict rate limiter (
limiters.auth) on the route.
- Re-entrancy guard: in-flight erasure flag → concurrent DELETE = 409.
- Resolve + snapshot axes ONCE:
{ soleOwnedOrgIds, sharedOrgIds } via memberships.
- Write the ErasureRequest ledger doc BEFORE the first destructive call — a retry re-reads the snapshot (memberships are deleted mid-run; request-time re-resolution after a partial failure would silently skip org-axis providers).
- Run
validate() across ALL providers — any blocker aborts before any deletion (predictable blockers surface pre-destruction).
- Phases: external + org-axis (sole-owned only) → user-axis → organizations/memberships → clear cross-refs (
referredBy) → confirmation email (Art 12(3), terminal outward action) → UserService.remove LAST.
- Response = erasure receipt (per-provider
{removed, retained, messages}).
- REMOVE
DELETE /api/users entirely (single erasure door; breaking note in MIGRATIONS.md). A deprecated-but-routable legacy route would remain a second door that still orphans data.
usersExportProjection: exclude password, reset/verification tokens, lockout counters; strip OAuth tokens from providerData and additionalProvidersData.
- Routes
/api/users/me/data (+ /me/data/exports wiring for the async export sub-issue): passport jwt + policy.isAllowed; moderate limiter on the export-request route (fan-out endpoint).
DoD
Depends on: registry leaf v2, ErasureRequest ledger.
Created via /dev:issue · contract v2 2026-07-03
Reintroduce the user-facing erasure endpoint + route wiring, orchestrated over the provider registry (no static cross-module imports).
Scope —
users.data.controller.js+ routesErasure orchestration (
DELETE /api/users/me/data):limiters.auth) on the route.{ soleOwnedOrgIds, sharedOrgIds }via memberships.validate()across ALL providers — any blocker aborts before any deletion (predictable blockers surface pre-destruction).referredBy) → confirmation email (Art 12(3), terminal outward action) →UserService.removeLAST.{removed, retained, messages}).DELETE /api/usersentirely (single erasure door; breaking note in MIGRATIONS.md). A deprecated-but-routable legacy route would remain a second door that still orphans data.usersExportProjection: exclude password, reset/verification tokens, lockout counters; strip OAuth tokens fromproviderDataandadditionalProvidersData./api/users/me/data(+/me/data/exportswiring for the async export sub-issue):passportjwt +policy.isAllowed; moderate limiter on the export-request route (fan-out endpoint).DoD
DELETE /api/usersgone (404)./verify+/dev:verify-qagreen.Depends on: registry leaf v2, ErasureRequest ledger.
Created via /dev:issue · contract v2 2026-07-03