Files
XBid/prisma/schema.prisma
T
2026-08-18 12:11:20 +02:00

627 lines
20 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"
}
datasource db {
provider = "postgresql"
}
// ─── Auth / Users ────────────────────────────────────────────────────────────
model User {
id String @id @default(cuid())
name String?
email String @unique
emailVerified DateTime?
image String?
password String?
role UserRole @default(ARTIST)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accounts Account[]
sessions Session[]
jobs Job[] @relation("JobCreator")
comments Comment[]
@@map("users")
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
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")
}
enum UserRole {
ADMIN
PRODUCER
SUPERVISOR
ARTIST
}
// ─── Clients ─────────────────────────────────────────────────────────────────
model Client {
id String @id @default(cuid())
companyName String
contactPerson String?
email String?
phone String?
vatNumber String?
companyRegNumber String?
billingAddress String?
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
jobs Job[]
invoices Invoice[]
@@map("clients")
}
// ─── Jobs / Quotes ────────────────────────────────────────────────────────────
model Job {
id String @id @default(cuid())
projectTitle String
projectCode String @unique
showId String @default("")
jobType JobType @default(STANDARD)
clientId String
createdById String?
issueDate DateTime @default(now())
expiryDate DateTime?
currency String @default("ZAR")
status JobStatus @default(DRAFT)
description String?
internalNotes String?
markupPercent Decimal @default(0) @db.Decimal(10, 4)
taxPercent Decimal @default(0) @db.Decimal(10, 4)
discountPercent Decimal @default(0) @db.Decimal(10, 4)
productionFeePercent Decimal @default(0) @db.Decimal(10, 4)
pullManagementFeePercent Decimal @default(0) @db.Decimal(10, 4)
customHeaderHtml String?
customFooterHtml String?
termsAndConditions String?
startDate DateTime?
estimatedCompletionDate DateTime?
version Int @default(1)
parentJobId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
client Client @relation(fields: [clientId], references: [id])
createdBy User? @relation("JobCreator", fields: [createdById], references: [id])
parentJob Job? @relation("JobVersions", fields: [parentJobId], references: [id], onDelete: SetNull)
versions Job[] @relation("JobVersions")
shots Shot[]
assets Asset[]
supervisions Supervision[]
previses Previs[]
comments Comment[]
history JobHistory[]
paymentSchedule PaymentSchedule?
invoices Invoice[]
@@map("jobs")
}
enum JobStatus {
DRAFT
SENT
APPROVED
REJECTED
ARCHIVED
}
enum JobType {
STANDARD
EPISODIC
}
model JobHistory {
id String @id @default(cuid())
jobId String
field String
oldValue String?
newValue String?
changedAt DateTime @default(now())
changedBy String?
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
@@map("job_history")
}
model Comment {
id String @id @default(cuid())
jobId String
userId String?
body String
createdAt DateTime @default(now())
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
user User? @relation(fields: [userId], references: [id])
@@map("comments")
}
// ─── Rate Cards ───────────────────────────────────────────────────────────────
model RateCard {
id String @id @default(cuid())
name String
department String?
defaultDailyRate Decimal @default(0) @db.Decimal(10, 4)
hoursPerDay Decimal @default(8) @db.Decimal(5, 2)
currency String @default("ZAR")
notes String?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lineItems LineItem[]
@@map("rate_cards")
}
// ─── Shot Templates ───────────────────────────────────────────────────────────
model ShotTemplate {
id String @id @default(cuid())
name String
description String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lineItemTemplates ShotLineItemTemplate[]
@@map("shot_templates")
}
model ShotLineItemTemplate {
id String @id @default(cuid())
templateId String
taskName String
artistRole String?
defaultHours Decimal @default(0) @db.Decimal(10, 4)
rateCardId String?
notes String?
sortOrder Int @default(0)
template ShotTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
@@map("shot_line_item_templates")
}
// ─── Asset Templates ──────────────────────────────────────────────────────────
model AssetTemplate {
id String @id @default(cuid())
name String
description String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lineItemTemplates AssetLineItemTemplate[]
@@map("asset_templates")
}
model AssetLineItemTemplate {
id String @id @default(cuid())
templateId String
taskName String
artistRole String?
defaultHours Decimal @default(0) @db.Decimal(10, 4)
rateCardId String?
notes String?
sortOrder Int @default(0)
template AssetTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
@@map("asset_line_item_templates")
}
// ─── Shots ────────────────────────────────────────────────────────────────────
model Shot {
id String @id @default(cuid())
jobId String
shotCode String
shotNumber Int @default(0)
scene String @default("")
episode String?
shotGroup String?
description String?
durationSeconds Int?
complexityMultiplier Decimal @default(1) @db.Decimal(5, 4)
notes String?
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
lineItems LineItem[]
@@map("shots")
}
// ─── Assets ───────────────────────────────────────────────────────────────────
model Asset {
id String @id @default(cuid())
jobId String
assetName String
assetType String?
description String?
complexityMultiplier Decimal @default(1) @db.Decimal(5, 4)
notes String?
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
lineItems LineItem[]
@@map("assets")
}
// ─── Supervision ─────────────────────────────────────────────────────────────
model Supervision {
id String @id @default(cuid())
jobId String
supervisionTitle String
shootName String?
location String?
shootDates String?
numShootDays Int @default(0)
travelDays Int @default(0)
prepDays Int @default(0)
wrapDays Int @default(0)
description String?
complexityMultiplier Decimal @default(1) @db.Decimal(5, 4)
notes String?
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
lineItems LineItem[]
@@map("supervisions")
}
model SupervisionTemplate {
id String @id @default(cuid())
name String
description String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lineItemTemplates SupervisionLineItemTemplate[]
@@map("supervision_templates")
}
model SupervisionLineItemTemplate {
id String @id @default(cuid())
templateId String
taskName String
artistRole String?
defaultHours Decimal @default(0) @db.Decimal(10, 4)
rateCardId String?
notes String?
sortOrder Int @default(0)
template SupervisionTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
@@map("supervision_line_item_templates")
}
// ─── Previs ───────────────────────────────────────────────────────────────────
model Previs {
id String @id @default(cuid())
jobId String
sequenceName String
previsCode String?
sequenceType String @default("Previs")
description String?
duration String?
frameRange String?
revisionCount Int @default(0)
deliveryStage String @default("Blocking")
complexityMultiplier Decimal @default(1) @db.Decimal(5, 4)
notes String?
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
lineItems LineItem[]
@@map("previses")
}
model PrevisTemplate {
id String @id @default(cuid())
name String
description String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lineItemTemplates PrevisLineItemTemplate[]
@@map("previs_templates")
}
model PrevisLineItemTemplate {
id String @id @default(cuid())
templateId String
taskName String
artistRole String?
defaultHours Decimal @default(0) @db.Decimal(10, 4)
rateCardId String?
notes String?
sortOrder Int @default(0)
template PrevisTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
@@map("previs_line_item_templates")
}
// ─── Line Items ───────────────────────────────────────────────────────────────
model LineItem {
id String @id @default(cuid())
shotId String?
assetId String?
supervisionId String?
previsId String?
rateCardId String?
taskName String
artistRole String?
// Inputs
quantityHours Decimal @default(0) @db.Decimal(10, 4)
dailyRate Decimal @default(0) @db.Decimal(10, 4)
hoursPerDay Decimal @default(8) @db.Decimal(5, 2)
numArtists Decimal @default(1) @db.Decimal(5, 2)
numDays Decimal @default(0) @db.Decimal(10, 4)
// Overrides
manualHourlyRate Decimal? @db.Decimal(10, 4)
manualSubtotal Decimal? @db.Decimal(14, 4)
// Adjustments
markupPercent Decimal @default(0) @db.Decimal(10, 4)
discountPercent Decimal @default(0) @db.Decimal(10, 4)
taxPercent Decimal @default(0) @db.Decimal(10, 4)
// Stored computed totals (recalculated server-side before PDF)
hourlyRate Decimal @default(0) @db.Decimal(10, 4)
subtotal Decimal @default(0) @db.Decimal(14, 4)
markupAmount Decimal @default(0) @db.Decimal(14, 4)
discountAmount Decimal @default(0) @db.Decimal(14, 4)
taxAmount Decimal @default(0) @db.Decimal(14, 4)
total Decimal @default(0) @db.Decimal(14, 4)
notes String?
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
shot Shot? @relation(fields: [shotId], references: [id], onDelete: Cascade)
asset Asset? @relation(fields: [assetId], references: [id], onDelete: Cascade)
supervision Supervision? @relation(fields: [supervisionId], references: [id], onDelete: Cascade)
previs Previs? @relation(fields: [previsId], references: [id], onDelete: Cascade)
rateCard RateCard? @relation(fields: [rateCardId], references: [id])
@@map("line_items")
}
// ─── Task Templates ───────────────────────────────────────────────────────────
model TaskTemplate {
id String @id @default(cuid())
name String
taskName String
artistRole String?
rateCardId String?
quantityHours Decimal @default(0) @db.Decimal(10, 4)
dailyRate Decimal @default(0) @db.Decimal(10, 4)
hoursPerDay Decimal @default(8) @db.Decimal(5, 2)
numArtists Decimal @default(1) @db.Decimal(5, 2)
numDays Decimal @default(0) @db.Decimal(10, 4)
manualHourlyRate Decimal? @db.Decimal(10, 4)
manualSubtotal Decimal? @db.Decimal(14, 4)
markupPercent Decimal @default(0) @db.Decimal(10, 4)
discountPercent Decimal @default(0) @db.Decimal(10, 4)
taxPercent Decimal @default(0) @db.Decimal(10, 4)
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("task_templates")
}
// ─── Studio Settings ──────────────────────────────────────────────────────────
model StudioSettings {
id String @id @default("default")
studioName String @default("My VFX Studio")
studioEmail String?
studioPhone String?
studioAddress String?
logoUrl String?
vatNumber String?
companyRegNumber String?
invoiceHeader String?
invoiceFooter String?
defaultTermsAndConditions String?
defaultCurrency String @default("ZAR")
defaultMarkupPercent Decimal @default(0) @db.Decimal(10, 4)
defaultDiscountPercent Decimal @default(0) @db.Decimal(10, 4)
defaultTaxPercent Decimal @default(0) @db.Decimal(10, 4)
updatedAt DateTime @updatedAt
@@map("studio_settings")
}
// ─── Payment Schedule ─────────────────────────────────────────────────────────
enum ScheduleTemplate {
STANDARD_FILM
SMALL_COMMERCIAL
EPISODIC
CUSTOM
}
enum MilestoneStatus {
DRAFT
PENDING
INVOICED
PARTIALLY_PAID
PAID
OVERDUE
CANCELLED
}
model PaymentSchedule {
id String @id @default(cuid())
jobId String @unique
template ScheduleTemplate @default(CUSTOM)
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
milestones PaymentMilestone[]
@@map("payment_schedules")
}
model PaymentMilestone {
id String @id @default(cuid())
scheduleId String
title String
description String?
dueDate DateTime?
percentOfTotal Decimal @default(0) @db.Decimal(10, 4)
fixedAmount Decimal? @db.Decimal(14, 4)
status MilestoneStatus @default(PENDING)
paymentReceivedDate DateTime?
notes String?
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
schedule PaymentSchedule @relation(fields: [scheduleId], references: [id], onDelete: Cascade)
invoice Invoice?
@@map("payment_milestones")
}
// ─── Invoices ─────────────────────────────────────────────────────────────────
enum InvoiceStatus {
DRAFT
SENT
VIEWED
PARTIALLY_PAID
PAID
OVERDUE
CANCELLED
}
enum PaymentMethod {
EFT
CASH
CREDIT_CARD
BANK_TRANSFER
CRYPTO
OTHER
}
model Invoice {
id String @id @default(cuid())
invoiceNumber String @unique
clientId String
jobId String
milestoneId String? @unique
status InvoiceStatus @default(DRAFT)
issueDate DateTime @default(now())
dueDate DateTime?
paymentTerms String?
currency String @default("ZAR")
subtotal Decimal @default(0) @db.Decimal(14, 4)
taxPercent Decimal @default(0) @db.Decimal(10, 4)
taxAmount Decimal @default(0) @db.Decimal(14, 4)
totalAmount Decimal @default(0) @db.Decimal(14, 4)
amountPaid Decimal @default(0) @db.Decimal(14, 4)
amountDue Decimal @default(0) @db.Decimal(14, 4)
notes String?
internalNotes String?
bankingDetails String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
client Client @relation(fields: [clientId], references: [id])
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
milestone PaymentMilestone? @relation(fields: [milestoneId], references: [id])
payments InvoicePayment[]
@@map("invoices")
}
model InvoicePayment {
id String @id @default(cuid())
invoiceId String
amount Decimal @db.Decimal(14, 4)
paymentDate DateTime
paymentMethod PaymentMethod @default(EFT)
reference String?
notes String?
createdAt DateTime @default(now())
invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
@@map("invoice_payments")
}