feat: account deletion flow (#117) #203
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/117-account-deletion"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #117. Final issue of v3.8.0 Privacy & Data Lifecycle — with this, the milestone is complete.
Self-service and admin account deletion with an orphan-free cascade.
Backend (
62f2af7)is_systemflag); migrationa3b4c5d6e7f8seeds it + excludesis_systemfrom user listings and the first-user-admin bootstrap count. Round-trips.delete_user_account: sole-GM BLOCK first (nothing mutates on 409, body lists blocking campaigns); then a full 26-FKusers.idsweep — delete personal data (memberships, platform links, feedback, availability/absences, attendance proposals, private notes), anonymize authored content to the tombstone (votes, attendance, session authorship, lore ownership/versions/drafts, loot/XP/gold ledger, milestones, highlights, shared notes — collision-guarded on unique constraints);audit_logs.actor_idleft as-is. Oneuser.deletedaudit attributed to the actor. Single transaction.DELETE /api/me(self, 409 sole-GM),DELETE /api/admin/users/{id}(admin; 403/404/400-system/409). OIDC deletion is local-only — re-login with the same sub yields a fresh empty user (tested).Frontend (
<head>)/auth/logout; 409 shows the sole-GM blocking list.ApiErrornow carries the parsed.bodyso the 409{campaigns}list is available to the UI.Tests
test_account_deletion.py) — sole-GM block+proceed, full-cascade no-orphans + remaining-member HTTP reads, tombstone→"Deleted user", OIDC re-login, actor-attributed audit, admin authz. Full suite 575 pass; migration round-trip verified.Notes (fixes found during authoritative verification)
uuidcolumn (DatatypeMismatchError) — added an explicitCAST.synchronize_session=False; expunged the deleted user + adjusted the shared-session HTTP-read test (production is unaffected — per-request sessions read fresh).DELETE /api/me(not/api/users/me) — matches the existingupdateMesibling.🤖 Generated with Claude Code
Self-service and admin account deletion with an orphan-free cascade. - Reserved "Deleted user" tombstone (fixed UUID, is_system flag); migration a3b4c5d6e7f8 seeds it + excludes is_system from user listings + the first-user-admin bootstrap count. (round-trips) - account_deletion_service.delete_user_account: sole-GM BLOCK first (nothing mutates on 409, body lists blocking campaigns); then a full users.id FK sweep (26 refs) — delete personal rows (memberships, platform links, feedback, availability/absences, attendance proposals, private notes), anonymize authored content to the tombstone (votes, attendance, session authorship, lore ownership/versions/drafts, loot/XP/gold ledger, milestones, highlights, shared notes — collision-guarded on unique constraints); audit_logs.actor_id left as-is. user.deleted audit attributed to the actor (self or admin). One transaction. - Endpoints: DELETE /users/me (self, 409 sole-GM) and DELETE /admin/users/{id} (admin; 403/404/400-system/409). OIDC deletion is local-only — re-login with the same sub creates a fresh empty user (tested). Loot/gold FKs repoint to the tombstone rather than SET NULL (NULL means "party pool" there, so nulling would silently reassign a deleted member's items). Tests: +14 (test_account_deletion.py) — sole-GM block+proceed, full cascade no-orphans + remaining-member HTTP reads, tombstone→"Deleted user", OIDC re-login, actor-attributed audit, admin authz. Full suite 575 pass; migration round-trip verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>- api/client.js: ApiError now carries the parsed .body so callers can read the 409 sole-GM {campaigns} list. - api/auth.js: deleteMe (DELETE /api/me) + adminDeleteUser (DELETE /api/admin/users/{id}). - Profile: "Danger zone" — GM-campaign export links ("download your data first"), a local-only/OIDC-re-login note, and a "Delete account" button → type-to-confirm modal (type your display name) → deleteMe → full-page redirect to /auth/logout on success; 409 shows the sole-GM blocking list. - Admin Users tab: per-row "Delete" (hidden for own row) → type-to-confirm → adminDeleteUser → removes the row; 409 shows the sole-GM message. Tests: +11 (auth wrappers 2, Profile 5, Admin 4). 307 pass, eslint clean, vite build succeeds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>