From 4eaa8731c4e5c46f90da17a3d53817a858f0f671 Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Wed, 29 Apr 2026 18:22:36 +0200 Subject: [PATCH] fix(api): remove redundant profile soft-delete profiles.id has ON DELETE CASCADE from auth.users, so calling auth.admin.deleteUser already removes the profile row. Only the org soft-delete needs to happen explicitly. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- apps/api/src/routers/user.ts | 22 ++----------------- ...leted_at_to_profiles_and_organizations.sql | 1 - 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/apps/api/src/routers/user.ts b/apps/api/src/routers/user.ts index 8345664..a565542 100644 --- a/apps/api/src/routers/user.ts +++ b/apps/api/src/routers/user.ts @@ -815,7 +815,6 @@ const deleteMe = factory.createHandlers(async (c) => { } const profile = rawProfile as typeof rawProfile & { organization_id: number | null }; - const deletedAt = new Date().toISOString(); let orgWasSoftDeleted = false; if (profile.organization_id) { @@ -828,7 +827,7 @@ const deleteMe = factory.createHandlers(async (c) => { console.warn("Failed to count org members during account deletion, skipping org soft-delete:", countError.message); } else if ((count ?? 0) === 1) { const { error: orgDeleteError } = await (supabase.from("organizations") as any) - .update({ deleted_at: deletedAt }) + .update({ deleted_at: new Date().toISOString() }) .eq("id", profile.organization_id); if (orgDeleteError) { return c.json({ error: "Failed to delete account" }, 500); @@ -837,27 +836,10 @@ const deleteMe = factory.createHandlers(async (c) => { } } - const { error: profileDeleteError } = await (supabase.from("profiles") as any) - .update({ deleted_at: deletedAt }) - .eq("id", user.id); - - if (profileDeleteError) { - if (orgWasSoftDeleted) { - const { error: rollbackErr } = await (supabase.from("organizations") as any) - .update({ deleted_at: null }) - .eq("id", profile.organization_id); - if (rollbackErr) console.error("Failed to roll back org soft-delete:", rollbackErr.message); - } - return c.json({ error: "Failed to delete account" }, 500); - } - + // Deleting the auth user cascades to profiles via FK (profiles_id_fkey ON DELETE CASCADE) const { error: authDeleteError } = await supabase.auth.admin.deleteUser(user.id); if (authDeleteError) { - const { error: profileRollbackErr } = await (supabase.from("profiles") as any) - .update({ deleted_at: null }) - .eq("id", user.id); - if (profileRollbackErr) console.error("Failed to roll back profile soft-delete:", profileRollbackErr.message); if (orgWasSoftDeleted) { const { error: orgRollbackErr } = await (supabase.from("organizations") as any) .update({ deleted_at: null }) diff --git a/supabase/migrations/20260427120000_add_deleted_at_to_profiles_and_organizations.sql b/supabase/migrations/20260427120000_add_deleted_at_to_profiles_and_organizations.sql index 4652ae0..0da148e 100644 --- a/supabase/migrations/20260427120000_add_deleted_at_to_profiles_and_organizations.sql +++ b/supabase/migrations/20260427120000_add_deleted_at_to_profiles_and_organizations.sql @@ -1,2 +1 @@ -ALTER TABLE profiles ADD COLUMN IF NOT EXISTS deleted_at timestamptz DEFAULT NULL; ALTER TABLE organizations ADD COLUMN IF NOT EXISTS deleted_at timestamptz DEFAULT NULL;