docs: add account deletion design spec
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9386778e2c
commit
03e1f335bc
1 changed files with 61 additions and 0 deletions
|
|
@ -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 2–3 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
|
||||
Loading…
Reference in a new issue