Account Deletion

One endpoint that removes the user and cascades every piece of owned data.

Account deletion is a single authenticated endpoint that removes the user's stored files and then the user row itself, letting database cascades clear everything the account owns. It is the only deletion path — there is no second, partial way to delete an account.

DELETE /api/app/v1/account
→ { "success": true, "data": { "deleted": true } }

What gets deleted

src/server/app/account/accountService.ts runs two steps:

Uploaded files

All objects under the user's storage prefix (uploads/<userId>/) are deleted from the object storage — files are the one thing a database cascade cannot reach. If storage cleanup fails, deletion still proceeds and the failure is logged for a manual sweep, so a storage outage can't hold the account hostage.

The user row + cascades

The Better Auth user row is deleted. Every owned table references user.id with ON DELETE CASCADE, so this clears:

  • session and account (auth sessions, OAuth links)
  • todos
  • device_tokens
  • subscription (the entitlement snapshot)
  • payment (order records)

Design notes

  • Server-side identity only. The route uses authedRoute, so the deleted account is always the session's — there is no user-ID parameter.
  • Better Auth's delete-user endpoint is not enabled. A second public deletion path would skip file cleanup and the cascade guarantees; keeping one path keeps the cleanup complete.
  • Native clients call this endpoint with their Bearer session, then clear the Keychain and local state.
  • Deleting the account does not cancel an App Store subscription — Apple billing is between the user and Apple. The local snapshot row is removed; advise users to cancel via Apple's subscription settings first.

On this page