diff --git a/docs/superpowers/specs/2026-04-27-expo-account-deletion-design.md b/docs/superpowers/specs/2026-04-27-expo-account-deletion-design.md new file mode 100644 index 0000000..0ecafe2 --- /dev/null +++ b/docs/superpowers/specs/2026-04-27-expo-account-deletion-design.md @@ -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