diff --git a/apps/api/src/routers/user.ts b/apps/api/src/routers/user.ts index 2e20429..69f1e8e 100644 --- a/apps/api/src/routers/user.ts +++ b/apps/api/src/routers/user.ts @@ -713,9 +713,48 @@ const deleteMe = factory.createHandlers(async (c) => { const user = c.get("user"); const supabase = c.get("supabase"); + const { data: rawProfile, error: profileError } = await supabase + .from("profiles") + .select("organization_id") + .eq("id", user.id) + .single(); + + if (profileError || !rawProfile) { + return c.json({ error: "User not found" }, 404); + } + + const profile = rawProfile as typeof rawProfile & { organization_id: number | null }; + let orgWasSoftDeleted = false; + + if (profile.organization_id) { + const { count, error: countError } = await supabase + .from("profiles") + .select("id", { count: "exact", head: true }) + .eq("organization_id", profile.organization_id); + + if (countError) { + 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: new Date().toISOString() }) + .eq("id", profile.organization_id); + if (orgDeleteError) { + return c.json({ error: "Failed to delete account" }, 500); + } + orgWasSoftDeleted = true; + } + } + + // 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) { + if (orgWasSoftDeleted) { + const { error: orgRollbackErr } = await (supabase.from("organizations") as any) + .update({ deleted_at: null }) + .eq("id", profile.organization_id); + if (orgRollbackErr) console.error("Failed to roll back org soft-delete:", orgRollbackErr.message); + } return c.json({ error: "Failed to delete account" }, 500); } 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 new file mode 100644 index 0000000..0da148e --- /dev/null +++ b/supabase/migrations/20260427120000_add_deleted_at_to_profiles_and_organizations.sql @@ -0,0 +1 @@ +ALTER TABLE organizations ADD COLUMN IF NOT EXISTS deleted_at timestamptz DEFAULT NULL;