Initial commit
This commit is contained in:
@@ -0,0 +1,472 @@
|
||||
// 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"
|
||||
binaryTargets = ["native", "linux-musl-arm64-openssl-3.0.x"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// ENUMS
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
enum Role {
|
||||
ADMIN
|
||||
PRODUCER
|
||||
SUPERVISOR
|
||||
ARTIST
|
||||
CLIENT
|
||||
}
|
||||
|
||||
enum ProjectStatus {
|
||||
ACTIVE
|
||||
ON_HOLD
|
||||
COMPLETED
|
||||
ARCHIVED
|
||||
}
|
||||
|
||||
enum ShotStatus {
|
||||
WAITING
|
||||
IN_PROGRESS
|
||||
IN_REVIEW
|
||||
REVISIONS
|
||||
COMPLETE
|
||||
}
|
||||
|
||||
enum ShotPriority {
|
||||
LOW
|
||||
NORMAL
|
||||
HIGH
|
||||
URGENT
|
||||
}
|
||||
|
||||
enum ApprovalStatus {
|
||||
PENDING_REVIEW
|
||||
APPROVED
|
||||
REJECTED
|
||||
NEEDS_CHANGES
|
||||
}
|
||||
|
||||
enum ReviewStatus {
|
||||
PENDING
|
||||
INTERNAL_APPROVED
|
||||
CLIENT_APPROVED
|
||||
NEEDS_CHANGES
|
||||
FINAL_APPROVED
|
||||
}
|
||||
|
||||
enum NotificationType {
|
||||
VERSION_UPLOADED
|
||||
FEEDBACK_ADDED
|
||||
SHOT_APPROVED
|
||||
SHOT_REJECTED
|
||||
COMMENT_REPLY
|
||||
MENTION
|
||||
REVISION_REQUESTED
|
||||
TASK_ASSIGNED
|
||||
TASK_OVERDUE
|
||||
TASK_APPROVED
|
||||
TASK_CHANGES_REQUESTED
|
||||
TASK_READY_FOR_REVIEW
|
||||
}
|
||||
|
||||
enum TaskStatus {
|
||||
TODO
|
||||
IN_PROGRESS
|
||||
INTERNAL_REVIEW
|
||||
CLIENT_REVIEW
|
||||
CHANGES
|
||||
DONE
|
||||
}
|
||||
|
||||
enum TaskType {
|
||||
TRACK
|
||||
ROTO
|
||||
KEY
|
||||
COMP
|
||||
FX
|
||||
LIGHTING
|
||||
RENDER
|
||||
ANIMATION
|
||||
MODEL
|
||||
TEXTURE
|
||||
RIG
|
||||
LOOKDEV
|
||||
GENERAL
|
||||
}
|
||||
|
||||
enum ProjectType {
|
||||
STANDARD
|
||||
EPISODIC
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// AUTH MODELS (NextAuth v5 compatible)
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
passwordHash String?
|
||||
role Role @default(ARTIST)
|
||||
isActive Boolean @default(true)
|
||||
mustChangePassword Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// NextAuth relations
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
|
||||
// App relations
|
||||
producedProjects Project[] @relation("ProducerProjects")
|
||||
supervisedProjects Project[] @relation("SupervisorProjects")
|
||||
assignedShots Shot[] @relation("ArtistShots")
|
||||
uploadedVersions Version[]
|
||||
comments Comment[]
|
||||
commentReplies CommentReply[]
|
||||
annotations Annotation[]
|
||||
approvals Approval[]
|
||||
notifications Notification[]
|
||||
clientAccess ClientAccess[]
|
||||
assignedTasks Task[] @relation("TaskArtist")
|
||||
createdTasks Task[] @relation("TaskCreator")
|
||||
sharedVersions Version[] @relation("VersionSharedBy")
|
||||
ledAssets Asset[] @relation("AssetLead")
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
model Account {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type String
|
||||
provider String
|
||||
providerAccountId String
|
||||
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
|
||||
userId String
|
||||
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("verification_tokens")
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// CORE DOMAIN MODELS
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
model Client {
|
||||
id String @id @default(cuid())
|
||||
company String
|
||||
contactPerson String
|
||||
email String @unique
|
||||
phone String?
|
||||
notes String? @db.Text
|
||||
logoUrl String?
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
projects Project[]
|
||||
clientAccess ClientAccess[]
|
||||
|
||||
@@map("clients")
|
||||
}
|
||||
|
||||
/// Links a USER with CLIENT role to the client record they represent
|
||||
model ClientAccess {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
clientId String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
client Client @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, clientId])
|
||||
@@map("client_access")
|
||||
}
|
||||
|
||||
model Project {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
code String @unique
|
||||
showId String @default("")
|
||||
projectType ProjectType @default(STANDARD)
|
||||
description String? @db.Text
|
||||
status ProjectStatus @default(ACTIVE)
|
||||
dueDate DateTime?
|
||||
startDate DateTime?
|
||||
clientId String?
|
||||
producerId String?
|
||||
supervisorId String?
|
||||
slackWebhook String?
|
||||
slackChannel String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
client Client? @relation(fields: [clientId], references: [id])
|
||||
producer User? @relation("ProducerProjects", fields: [producerId], references: [id])
|
||||
supervisor User? @relation("SupervisorProjects", fields: [supervisorId], references: [id])
|
||||
shots Shot[]
|
||||
assets Asset[]
|
||||
tasks Task[]
|
||||
reviewSessions ReviewSession[]
|
||||
|
||||
@@map("projects")
|
||||
}
|
||||
|
||||
model Shot {
|
||||
id String @id @default(cuid())
|
||||
shotCode String
|
||||
scene String @default("")
|
||||
episode String?
|
||||
shotNumber Int @default(0)
|
||||
sequence String?
|
||||
description String? @db.Text
|
||||
status ShotStatus @default(WAITING)
|
||||
priority ShotPriority @default(NORMAL)
|
||||
artistId String?
|
||||
projectId String
|
||||
frameStart Int?
|
||||
frameEnd Int?
|
||||
fps Float @default(24)
|
||||
dueDate DateTime?
|
||||
thumbnailUrl String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
artist User? @relation("ArtistShots", fields: [artistId], references: [id])
|
||||
versions Version[]
|
||||
tasks Task[]
|
||||
|
||||
@@unique([projectId, shotCode])
|
||||
@@map("shots")
|
||||
}
|
||||
|
||||
model Version {
|
||||
id String @id @default(cuid())
|
||||
versionNumber Int
|
||||
shotId String?
|
||||
taskId String?
|
||||
artistId String?
|
||||
fileUrl String
|
||||
fileName String
|
||||
fileSize BigInt?
|
||||
mimeType String?
|
||||
thumbnailUrl String?
|
||||
posterUrl String?
|
||||
proxyUrl String?
|
||||
fps Float @default(24)
|
||||
duration Float?
|
||||
frameCount Int?
|
||||
width Int?
|
||||
height Int?
|
||||
notes String? @db.Text
|
||||
approvalStatus ApprovalStatus @default(PENDING_REVIEW)
|
||||
reviewStatus ReviewStatus @default(PENDING)
|
||||
isLatest Boolean @default(true)
|
||||
isClientVisible Boolean @default(false)
|
||||
sharedAt DateTime?
|
||||
sharedById String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
shot Shot? @relation(fields: [shotId], references: [id], onDelete: Cascade)
|
||||
task Task? @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
||||
artist User? @relation(fields: [artistId], references: [id])
|
||||
sharedBy User? @relation("VersionSharedBy", fields: [sharedById], references: [id])
|
||||
comments Comment[]
|
||||
annotations Annotation[]
|
||||
approvals Approval[]
|
||||
|
||||
@@map("versions")
|
||||
}
|
||||
|
||||
model Comment {
|
||||
id String @id @default(cuid())
|
||||
versionId String
|
||||
authorId String?
|
||||
frameNumber Int
|
||||
timestamp Float
|
||||
text String @db.Text
|
||||
isResolved Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
version Version @relation(fields: [versionId], references: [id], onDelete: Cascade)
|
||||
author User? @relation(fields: [authorId], references: [id], onDelete: SetNull)
|
||||
replies CommentReply[]
|
||||
annotations Annotation[]
|
||||
|
||||
@@map("comments")
|
||||
}
|
||||
|
||||
model CommentReply {
|
||||
id String @id @default(cuid())
|
||||
commentId String
|
||||
authorId String?
|
||||
text String @db.Text
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
comment Comment @relation(fields: [commentId], references: [id], onDelete: Cascade)
|
||||
author User? @relation(fields: [authorId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@map("comment_replies")
|
||||
}
|
||||
|
||||
/// Stores canvas drawing data as JSON (normalized 0-1 coordinates)
|
||||
model Annotation {
|
||||
id String @id @default(cuid())
|
||||
versionId String
|
||||
commentId String?
|
||||
authorId String?
|
||||
frameNumber Int
|
||||
drawingData Json // Array of AnnotationShape objects
|
||||
color String @default("#ef4444")
|
||||
isVisible Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
version Version @relation(fields: [versionId], references: [id], onDelete: Cascade)
|
||||
comment Comment? @relation(fields: [commentId], references: [id], onDelete: SetNull)
|
||||
author User? @relation(fields: [authorId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@map("annotations")
|
||||
}
|
||||
|
||||
model Approval {
|
||||
id String @id @default(cuid())
|
||||
versionId String
|
||||
userId String?
|
||||
status ApprovalStatus
|
||||
notes String? @db.Text
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
version Version @relation(fields: [versionId], references: [id], onDelete: Cascade)
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@map("approvals")
|
||||
}
|
||||
|
||||
model Notification {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type NotificationType
|
||||
title String
|
||||
message String @db.Text
|
||||
data Json? // Extra context (versionId, shotCode, etc.)
|
||||
isRead Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("notifications")
|
||||
}
|
||||
|
||||
model Asset {
|
||||
id String @id @default(cuid())
|
||||
projectId String
|
||||
assetCode String
|
||||
name String
|
||||
description String? @db.Text
|
||||
status ShotStatus @default(WAITING)
|
||||
priority ShotPriority @default(NORMAL)
|
||||
leadId String?
|
||||
dueDate DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
lead User? @relation("AssetLead", fields: [leadId], references: [id])
|
||||
tasks Task[]
|
||||
|
||||
@@unique([projectId, assetCode])
|
||||
@@map("assets")
|
||||
}
|
||||
|
||||
model Task {
|
||||
id String @id @default(cuid())
|
||||
title String
|
||||
description String? @db.Text
|
||||
type TaskType @default(GENERAL)
|
||||
status TaskStatus @default(TODO)
|
||||
priority ShotPriority @default(NORMAL)
|
||||
dueDate DateTime?
|
||||
estimatedHours Float?
|
||||
sortOrder Int @default(0)
|
||||
shotId String?
|
||||
assetId String?
|
||||
assignedArtistId String?
|
||||
createdById String?
|
||||
projectId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
scheduledStartDate DateTime?
|
||||
scheduledEndDate DateTime?
|
||||
scheduleNotes String? @db.Text
|
||||
|
||||
shot Shot? @relation(fields: [shotId], references: [id], onDelete: Cascade)
|
||||
asset Asset? @relation(fields: [assetId], references: [id], onDelete: Cascade)
|
||||
assignedArtist User? @relation("TaskArtist", fields: [assignedArtistId], references: [id])
|
||||
createdBy User? @relation("TaskCreator", fields: [createdById], references: [id], onDelete: SetNull)
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
versions Version[]
|
||||
|
||||
@@index([scheduledStartDate])
|
||||
@@index([scheduledEndDate])
|
||||
@@map("tasks")
|
||||
}
|
||||
|
||||
/// Secure tokenized review link for clients
|
||||
model ReviewSession {
|
||||
id String @id @default(cuid())
|
||||
projectId String
|
||||
token String @unique @default(cuid())
|
||||
label String?
|
||||
email String?
|
||||
expiresAt DateTime
|
||||
isActive Boolean @default(true)
|
||||
accessCount Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("review_sessions")
|
||||
}
|
||||
Reference in New Issue
Block a user