mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 05:26:24 +09:00
## Description 1. What is this PR about (link the issue and add a short description) ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 5de6) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file
361 lines
10 KiB
Plaintext
361 lines
10 KiB
Plaintext
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
previewFeatures = ["views"]
|
|
// see commands.ts
|
|
// <output-placeholder-for-migrations>
|
|
output = "../src/__generated__"
|
|
// </output-placeholder-for-migrations>
|
|
|
|
binaryTargets = env("PRISMA_BINARY_TARGET")
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgres"
|
|
url = env("DATABASE_URL")
|
|
directUrl = env("DIRECT_URL")
|
|
}
|
|
|
|
model Team {
|
|
id String @id @default(uuid())
|
|
users User[]
|
|
}
|
|
|
|
enum UploadStatus {
|
|
UPLOADING
|
|
UPLOADED
|
|
}
|
|
|
|
model File {
|
|
name String @id
|
|
format String
|
|
size Int
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @default(now()) @updatedAt
|
|
meta String @default("{}")
|
|
status UploadStatus @default(UPLOADING)
|
|
isDeleted Boolean @default(false)
|
|
uploaderProject Project? @relation(fields: [uploaderProjectId], references: [id])
|
|
uploaderProjectId String?
|
|
assets Asset[]
|
|
}
|
|
|
|
model Asset {
|
|
id String @default(uuid()) // not unique!
|
|
projectId String
|
|
file File @relation(fields: [name], references: [name])
|
|
name String
|
|
Project Project[]
|
|
DashboardProject DashboardProject[]
|
|
|
|
@@id([id, projectId])
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(uuid())
|
|
email String? @unique
|
|
provider String?
|
|
image String?
|
|
username String?
|
|
createdAt DateTime @default(now())
|
|
team Team? @relation(fields: [teamId], references: [id])
|
|
teamId String?
|
|
projects Project[]
|
|
clientReferences ClientReferences[]
|
|
checkout TransactionLog[]
|
|
products UserProduct[]
|
|
}
|
|
|
|
// User client references in external services like stripe etc
|
|
model ClientReferences {
|
|
reference String @default(dbgenerated())
|
|
service String
|
|
createdAt DateTime @default(now())
|
|
user User @relation(fields: [userId], references: [id])
|
|
userId String
|
|
|
|
@@id([userId, service])
|
|
@@unique([reference, service])
|
|
}
|
|
|
|
model Product {
|
|
id String @id
|
|
name String
|
|
description String?
|
|
features String[]
|
|
images String[]
|
|
meta Json
|
|
|
|
createdAt DateTime @default(now())
|
|
checkout TransactionLog[]
|
|
userProducts UserProduct[]
|
|
}
|
|
|
|
model TransactionLog {
|
|
// Stripe event id (debug and idempotency purposes)
|
|
eventId String @id
|
|
userId String?
|
|
user User? @relation(fields: [userId], references: [id])
|
|
|
|
productId String?
|
|
product Product? @relation(fields: [productId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
eventData Json? @default(dbgenerated())
|
|
|
|
eventType String? @default(dbgenerated())
|
|
eventCreated Int? @default(dbgenerated())
|
|
|
|
// paid
|
|
status String? @default(dbgenerated())
|
|
|
|
customerId String? @default(dbgenerated())
|
|
customerEmail String? @default(dbgenerated())
|
|
|
|
subscriptionId String? @default(dbgenerated())
|
|
|
|
// Used for Refund
|
|
paymentIntent String? @default(dbgenerated())
|
|
|
|
@@unique([eventId, productId])
|
|
}
|
|
|
|
view UserProduct {
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id])
|
|
productId String
|
|
product Product @relation(fields: [productId], references: [id])
|
|
// subscriptionId and customerId not null for subscriptions
|
|
subscriptionId String?
|
|
customerId String?
|
|
// Easier to debug
|
|
customerEmail String?
|
|
|
|
@@unique([userId, productId])
|
|
}
|
|
|
|
model Project {
|
|
id String @id @default(uuid())
|
|
createdAt DateTime @default(now())
|
|
title String
|
|
domain String @unique
|
|
user User? @relation(fields: [userId], references: [id])
|
|
userId String?
|
|
build Build[]
|
|
isDeleted Boolean @default(false)
|
|
files File[]
|
|
projectDomain ProjectDomain[]
|
|
latestBuild LatestBuildPerProject?
|
|
authorizationToken AuthorizationToken[]
|
|
previewImageAsset Asset? @relation(fields: [previewImageAssetId, id], references: [id, projectId])
|
|
previewImageAssetId String?
|
|
marketplaceApprovalStatus MarketplaceApprovalStatus @default(UNLISTED)
|
|
latestStaticBuild LatestStaticBuildPerProject?
|
|
|
|
@@unique([id, isDeleted])
|
|
@@unique([domain, isDeleted])
|
|
@@unique([id, domain])
|
|
// ApprovedMarketplaceProduct view performance index
|
|
@@index([isDeleted, marketplaceApprovalStatus])
|
|
}
|
|
|
|
enum PublishStatus {
|
|
PENDING
|
|
PUBLISHED
|
|
FAILED
|
|
}
|
|
|
|
enum MarketplaceApprovalStatus {
|
|
UNLISTED
|
|
PENDING
|
|
APPROVED
|
|
REJECTED
|
|
}
|
|
|
|
model Build {
|
|
id String @unique @default(uuid())
|
|
version Int @default(0)
|
|
lastTransactionId String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz(3)
|
|
|
|
pages String
|
|
|
|
project Project @relation(fields: [projectId], references: [id])
|
|
projectId String
|
|
|
|
breakpoints String @default("[]")
|
|
styles String @default("[]")
|
|
styleSources String @default("[]")
|
|
styleSourceSelections String @default("[]")
|
|
props String @default("[]")
|
|
dataSources String @default("[]")
|
|
resources String @default("[]")
|
|
instances String @default("[]")
|
|
marketplaceProduct String @default("{}")
|
|
|
|
deployment String?
|
|
publishStatus PublishStatus @default(PENDING)
|
|
|
|
latestBuildPerProject LatestBuildPerProject?
|
|
latestStaticBuildPerProject LatestStaticBuildPerProject?
|
|
|
|
@@id([id, projectId])
|
|
// ApprovedMarketplaceProduct view performance index
|
|
@@index([projectId, createdAt(sort: Desc)])
|
|
}
|
|
|
|
enum AuthorizationRelation {
|
|
viewers
|
|
editors
|
|
builders
|
|
administrators
|
|
}
|
|
|
|
model AuthorizationToken {
|
|
token String @default(uuid())
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id])
|
|
name String @default("")
|
|
relation AuthorizationRelation @default(viewers)
|
|
createdAt DateTime @default(now())
|
|
|
|
canClone Boolean @default(true)
|
|
canCopy Boolean @default(true)
|
|
|
|
@@id([token, projectId])
|
|
@@unique([token])
|
|
}
|
|
|
|
enum DomainStatus {
|
|
INITIALIZING
|
|
ACTIVE
|
|
ERROR
|
|
PENDING
|
|
}
|
|
|
|
// Domains + last known status and last known txtRecord
|
|
// In the future we can update this table using queue, n8n or temporal workflows.
|
|
// As of now updates are done during UI interactions
|
|
model Domain {
|
|
id String @id @default(uuid())
|
|
domain String @unique
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @default(now()) @updatedAt
|
|
|
|
ProjectDomain ProjectDomain[]
|
|
// Last known txtRecord of the domain (to check domain ownership)
|
|
txtRecord String?
|
|
// create, init, pending, active, error
|
|
status DomainStatus @default(INITIALIZING)
|
|
// In case of status="error", this will contain the error message
|
|
error String?
|
|
|
|
projectWithDomain ProjectWithDomain[]
|
|
}
|
|
|
|
model ProjectDomain {
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id])
|
|
domainId String
|
|
domain Domain @relation(fields: [domainId], references: [id])
|
|
createdAt DateTime @default(now())
|
|
// Generated txt record to check domain ownership
|
|
txtRecord String @unique @default(uuid())
|
|
|
|
// CNAME record to point to the domain
|
|
cname String
|
|
|
|
@@id([projectId, domainId])
|
|
@@index([domainId])
|
|
}
|
|
|
|
view ProjectWithDomain {
|
|
projectId String
|
|
|
|
domainId String
|
|
domain Domain @relation(fields: [domainId], references: [id])
|
|
txtRecord String
|
|
|
|
createdAt DateTime
|
|
|
|
// CNAME record to point to the domain
|
|
cname String
|
|
|
|
verified Boolean
|
|
// To count statistics per user
|
|
userId String?
|
|
|
|
// We can deploy on per domain basis, here for each project domain we have latest build
|
|
latestBuid LatestBuildPerProjectDomain?
|
|
|
|
@@id([projectId, domainId])
|
|
}
|
|
|
|
view LatestBuildPerProjectDomain {
|
|
domainId String
|
|
buildId String
|
|
projectId String
|
|
projectWithDomain ProjectWithDomain @relation(fields: [projectId, domainId], references: [projectId, domainId])
|
|
|
|
isLatestBuild Boolean
|
|
publishStatus PublishStatus
|
|
updatedAt DateTime
|
|
|
|
@@id([projectId, domainId])
|
|
}
|
|
|
|
view LatestBuildPerProject {
|
|
buildId String
|
|
build Build @relation(fields: [buildId, projectId], references: [id, projectId])
|
|
|
|
projectId String
|
|
domain String
|
|
project Project @relation(fields: [projectId, domain], references: [id, domain])
|
|
|
|
isLatestBuild Boolean
|
|
publishStatus PublishStatus
|
|
updatedAt DateTime
|
|
|
|
@@id([projectId, domain])
|
|
@@unique([buildId, projectId])
|
|
}
|
|
|
|
view LatestStaticBuildPerProject {
|
|
buildId String
|
|
build Build @relation(fields: [buildId, projectId], references: [id, projectId])
|
|
|
|
projectId String
|
|
project Project @relation(fields: [projectId], references: [id])
|
|
|
|
publishStatus PublishStatus
|
|
updatedAt DateTime
|
|
|
|
@@id([projectId])
|
|
@@unique([buildId, projectId])
|
|
}
|
|
|
|
// Dashboard
|
|
view DashboardProject {
|
|
id String @id @default(uuid())
|
|
createdAt DateTime @default(now())
|
|
title String
|
|
domain String
|
|
userId String?
|
|
previewImageAsset Asset? @relation(fields: [previewImageAssetId, id], references: [id, projectId])
|
|
previewImageAssetId String?
|
|
isDeleted Boolean @default(false)
|
|
isPublished Boolean
|
|
marketplaceApprovalStatus MarketplaceApprovalStatus @default(UNLISTED)
|
|
}
|
|
|
|
view ApprovedMarketplaceProduct {
|
|
projectId String @id
|
|
marketplaceProduct String
|
|
authorizationToken String?
|
|
}
|