docs: add account deletion design spec

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arthur Belleville 2026-04-29 15:34:46 +02:00
parent 9386778e2c
commit 03e1f335bc
No known key found for this signature in database

View file

@ -0,0 +1,61 @@
# Account Deletion — Design Spec
**Date:** 2026-04-27
**Scope:** Expo app + API
## Summary
Add account deletion to the Expo app. Deletion is immediate in terms of auth access (Supabase auth user is hard-deleted), but data is retained in the database (soft delete via `deleted_at`). No purge cron — orphaned data can be cleaned up manually later.
## API
### Endpoint
`DELETE /users/me` — authenticated, added to `apps/api/src/routers/user.ts`.
### Logic
1. Fetch the user's `organization_id` from `profiles`
2. If `organization_id` is set, count profiles with the same `organization_id`
3. If count == 1 (sole member), set `deleted_at = now()` on the `organizations` row
4. Set `deleted_at = now()` on the user's `profiles` row
5. Call `supabase.auth.admin.deleteUser(userId)` to hard-delete the Supabase auth user (revokes all sessions immediately)
6. Return `200 OK`
### Error handling
- If the user's profile is not found, return `404`
- If the Supabase admin delete fails, return `500` and do not set `deleted_at` (keep the operation atomic)
- If the user has no `organization_id`, skip steps 23 and proceed normally
## Database
- Add `deleted_at` column (nullable `timestamptz`) to `profiles` table — requires a Supabase migration
- `organizations` table already exists (referenced by the API, but absent from current generated types which are stale); add `deleted_at` column (nullable `timestamptz`) via migration as well
- No changes to other tables — tablos, tasks, and events are orphaned but inaccessible once auth is revoked
- After migrations, regenerate types: `npx supabase gen types typescript > packages/shared-types/src/database.types.ts`
## UI (Expo)
### Location
New "Danger Zone" section in the Settings screen (`xtablo-expo/app/(app)/(tabs)/settings.tsx`), positioned above the Sign Out button.
### Flow
1. User taps "Delete Account" in the Danger Zone section
2. Native `Alert` — warning message: account will be permanently deleted; if they are the sole owner of an organization, the organization will also be deleted. Buttons: "Cancel" and "Delete my account"
3. On confirm, call `DELETE /users/me` with Bearer token via the existing `api` client
4. On success, call `signOut()` from the auth store to clear local state and navigate to login
5. On error, show a toast with a user-friendly message
### Pattern
Uses native `Alert` dialogs — consistent with the existing logout confirmation pattern. No new screen required.
## Out of Scope
- Purge cron / scheduled data cleanup (deferred)
- Account reactivation / grace period cancellation
- Blocking deletion for sole org owners (org is cascade-deleted instead)
- Email confirmation step