feat: cleanup tables (#14203)

#### PR Dependency Tree


* **PR #14203** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Removed deprecated database tables, enums and schema fields (cleanup
of legacy subscription, invoice, runtime settings and session expiry
data). This includes irreversible data removal for those legacy
elements.
* **Tests**
* Updated tests and test data to align with the cleaned-up schema and
removed fields.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-01-03 03:50:14 +08:00
committed by GitHub
parent 41addfe311
commit 3633c75c6f
10 changed files with 59 additions and 173 deletions
@@ -0,0 +1,38 @@
/*
Warnings:
- You are about to drop the column `expires_at` on the `multiple_users_sessions` table. All the data in the column will be lost.
- You are about to drop the column `seq` on the `snapshots` table. All the data in the column will be lost.
- You are about to drop the column `seq` on the `updates` table. All the data in the column will be lost.
- You are about to drop the column `accepted` on the `workspace_user_permissions` table. All the data in the column will be lost.
- You are about to drop the `app_runtime_settings` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the `user_invoices` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the `user_subscriptions` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "app_runtime_settings" DROP CONSTRAINT "app_runtime_settings_last_updated_by_fkey";
-- AlterTable
ALTER TABLE "multiple_users_sessions" DROP COLUMN "expires_at";
-- AlterTable
ALTER TABLE "snapshots" DROP COLUMN "seq";
-- AlterTable
ALTER TABLE "updates" DROP COLUMN "seq";
-- AlterTable
ALTER TABLE "workspace_user_permissions" DROP COLUMN "accepted";
-- DropTable
DROP TABLE "app_runtime_settings";
-- DropTable
DROP TABLE "user_invoices";
-- DropTable
DROP TABLE "user_subscriptions";
-- DropEnum
DROP TYPE "RuntimeConfigType";
+21 -119
View File
@@ -25,31 +25,29 @@ model User {
registered Boolean @default(true)
disabled Boolean @default(false)
features UserFeature[]
userStripeCustomer UserStripeCustomer?
workspaces WorkspaceUserRole[]
features UserFeature[]
userStripeCustomer UserStripeCustomer?
workspaces WorkspaceUserRole[]
// Invite others to join the workspace
WorkspaceInvitations WorkspaceUserRole[] @relation("inviter")
docPermissions WorkspaceDocUserRole[]
connectedAccounts ConnectedAccount[]
sessions UserSession[]
aiSessions AiSession[]
/// @deprecated
deprecatedAppRuntimeSettings DeprecatedAppRuntimeSettings[]
appConfigs AppConfig[]
userSnapshots UserSnapshot[]
createdSnapshot Snapshot[] @relation("createdSnapshot")
updatedSnapshot Snapshot[] @relation("updatedSnapshot")
createdUpdate Update[] @relation("createdUpdate")
createdHistory SnapshotHistory[] @relation("createdHistory")
createdAiJobs AiJobs[] @relation("createdAiJobs")
WorkspaceInvitations WorkspaceUserRole[] @relation("inviter")
docPermissions WorkspaceDocUserRole[]
connectedAccounts ConnectedAccount[]
sessions UserSession[]
aiSessions AiSession[]
appConfigs AppConfig[]
userSnapshots UserSnapshot[]
createdSnapshot Snapshot[] @relation("createdSnapshot")
updatedSnapshot Snapshot[] @relation("updatedSnapshot")
createdUpdate Update[] @relation("createdUpdate")
createdHistory SnapshotHistory[] @relation("createdHistory")
createdAiJobs AiJobs[] @relation("createdAiJobs")
// receive notifications
notifications Notification[] @relation("user_notifications")
settings UserSettings?
comments Comment[]
replies Reply[]
commentAttachments CommentAttachment[] @relation("createdCommentAttachments")
AccessToken AccessToken[]
notifications Notification[] @relation("user_notifications")
settings UserSettings?
comments Comment[]
replies Reply[]
commentAttachments CommentAttachment[] @relation("createdCommentAttachments")
AccessToken AccessToken[]
@@index([email])
@@map("users")
@@ -79,9 +77,6 @@ model Session {
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
userSessions UserSession[]
// @deprecated use [UserSession.expiresAt]
deprecated_expiresAt DateTime? @map("expires_at") @db.Timestamptz(3)
@@map("multiple_users_sessions")
}
@@ -207,9 +202,6 @@ model WorkspaceUserRole {
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
inviter User? @relation(name: "inviter", fields: [inviterId], references: [id], onDelete: SetNull)
/// @deprecated Whether the permission invitation is accepted by the user, use status instead
accepted Boolean @default(false)
@@unique([workspaceId, userId])
// optimize for querying user's workspace permissions
@@index([workspaceId, type, status])
@@ -329,9 +321,6 @@ model Snapshot {
createdByUser User? @relation(name: "createdSnapshot", fields: [createdBy], references: [id], onDelete: SetNull)
updatedByUser User? @relation(name: "updatedSnapshot", fields: [updatedBy], references: [id], onDelete: SetNull)
// @deprecated use updatedAt only
seq Int? @default(0) @db.Integer
// we need to clear all hanging updates and snapshots before enable the foreign key on workspaceId
// workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
@@ -369,9 +358,6 @@ model Update {
// will delete creator record if creator's account is deleted
createdByUser User? @relation(name: "createdUpdate", fields: [createdBy], references: [id], onDelete: SetNull)
// @deprecated use createdAt only
seq Int? @db.Integer
@@id([workspaceId, id, createdAt])
@@map("updates")
}
@@ -645,32 +631,6 @@ model DataMigration {
@@map("_data_migrations")
}
enum RuntimeConfigType {
String
Number
Boolean
Object
Array
}
/// @deprecated use AppConfig instead
model DeprecatedAppRuntimeSettings {
id String @id @db.VarChar
type RuntimeConfigType
module String @db.VarChar
key String @db.VarChar
value Json @db.Json
description String @db.Text
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
deletedAt DateTime? @map("deleted_at") @db.Timestamptz(3)
lastUpdatedBy String? @map("last_updated_by") @db.VarChar
lastUpdatedByUser User? @relation(fields: [lastUpdatedBy], references: [id])
@@unique([module, key])
@@map("app_runtime_settings")
}
model AppConfig {
id String @id @db.VarChar
value Json @db.JsonB
@@ -683,64 +643,6 @@ model AppConfig {
@@map("app_configs")
}
model DeprecatedUserSubscription {
id Int @id @default(autoincrement()) @db.Integer
userId String @map("user_id") @db.VarChar
plan String @db.VarChar(20)
// yearly/monthly/lifetime
recurring String @db.VarChar(20)
// onetime subscription or anything else
variant String? @db.VarChar(20)
// subscription.id, null for lifetime payment or one time payment subscription
stripeSubscriptionId String? @unique @map("stripe_subscription_id")
// subscription.status, active/past_due/canceled/unpaid...
status String @db.VarChar(20)
// subscription.current_period_start
start DateTime @map("start") @db.Timestamptz(3)
// subscription.current_period_end, null for lifetime payment
end DateTime? @map("end") @db.Timestamptz(3)
// subscription.billing_cycle_anchor
nextBillAt DateTime? @map("next_bill_at") @db.Timestamptz(3)
// subscription.canceled_at
canceledAt DateTime? @map("canceled_at") @db.Timestamptz(3)
// subscription.trial_start
trialStart DateTime? @map("trial_start") @db.Timestamptz(3)
// subscription.trial_end
trialEnd DateTime? @map("trial_end") @db.Timestamptz(3)
stripeScheduleId String? @map("stripe_schedule_id") @db.VarChar
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
@@unique([userId, plan])
@@map("user_subscriptions")
}
model DeprecatedUserInvoice {
id Int @id @default(autoincrement()) @db.Integer
userId String @map("user_id") @db.VarChar
stripeInvoiceId String @unique @map("stripe_invoice_id")
currency String @db.VarChar(3)
// CNY 12.50 stored as 1250
amount Int @db.Integer
status String @db.VarChar(20)
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
// billing reason
reason String? @db.VarChar
lastPaymentError String? @map("last_payment_error") @db.Text
// stripe hosted invoice link
link String? @db.Text
// @deprecated
plan String? @db.VarChar(20)
// @deprecated
recurring String? @db.VarChar(20)
@@index([userId])
@@map("user_invoices")
}
model UserStripeCustomer {
userId String @id @map("user_id") @db.VarChar
stripeCustomerId String @unique @map("stripe_customer_id") @db.VarChar
@@ -41,7 +41,6 @@ const snapshot: Snapshot = {
id: 'doc1',
blob: Uint8Array.from([1, 0]),
state: Uint8Array.from([0]),
seq: 0,
size: BigInt(2),
updatedAt: new Date(),
createdAt: new Date(),
@@ -38,7 +38,6 @@ test('should create a new session', async t => {
const session = await t.context.session.createSession();
t.truthy(session.id);
t.truthy(session.createdAt);
t.is(session.deprecated_expiresAt, null);
});
test('should get a exists session', async t => {
@@ -16,7 +16,6 @@ export class WorkspaceResolverMock {
create: {
type: WorkspaceRole.Owner,
userId: user.id,
accepted: true,
status: WorkspaceMemberStatus.Accepted,
},
},
@@ -1,18 +0,0 @@
import { PrismaClient, WorkspaceMemberStatus } from '@prisma/client';
export class MigrateInviteStatus1732861452428 {
// do the migration
static async up(db: PrismaClient) {
await db.workspaceUserRole.updateMany({
where: {
accepted: true,
},
data: {
status: WorkspaceMemberStatus.Accepted,
},
});
}
// revert the migration
static async down(_db: PrismaClient) {}
}
@@ -1,29 +0,0 @@
import { PrismaClient } from '@prisma/client';
import { loop } from './utils/loop';
export class UniversalSubscription1733125339942 {
// do the migration
static async up(db: PrismaClient) {
await loop(async (offset, take) => {
const oldSubscriptions = await db.deprecatedUserSubscription.findMany({
skip: offset,
take,
});
await db.subscription.createMany({
data: oldSubscriptions.map(({ userId, ...subscription }) => ({
targetId: userId,
...subscription,
})),
});
return oldSubscriptions.length;
}, 50);
}
// revert the migration
static async down(_db: PrismaClient) {
// noop
}
}
@@ -1,7 +1,5 @@
export * from './1698398506533-guid';
export * from './1703756315970-unamed-account';
export * from './1721299086340-refresh-unnamed-user';
export * from './1732861452428-migrate-invite-status';
export * from './1733125339942-universal-subscription';
export * from './1745211351719-create-indexer-tables';
export * from './1751966744168-correct-session-update-time';
@@ -61,7 +61,6 @@ export class DocModel extends BaseModel {
blob: record.blob,
createdAt: new Date(record.timestamp),
createdBy: record.editorId || null,
seq: null,
};
}
-1
View File
@@ -92,7 +92,6 @@ export async function addUserToWorkspace(
data: {
workspaceId: workspace.id,
userId,
accepted: true,
status: 'Accepted',
type: permission,
},