Skip to content

feat(account): full account deletion (GDPR / Play + Apple compliance)#388

Merged
mrviduus merged 1 commit into
mainfrom
feat/account-deletion
Jun 23, 2026
Merged

feat(account): full account deletion (GDPR / Play + Apple compliance)#388
mrviduus merged 1 commit into
mainfrom
feat/account-deletion

Conversation

@mrviduus

Copy link
Copy Markdown
Owner

Why

Google Play (and Apple) require apps with sign-in to let users delete their account + all data in-app. We had no such flow — a hard blocker for the Play Data safety declaration and production access. This adds it end-to-end.

What

BackendDELETE /me/account (auth, rate-limit 3/5min). Transactional cascade delete of every user-owned entity (books/files/chapters/ingestion jobs, reading progress, bookmarks, highlights, vocabulary + reviews + settings/clusters, reading sessions/goals/achievements, library/collections, refresh & password-reset tokens) + best-effort disk cleanup (avatar + user storage dir), now logged on failure instead of swallowed. Audit telemetry (LlmTrace/ShadowRun/AgentRun/DeviceAuthorization) → user_id = NULL (non-PII retention). No migration (relies on existing cascade FKs).

Web — Profile → Edit profile → Danger zone → dialog requiring the user to type DELETEAuthContext.deleteAccount() → clears session → redirect home. Public /:lang/delete-account info page + footer link. i18n strings added.

Mobile — Profile → Danger zone → two-step destructive AlertsignOut() → Home. Honors theme/dark mode; hidden for guests. (Also satisfies Apple's in-app deletion requirement.)

Security note

A short-lived access JWT stays signature-valid after deletion. Treated as bounded, acceptable: refresh-token rows cascade-delete (no new tokens), access TTL ≤60min, no data leakage (owned data gone, reads empty, writes fail at FK). No per-request DB guard added (would tax the hot path). Documented; proper fix (revocation set / shorter TTL) noted if the threat model tightens.

Tests

  • Backend: 2 integration tests (cascade delete + token-no-longer-works, incl. repeat-DELETE → 401).
  • Web: unit (api method + confirm-gating) + 5 Playwright e2e (danger zone, gating, stubbed-204 happy path → logout+redirect, 500 error → session survives, public page). Full chromium suite 44 passed.
  • Mobile: tsc --noEmit clean.

Verify after merge

  • Auto-deploy carries web /delete-account page + endpoint.
  • Rebuild production AAB for the mobile delete button (next Closed-test build).
  • Then Play → Data safety can honestly answer "Yes" (in-app + URL).

🤖 Generated with Claude Code

Add DELETE /me/account — transactional cascade delete of all user data
(books/files/chapters, progress, bookmarks, highlights, vocab+reviews,
sessions/goals/achievements, collections, avatar, refresh/reset tokens)
+ best-effort disk cleanup (logged on failure). Audit telemetry user_id
set NULL (non-PII retention). Rate-limited 3/5min.

Web: profile Danger zone -> type-DELETE confirm -> logout+redirect;
public /delete-account info page. Mobile: profile Danger zone -> two-step
Alert -> signOut. Stale access token accepted as bounded risk (refresh
cascade-deleted, <=60min TTL, no leakage).

Tests: 2 backend integration, web unit (api + confirm-gating), 5 e2e.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mrviduus mrviduus merged commit c2835cb into main Jun 23, 2026
5 checks passed
@mrviduus mrviduus deleted the feat/account-deletion branch June 23, 2026 00:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant