2023-04-18 06:24:44 +03:00
|
|
|
generator client {
|
2023-09-08 00:32:41 +03:00
|
|
|
provider = "prisma-client-js"
|
2023-10-19 11:59:02 +03:00
|
|
|
binaryTargets = ["native", "debian-openssl-3.0.x", "linux-arm64-openssl-3.0.x"]
|
2023-12-28 11:09:10 +03:00
|
|
|
previewFeatures = ["metrics", "tracing", "relationJoins", "nativeDistinct"]
|
2023-04-18 06:24:44 +03:00
|
|
|
}
|
|
|
|
|
2023-06-21 09:08:32 +03:00
|
|
|
datasource db {
|
|
|
|
provider = "postgresql"
|
|
|
|
url = env("DATABASE_URL")
|
2023-04-18 06:24:44 +03:00
|
|
|
}
|
|
|
|
|
2023-11-06 06:49:39 +03:00
|
|
|
model User {
|
|
|
|
id String @id @default(uuid()) @db.VarChar
|
|
|
|
name String
|
|
|
|
email String @unique
|
|
|
|
emailVerified DateTime? @map("email_verified")
|
|
|
|
// image field is for the next-auth
|
|
|
|
avatarUrl String? @map("avatar_url") @db.VarChar
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
/// Not available if user signed up through OAuth providers
|
|
|
|
password String? @db.VarChar
|
|
|
|
|
|
|
|
accounts Account[]
|
|
|
|
sessions Session[]
|
2023-12-13 12:21:14 +03:00
|
|
|
features UserFeatures[]
|
2023-11-06 06:49:39 +03:00
|
|
|
customer UserStripeCustomer?
|
|
|
|
subscription UserSubscription?
|
|
|
|
invoices UserInvoice[]
|
|
|
|
workspacePermissions WorkspaceUserPermission[]
|
|
|
|
pagePermissions WorkspacePageUserPermission[]
|
|
|
|
|
|
|
|
@@map("users")
|
|
|
|
}
|
|
|
|
|
2023-04-28 02:02:05 +03:00
|
|
|
model Workspace {
|
2023-11-06 06:49:39 +03:00
|
|
|
id String @id @default(uuid()) @db.VarChar
|
2023-08-29 13:07:05 +03:00
|
|
|
public Boolean
|
2023-11-06 06:49:39 +03:00
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
|
|
|
|
pages WorkspacePage[]
|
|
|
|
permissions WorkspaceUserPermission[]
|
|
|
|
pagePermissions WorkspacePageUserPermission[]
|
2024-01-05 07:13:44 +03:00
|
|
|
features WorkspaceFeatures[]
|
2023-04-28 02:02:05 +03:00
|
|
|
|
|
|
|
@@map("workspaces")
|
2023-04-18 06:24:44 +03:00
|
|
|
}
|
|
|
|
|
2023-11-06 06:49:39 +03:00
|
|
|
// Table for workspace page meta data
|
|
|
|
// NOTE:
|
|
|
|
// We won't make sure every page has a corresponding record in this table.
|
|
|
|
// Only the ones that have ever changed will have records here,
|
|
|
|
// and for others we will make sure it's has a default value return in our bussiness logic.
|
|
|
|
model WorkspacePage {
|
|
|
|
workspaceId String @map("workspace_id") @db.VarChar(36)
|
|
|
|
pageId String @map("page_id") @db.VarChar(36)
|
|
|
|
public Boolean @default(false)
|
|
|
|
// Page/Edgeless
|
|
|
|
mode Int @default(0) @db.SmallInt
|
|
|
|
|
|
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
@@id([workspaceId, pageId])
|
|
|
|
@@map("workspace_pages")
|
|
|
|
}
|
|
|
|
|
|
|
|
// @deprecated, use WorkspaceUserPermission
|
|
|
|
model DeprecatedUserWorkspacePermission {
|
|
|
|
id String @id @default(uuid()) @db.VarChar
|
|
|
|
workspaceId String @map("workspace_id") @db.VarChar
|
|
|
|
subPageId String? @map("sub_page_id") @db.VarChar
|
|
|
|
userId String? @map("entity_id") @db.VarChar
|
2023-04-28 02:02:05 +03:00
|
|
|
/// Read/Write/Admin/Owner
|
2023-11-06 06:49:39 +03:00
|
|
|
type Int @db.SmallInt
|
2023-04-28 02:02:05 +03:00
|
|
|
/// Whether the permission invitation is accepted by the user
|
2023-11-06 06:49:39 +03:00
|
|
|
accepted Boolean @default(false)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
2023-04-28 02:02:05 +03:00
|
|
|
|
2023-08-29 13:07:05 +03:00
|
|
|
@@unique([workspaceId, subPageId, userId])
|
2023-04-28 02:02:05 +03:00
|
|
|
@@map("user_workspace_permissions")
|
2023-04-18 06:24:44 +03:00
|
|
|
}
|
2023-06-21 09:08:32 +03:00
|
|
|
|
2023-11-06 06:49:39 +03:00
|
|
|
model WorkspaceUserPermission {
|
|
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
|
|
workspaceId String @map("workspace_id") @db.VarChar(36)
|
|
|
|
userId String @map("user_id") @db.VarChar(36)
|
|
|
|
// Read/Write
|
|
|
|
type Int @db.SmallInt
|
|
|
|
/// Whether the permission invitation is accepted by the user
|
|
|
|
accepted Boolean @default(false)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
2023-06-21 09:08:32 +03:00
|
|
|
|
2023-11-06 06:49:39 +03:00
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
@@unique([workspaceId, userId])
|
|
|
|
@@map("workspace_user_permissions")
|
|
|
|
}
|
|
|
|
|
|
|
|
model WorkspacePageUserPermission {
|
|
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
|
|
workspaceId String @map("workspace_id") @db.VarChar(36)
|
|
|
|
pageId String @map("page_id") @db.VarChar(36)
|
|
|
|
userId String @map("user_id") @db.VarChar(36)
|
|
|
|
// Read/Write
|
|
|
|
type Int @db.SmallInt
|
|
|
|
/// Whether the permission invitation is accepted by the user
|
|
|
|
accepted Boolean @default(false)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
@@unique([workspaceId, pageId, userId])
|
|
|
|
@@map("workspace_page_user_permissions")
|
2023-06-21 09:08:32 +03:00
|
|
|
}
|
|
|
|
|
2023-12-13 12:21:14 +03:00
|
|
|
// feature gates is a way to enable/disable features for a user
|
|
|
|
// for example:
|
|
|
|
// - early access is a feature that allow some users to access the insider version
|
|
|
|
// - pro plan is a quota that allow some users access to more resources after they pay
|
|
|
|
model UserFeatures {
|
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
userId String @map("user_id") @db.VarChar(36)
|
|
|
|
featureId Int @map("feature_id") @db.Integer
|
|
|
|
|
|
|
|
// we will record the reason why the feature is enabled/disabled
|
|
|
|
// for example:
|
|
|
|
// - pro_plan_v1: "user buy the pro plan"
|
|
|
|
reason String @db.VarChar
|
|
|
|
// record the quota enabled time
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
// record the quota expired time, pay plan is a subscription, so it will expired
|
|
|
|
expiredAt DateTime? @map("expired_at") @db.Timestamptz(6)
|
|
|
|
// whether the feature is activated
|
|
|
|
// for example:
|
|
|
|
// - if we switch the user to another plan, we will set the old plan to deactivated, but dont delete it
|
|
|
|
activated Boolean @default(false)
|
|
|
|
|
|
|
|
feature Features @relation(fields: [featureId], references: [id], onDelete: Cascade)
|
2024-01-05 07:13:44 +03:00
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
2023-12-13 12:21:14 +03:00
|
|
|
|
|
|
|
@@map("user_features")
|
|
|
|
}
|
|
|
|
|
2024-01-05 07:13:44 +03:00
|
|
|
// feature gates is a way to enable/disable features for a workspace
|
|
|
|
// for example:
|
|
|
|
// - copilet is a feature that allow some users in a workspace to access the copilet feature
|
|
|
|
model WorkspaceFeatures {
|
|
|
|
id Int @id @default(autoincrement())
|
|
|
|
workspaceId String @map("workspace_id") @db.VarChar(36)
|
|
|
|
featureId Int @map("feature_id") @db.Integer
|
|
|
|
|
|
|
|
// we will record the reason why the feature is enabled/disabled
|
|
|
|
// for example:
|
|
|
|
// - copilet_v1: "owner buy the copilet feature package"
|
|
|
|
reason String @db.VarChar
|
|
|
|
// record the feature enabled time
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
// record the quota expired time, pay plan is a subscription, so it will expired
|
|
|
|
expiredAt DateTime? @map("expired_at") @db.Timestamptz(6)
|
|
|
|
// whether the feature is activated
|
|
|
|
// for example:
|
|
|
|
// - if owner unsubscribe a feature package, we will set the feature to deactivated, but dont delete it
|
|
|
|
activated Boolean @default(false)
|
|
|
|
|
|
|
|
feature Features @relation(fields: [featureId], references: [id], onDelete: Cascade)
|
2024-01-05 07:13:47 +03:00
|
|
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
2024-01-05 07:13:44 +03:00
|
|
|
|
|
|
|
@@map("workspace_features")
|
|
|
|
}
|
|
|
|
|
2023-12-13 12:21:14 +03:00
|
|
|
model Features {
|
|
|
|
id Int @id @default(autoincrement())
|
2023-09-08 00:32:41 +03:00
|
|
|
feature String @db.VarChar
|
2023-12-13 12:21:14 +03:00
|
|
|
version Int @default(0) @db.Integer
|
|
|
|
// 0: feature, 1: quota
|
|
|
|
type Int @db.Integer
|
|
|
|
// configs, define by feature conntroller
|
|
|
|
configs Json @db.Json
|
2023-09-08 00:32:41 +03:00
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
|
2024-01-05 07:13:44 +03:00
|
|
|
UserFeatureGates UserFeatures[]
|
|
|
|
WorkspaceFeatures WorkspaceFeatures[]
|
2023-12-13 12:21:14 +03:00
|
|
|
|
|
|
|
@@unique([feature, version])
|
|
|
|
@@map("features")
|
2023-09-08 00:32:41 +03:00
|
|
|
}
|
|
|
|
|
2023-06-21 09:08:32 +03:00
|
|
|
model Account {
|
|
|
|
id String @id @default(cuid())
|
|
|
|
userId String @map("user_id")
|
|
|
|
type String
|
|
|
|
provider String
|
|
|
|
providerAccountId String @map("provider_account_id")
|
|
|
|
refresh_token String? @db.Text
|
|
|
|
access_token String? @db.Text
|
|
|
|
expires_at Int?
|
|
|
|
token_type String?
|
|
|
|
scope String?
|
|
|
|
id_token String? @db.Text
|
|
|
|
session_state String?
|
|
|
|
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
@@unique([provider, providerAccountId])
|
|
|
|
@@map("accounts")
|
|
|
|
}
|
|
|
|
|
|
|
|
model Session {
|
|
|
|
id String @id @default(cuid())
|
|
|
|
sessionToken String @unique @map("session_token")
|
|
|
|
userId String @map("user_id")
|
|
|
|
expires DateTime
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
@@map("sessions")
|
|
|
|
}
|
|
|
|
|
|
|
|
model VerificationToken {
|
|
|
|
identifier String
|
|
|
|
token String @unique
|
|
|
|
expires DateTime
|
|
|
|
|
|
|
|
@@unique([identifier, token])
|
|
|
|
@@map("verificationtokens")
|
|
|
|
}
|
2023-06-29 04:45:45 +03:00
|
|
|
|
2024-01-03 13:56:54 +03:00
|
|
|
// deprecated, use [ObjectStorage]
|
2023-06-29 04:45:45 +03:00
|
|
|
model Blob {
|
2023-11-22 06:31:22 +03:00
|
|
|
id Int @id @default(autoincrement()) @db.Integer
|
|
|
|
hash String @db.VarChar
|
|
|
|
workspaceId String @map("workspace_id") @db.VarChar
|
|
|
|
blob Bytes @db.ByteA
|
2023-08-29 13:07:05 +03:00
|
|
|
length BigInt
|
2023-11-22 06:31:22 +03:00
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
// not for keeping, but for snapshot history
|
|
|
|
deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6)
|
2023-06-29 04:45:45 +03:00
|
|
|
|
|
|
|
@@unique([workspaceId, hash])
|
|
|
|
@@map("blobs")
|
|
|
|
}
|
|
|
|
|
2024-01-03 13:56:54 +03:00
|
|
|
// deprecated, use [ObjectStorage]
|
2023-06-29 04:45:45 +03:00
|
|
|
model OptimizedBlob {
|
2023-11-27 10:06:30 +03:00
|
|
|
id Int @id @default(autoincrement()) @db.Integer
|
|
|
|
hash String @db.VarChar
|
|
|
|
workspaceId String @map("workspace_id") @db.VarChar
|
|
|
|
params String @db.VarChar
|
|
|
|
blob Bytes @db.ByteA
|
2023-08-29 13:07:05 +03:00
|
|
|
length BigInt
|
2023-11-27 10:06:30 +03:00
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
// not for keeping, but for snapshot history
|
|
|
|
deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6)
|
2023-06-29 04:45:45 +03:00
|
|
|
|
|
|
|
@@unique([workspaceId, hash, params])
|
|
|
|
@@map("optimized_blobs")
|
|
|
|
}
|
|
|
|
|
2023-08-29 13:07:05 +03:00
|
|
|
// the latest snapshot of each doc that we've seen
|
|
|
|
// Snapshot + Updates are the latest state of the doc
|
|
|
|
model Snapshot {
|
|
|
|
workspaceId String @map("workspace_id") @db.VarChar
|
2023-11-22 06:31:22 +03:00
|
|
|
id String @default(uuid()) @map("guid") @db.VarChar
|
2023-08-29 13:07:05 +03:00
|
|
|
blob Bytes @db.ByteA
|
2023-10-10 06:23:12 +03:00
|
|
|
seq Int @default(0) @db.Integer
|
|
|
|
state Bytes? @db.ByteA
|
2023-08-29 13:07:05 +03:00
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6)
|
|
|
|
|
|
|
|
@@id([id, workspaceId])
|
|
|
|
@@map("snapshots")
|
|
|
|
}
|
|
|
|
|
|
|
|
model Update {
|
|
|
|
workspaceId String @map("workspace_id") @db.VarChar
|
2023-10-10 06:23:12 +03:00
|
|
|
id String @map("guid") @db.VarChar
|
|
|
|
seq Int @db.Integer
|
2023-08-29 13:07:05 +03:00
|
|
|
blob Bytes @db.ByteA
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
|
2023-10-24 12:33:24 +03:00
|
|
|
@@id([workspaceId, id, seq])
|
2023-08-29 13:07:05 +03:00
|
|
|
@@map("updates")
|
|
|
|
}
|
2023-06-29 04:45:45 +03:00
|
|
|
|
2023-11-22 06:31:22 +03:00
|
|
|
model SnapshotHistory {
|
|
|
|
workspaceId String @map("workspace_id") @db.VarChar(36)
|
|
|
|
id String @map("guid") @db.VarChar(36)
|
2023-11-22 10:56:59 +03:00
|
|
|
timestamp DateTime @db.Timestamptz(6)
|
2023-11-22 06:31:22 +03:00
|
|
|
blob Bytes @db.ByteA
|
|
|
|
state Bytes? @db.ByteA
|
2023-11-22 10:56:59 +03:00
|
|
|
expiredAt DateTime @map("expired_at") @db.Timestamptz(6)
|
2023-11-22 06:31:22 +03:00
|
|
|
|
2023-11-22 10:56:59 +03:00
|
|
|
@@id([workspaceId, id, timestamp])
|
2023-11-22 06:31:22 +03:00
|
|
|
@@map("snapshot_histories")
|
|
|
|
}
|
|
|
|
|
2023-08-29 13:07:05 +03:00
|
|
|
model NewFeaturesWaitingList {
|
|
|
|
id String @id @default(uuid()) @db.VarChar
|
|
|
|
email String @unique
|
|
|
|
type Int @db.SmallInt
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
2023-06-29 04:45:45 +03:00
|
|
|
|
2023-08-29 13:07:05 +03:00
|
|
|
@@map("new_features_waiting_list")
|
2023-06-29 04:45:45 +03:00
|
|
|
}
|
2023-10-19 05:06:34 +03:00
|
|
|
|
|
|
|
model UserStripeCustomer {
|
|
|
|
userId String @id @map("user_id") @db.VarChar
|
|
|
|
stripeCustomerId String @unique @map("stripe_customer_id") @db.VarChar
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
@@map("user_stripe_customers")
|
|
|
|
}
|
|
|
|
|
|
|
|
model UserSubscription {
|
|
|
|
id Int @id @default(autoincrement()) @db.Integer
|
|
|
|
userId String @unique @map("user_id") @db.VarChar(36)
|
|
|
|
plan String @db.VarChar(20)
|
|
|
|
// yearly/monthly
|
|
|
|
recurring String @db.VarChar(20)
|
|
|
|
// subscription.id
|
|
|
|
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(6)
|
|
|
|
// subscription.current_period_end
|
|
|
|
end DateTime @map("end") @db.Timestamptz(6)
|
|
|
|
// subscription.billing_cycle_anchor
|
|
|
|
nextBillAt DateTime? @map("next_bill_at") @db.Timestamptz(6)
|
|
|
|
// subscription.canceled_at
|
|
|
|
canceledAt DateTime? @map("canceled_at") @db.Timestamptz(6)
|
|
|
|
// subscription.trial_start
|
|
|
|
trialStart DateTime? @map("trial_start") @db.Timestamptz(6)
|
|
|
|
// subscription.trial_end
|
|
|
|
trialEnd DateTime? @map("trial_end") @db.Timestamptz(6)
|
|
|
|
stripeScheduleId String? @map("stripe_schedule_id") @db.VarChar
|
|
|
|
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6)
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
@@map("user_subscriptions")
|
|
|
|
}
|
|
|
|
|
|
|
|
model UserInvoice {
|
|
|
|
id Int @id @default(autoincrement()) @db.Integer
|
|
|
|
userId String @map("user_id") @db.VarChar(36)
|
|
|
|
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)
|
|
|
|
plan String @db.VarChar(20)
|
|
|
|
recurring String @db.VarChar(20)
|
|
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6)
|
|
|
|
// billing reason
|
|
|
|
reason String @db.VarChar
|
|
|
|
lastPaymentError String? @map("last_payment_error") @db.Text
|
2023-10-20 04:42:33 +03:00
|
|
|
// stripe hosted invoice link
|
|
|
|
link String? @db.Text
|
2023-10-19 05:06:34 +03:00
|
|
|
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
|
|
|
@@map("user_invoices")
|
|
|
|
}
|
2023-10-30 09:55:51 +03:00
|
|
|
|
2023-10-27 12:31:52 +03:00
|
|
|
model DataMigration {
|
|
|
|
id String @id @default(uuid()) @db.VarChar(36)
|
|
|
|
name String @db.VarChar
|
|
|
|
startedAt DateTime @default(now()) @map("started_at") @db.Timestamptz(6)
|
|
|
|
finishedAt DateTime? @map("finished_at") @db.Timestamptz(6)
|
|
|
|
|
|
|
|
@@map("_data_migrations")
|
|
|
|
}
|