feat(api): DELETE /api/account for permanent account removal (#126)#151
Conversation
Implement permanent account deletion in a DB transaction by deleting the users row; dependent personal data cascades per schema FKs. Clear the auth cookie after the attempt so JWT cookies cannot be reused. Part of #126 Made-with: Cursor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds account deletion: a new Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API as "API Route\nDELETE /api/account"
participant Auth as "Auth (getCurrentUser)"
participant DB as "Database\ndeleteUserAccount"
Client->>API: DELETE /api/account (with cookies)
API->>Auth: getCurrentUser()
alt not authenticated
Auth-->>API: null
API-->>Client: 401 { error: "Unauthorized" }
else authenticated
Auth-->>API: { userId }
API->>DB: deleteUserAccount(userId)
alt deletion failed (not found)
DB-->>API: false
API->>API: clear auth cookie (best-effort)
API-->>Client: 404 { error: "Account not found" }
else deletion succeeded
DB-->>API: true
API->>API: clear auth cookie (best-effort)
API-->>Client: 200 { ok: true }
end
end
opt unexpected error
API-->>Client: 500 { error: "Internal server error" }
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/app/api/account/route.ts`:
- Around line 16-27: The current handler treats clearAuthCookie() failures as
fatal even when deleteUserAccount(auth.userId) succeeded; change this so
deletion result is authoritative by making clearAuthCookie() best-effort: after
awaiting deleteUserAccount, if deleted is true attempt clearAuthCookie() inside
its own try/catch and log any cookie-clearing error without returning a 500,
then return the successful JSON response; only propagate a 500 if
deleteUserAccount failed or an unrelated error occurs outside the cookie-clear
catch. Reference deleteUserAccount and clearAuthCookie to locate the changes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9c31c509-80b8-43d8-b01b-ab30e5ffec4c
📒 Files selected for processing (2)
src/app/api/account/route.tssrc/lib/accountDeletion.ts
| await clearAuthCookie(); | ||
|
|
||
| if (!deleted) { | ||
| return NextResponse.json({ error: "Account not found" }, { status: 404 }); | ||
| } | ||
|
|
CodeRabbit: avoid turning a successful DB delete into 500 if clearAuthCookie throws. Vercel review: clear cookie only after we know delete outcome so stale-token 404 still invalidates the session without implying a row existed. Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
Summary
Part of #126 (App Store Guideline 5.1.1(v)). Adds a server-side endpoint so an authenticated user can permanently delete their account and associated personal data.
Why
DELETE /api/accountREST maps the authenticated user’s account to a single resource URI.
DELETEis idempotent at the HTTP level (repeat calls after deletion are handled safely) and matches common “delete my account” semantics without a JSON body.Auth
getCurrentUser()from thesp_tokencookie; 401 if missing/invalid (middleware + handler).WHERE id = auth.userId).Data / transaction
All FKs from
users.idinsrc/db/schema.tsuseonDelete: "cascade":buddy_sessions(host),buddy_session_participants(participant),sessions(owner),thoughts(owner),friend_requests(from/to),friendships(either side).The implementation runs
DELETE FROM users WHERE id = …inside a single Drizzle transaction. Postgres applies cascades in a valid order; no orphaned rows for this user’s owned data.Co-participants:
sessions.buddy_session_id→buddy_sessionsisonDelete: "set null". If the deleted user was a buddy host, theirbuddy_sessionsrow goes away and other users’ personalsessionsrows that pointed at that buddy sit getbuddy_session_idnulled (they are not deleted).Session
JWT is stateless; after a successful delete (or missing user with a stale token), we call
clearAuthCookie()(same as/api/auth/logout) so the cookie cannot be reused.Response
{ "ok": true }after a row was deleted.{ "error": "Account not found" }if the token user id has no row (cookie still cleared).Tests
This repo has no
npm test/ test runner inpackage.json. Verification for this PR:npm run build(passes).Manual verification (
curl)POST /api/auth/login) so the browser/client hassp_token.{"ok":true}, thenGET /api/auth/mewith the same cookie should yield 401 (cookie cleared on delete response — re-send cookie only if you captured it before the delete response strips it).Do not commit tokens or
.envcontents.Made with Cursor
Summary by CodeRabbit