feat: add account deletion functionality with cascade delete for work… (#33)
* feat: add account deletion functionality with cascade delete for workspace relations * fix: add cascade delete to workspace user foreign key constraints * fix: change onDelete action to set null for user references in schema * feat: tweak design --------- Co-authored-by: Henry <henry_ball@hotmail.co.uk> Co-authored-by: Henry <30578846+hjball@users.noreply.github.com>
This commit is contained in:
@@ -112,6 +112,9 @@ export const initAuth = (db: dbClient) => {
|
||||
}),
|
||||
socialProviders: configuredProviders,
|
||||
user: {
|
||||
deleteUser: {
|
||||
enabled: true,
|
||||
},
|
||||
additionalFields: {
|
||||
stripeCustomerId: {
|
||||
type: "string",
|
||||
|
||||
@@ -76,4 +76,4 @@ DO $$ BEGIN
|
||||
ALTER TABLE "card_comments" ADD CONSTRAINT "card_comments_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
END $$;
|
||||
@@ -0,0 +1,152 @@
|
||||
ALTER TABLE "board" DROP CONSTRAINT "board_createdBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "board" DROP CONSTRAINT "board_deletedBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "card_activity" DROP CONSTRAINT "card_activity_workspaceMemberId_workspace_members_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "card_activity" DROP CONSTRAINT "card_activity_createdBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "card" DROP CONSTRAINT "card_createdBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "card" DROP CONSTRAINT "card_deletedBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "card_comments" DROP CONSTRAINT "card_comments_createdBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "card_comments" DROP CONSTRAINT "card_comments_deletedBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "feedback" DROP CONSTRAINT "feedback_createdBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "import" DROP CONSTRAINT "import_createdBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "label" DROP CONSTRAINT "label_createdBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "label" DROP CONSTRAINT "label_deletedBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "list" DROP CONSTRAINT "list_createdBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "list" DROP CONSTRAINT "list_deletedBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "workspace_members" DROP CONSTRAINT "workspace_members_userId_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "workspace_members" DROP CONSTRAINT "workspace_members_deletedBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "workspace" DROP CONSTRAINT "workspace_createdBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "workspace" DROP CONSTRAINT "workspace_deletedBy_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "board" ALTER COLUMN "createdBy" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "card_activity" ALTER COLUMN "createdBy" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "card" ALTER COLUMN "createdBy" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "card_comments" ALTER COLUMN "createdBy" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "feedback" ALTER COLUMN "createdBy" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "import" ALTER COLUMN "createdBy" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "label" ALTER COLUMN "createdBy" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "list" ALTER COLUMN "createdBy" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "workspace" ALTER COLUMN "createdBy" DROP NOT NULL;--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "board" ADD CONSTRAINT "board_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "board" ADD CONSTRAINT "board_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_workspaceMemberId_workspace_members_id_fk" FOREIGN KEY ("workspaceMemberId") REFERENCES "public"."workspace_members"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card" ADD CONSTRAINT "card_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card" ADD CONSTRAINT "card_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_comments" ADD CONSTRAINT "card_comments_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_comments" ADD CONSTRAINT "card_comments_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "feedback" ADD CONSTRAINT "feedback_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "import" ADD CONSTRAINT "import_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "label" ADD CONSTRAINT "label_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "label" ADD CONSTRAINT "label_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "list" ADD CONSTRAINT "list_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "list" ADD CONSTRAINT "list_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "workspace_members" ADD CONSTRAINT "workspace_members_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "workspace_members" ADD CONSTRAINT "workspace_members_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "workspace" ADD CONSTRAINT "workspace_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "workspace" ADD CONSTRAINT "workspace_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
2087
packages/db/migrations/meta/20250608175448_snapshot.json
Normal file
2087
packages/db/migrations/meta/20250608175448_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -29,6 +29,13 @@
|
||||
"when": 1749118315675,
|
||||
"tag": "20250605101155_AddCascadeDeleteToCardRelations",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "7",
|
||||
"when": 1749405288761,
|
||||
"tag": "20250608175448_AddOnDeleteActionToUserDeletion",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -33,13 +33,15 @@ export const boards = pgTable(
|
||||
name: varchar("name", { length: 255 }).notNull(),
|
||||
description: text("description"),
|
||||
slug: varchar("slug", { length: 255 }).notNull(),
|
||||
createdBy: uuid("createdBy")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt"),
|
||||
deletedAt: timestamp("deletedAt"),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
importId: bigint("importId", { mode: "number" }).references(
|
||||
() => imports.id,
|
||||
),
|
||||
|
||||
@@ -44,13 +44,15 @@ export const cards = pgTable("card", {
|
||||
title: varchar("title", { length: 255 }).notNull(),
|
||||
description: text("description"),
|
||||
index: integer("index").notNull(),
|
||||
createdBy: uuid("createdBy")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt"),
|
||||
deletedAt: timestamp("deletedAt"),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
listId: bigint("listId", { mode: "number" })
|
||||
.notNull()
|
||||
.references(() => lists.id, { onDelete: "cascade" }),
|
||||
@@ -105,14 +107,14 @@ export const cardActivities = pgTable("card_activity", {
|
||||
}),
|
||||
workspaceMemberId: bigint("workspaceMemberId", {
|
||||
mode: "number",
|
||||
}).references(() => workspaceMembers.id, { onDelete: "cascade" }),
|
||||
}).references(() => workspaceMembers.id, { onDelete: "set null" }),
|
||||
fromTitle: varchar("fromTitle", { length: 255 }),
|
||||
toTitle: varchar("toTitle", { length: 255 }),
|
||||
fromDescription: text("fromDescription"),
|
||||
toDescription: text("toDescription"),
|
||||
createdBy: uuid("createdBy")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
commentId: bigint("commentId", { mode: "number" }).references(
|
||||
() => comments.id,
|
||||
@@ -227,14 +229,14 @@ export const comments = pgTable("card_comments", {
|
||||
cardId: bigint("cardId", { mode: "number" })
|
||||
.notNull()
|
||||
.references(() => cards.id, { onDelete: "cascade" }),
|
||||
createdBy: uuid("createdBy")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt"),
|
||||
deletedAt: timestamp("deletedAt"),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id, {
|
||||
onDelete: "cascade",
|
||||
onDelete: "set null",
|
||||
}),
|
||||
}).enableRLS();
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ import { users } from "./users";
|
||||
export const feedback = pgTable("feedback", {
|
||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||
feedback: text("feedback").notNull(),
|
||||
createdBy: uuid("createdBy")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt"),
|
||||
url: text("url").notNull(),
|
||||
|
||||
@@ -26,9 +26,9 @@ export const imports = pgTable("import", {
|
||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||
source: importSourceEnum("source").notNull(),
|
||||
status: importStatusEnum("status").notNull(),
|
||||
createdBy: uuid("createdBy")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
}).enableRLS();
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ export const labels = pgTable("label", {
|
||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||
name: varchar("name", { length: 255 }).notNull(),
|
||||
colourCode: varchar("colourCode", { length: 12 }),
|
||||
createdBy: uuid("createdBy")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt"),
|
||||
boardId: bigint("boardId", { mode: "number" })
|
||||
@@ -28,7 +28,9 @@ export const labels = pgTable("label", {
|
||||
.references(() => boards.id, { onDelete: "cascade" }),
|
||||
importId: bigint("importId", { mode: "number" }).references(() => imports.id),
|
||||
deletedAt: timestamp("deletedAt"),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
}).enableRLS();
|
||||
|
||||
export const labelsRelations = relations(labels, ({ one, many }) => ({
|
||||
|
||||
@@ -19,13 +19,15 @@ export const lists = pgTable("list", {
|
||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||
name: varchar("name", { length: 255 }).notNull(),
|
||||
index: integer("index").notNull(),
|
||||
createdBy: uuid("createdBy")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt"),
|
||||
deletedAt: timestamp("deletedAt"),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
boardId: bigint("boardId", { mode: "number" })
|
||||
.notNull()
|
||||
.references(() => boards.id, { onDelete: "cascade" }),
|
||||
|
||||
@@ -36,13 +36,15 @@ export const workspaces = pgTable("workspace", {
|
||||
description: text("description"),
|
||||
slug: varchar("slug", { length: 255 }).notNull().unique(),
|
||||
plan: workspacePlanEnum("plan").notNull().default("free"),
|
||||
createdBy: uuid("createdBy")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt"),
|
||||
deletedAt: timestamp("deletedAt"),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
}).enableRLS();
|
||||
|
||||
export const workspaceRelations = relations(workspaces, ({ one, many }) => ({
|
||||
@@ -64,7 +66,7 @@ export const workspaceMembers = pgTable("workspace_members", {
|
||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||
email: varchar("email", { length: 255 }).notNull(),
|
||||
userId: uuid("userId").references(() => users.id),
|
||||
userId: uuid("userId").references(() => users.id, { onDelete: "set null" }),
|
||||
workspaceId: bigint("workspaceId", { mode: "number" })
|
||||
.notNull()
|
||||
.references(() => workspaces.id, { onDelete: "cascade" }),
|
||||
@@ -72,7 +74,9 @@ export const workspaceMembers = pgTable("workspace_members", {
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt"),
|
||||
deletedAt: timestamp("deletedAt"),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
role: memberRoleEnum("role").notNull(),
|
||||
status: memberStatusEnum("status").default("invited").notNull(),
|
||||
}).enableRLS();
|
||||
|
||||
Reference in New Issue
Block a user