| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- // 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"
- }
- datasource db {
- provider = "postgresql"
- url = env("DATABASE_URL")
- }
- model User {
- id String @id @default(cuid())
- email String @unique
- name String
- password String
- avatarUrl String?
- globalRole GlobalRole @default(MEMBER)
- active Boolean @default(true)
- storageQuota Int @default(524288000) // 500 MB in bytes
- storageUsed Int @default(0) // bytes consumed
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- memberships ProjectMember[]
- comments Comment[]
- projects Project[] // projects where this user is the owner
- resolvedComments Comment[] @relation("ResolvedBy")
- requestedComments Comment[] @relation("RequestedBy")
- assets Asset[]
- }
- model Project {
- id String @id @default(cuid())
- name String
- description String?
- ownerId String
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- assets Asset[]
- members ProjectMember[]
- invitations Invitation[]
- owner User @relation(fields: [ownerId], references: [id])
- }
- model SiteSetting {
- id String @id @default(cuid())
- name String @unique
- value String
- }
- model ProjectMember {
- id String @id @default(cuid())
- userId String
- projectId String
- role Role @default(REVIEWER)
- joinedAt DateTime @default(now())
- invitedBy String? // userId who sent the invite
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
- @@unique([userId, projectId])
- @@index([projectId])
- @@index([userId])
- }
- model Asset {
- id String @id @default(cuid())
- projectId String
- uploaderId String? // null for legacy assets before this feature
- title String
- filename String
- filePath String
- thumbnail String?
- hlsPath String?
- duration Float?
- fps Float @default(30)
- codec String?
- mimeType String
- fileSize Int @default(0) // raw video file size in bytes
- status AssetStatus @default(PENDING_REVIEW)
- transcodeStatus TranscodeStatus @default(PENDING)
- transcodeProgress Int @default(0)
- transcodeError String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
- uploader User? @relation(fields: [uploaderId], references: [id], onDelete: SetNull)
- comments Comment[]
- }
- model Comment {
- id String @id @default(cuid())
- assetId String
- userId String
- content String
- timestamp Float?
- annotations Json?
- resolved Boolean @default(false)
- resolveStatus ResolveStatus @default(UNRESOLVED)
- resolvedById String?
- resolvedByAt DateTime?
- requestedById String?
- requestedByAt DateTime?
- parentId String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade)
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- parent Comment? @relation("Replies", fields: [parentId], references: [id], onDelete: Cascade)
- replies Comment[] @relation("Replies")
- resolvedBy User? @relation("ResolvedBy", fields: [resolvedById], references: [id])
- requestedBy User? @relation("RequestedBy", fields: [requestedById], references: [id])
- }
- enum Role {
- ADMIN
- EDITOR
- REVIEWER
- VIEWER
- }
- enum GlobalRole {
- ADMIN // system-wide admin: manage users, all projects, quotas
- MEMBER // registered user: create own projects, invite members
- PROJECT_USER // invited user: no project creation, workspace visibility only via invite
- }
- enum InvitationStatus {
- PENDING
- ACCEPTED
- EXPIRED
- REVOKED
- }
- model Invitation {
- id String @id @default(cuid())
- email String // invitee email
- projectId String? // null = workspace invite (creates MEMBER); set = project invite (creates PROJECT_USER)
- type InvitationType @default(PROJECT)
- role Role @default(REVIEWER)
- token String @unique
- status InvitationStatus @default(PENDING)
- invitedBy String? // userId who sent the invite
- expiresAt DateTime
- createdAt DateTime @default(now())
- project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
- @@index([projectId])
- @@index([email])
- @@index([token])
- }
- enum InvitationType {
- WORKSPACE // admin invites MEMBER — no project attached, user registers as MEMBER
- PROJECT // admin/project member invites PROJECT_USER — attached to a project
- }
- enum AssetStatus {
- PENDING_REVIEW
- CHANGES_REQUESTED
- APPROVED
- REJECTED
- }
- enum ResolveStatus {
- UNRESOLVED // no request made
- PENDING_APPROVAL // someone requested resolve, awaiting approval
- RESOLVED // approved and closed
- }
- enum TranscodeStatus {
- PENDING
- UPLOADING
- PROCESSING
- COMPLETED
- FAILED
- UNSUPPORTED_CODEC
- }
|