generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } enum Plan { FREE PREMIUM } enum Privacy { PUBLIC PRIVATE UNLISTED } enum JobStatus { PENDING PROCESSING COMPLETED FAILED PARTIAL } enum JobItemStatus { PENDING ENCODING UPLOADING COMPLETED FAILED } enum QuotaExtensionRequestStatus { PENDING APPROVED REJECTED } enum QuotaExtensionKind { VIDEO_QUOTA API_RATE_LIMIT } model User { id String @id @default(cuid()) email String @unique name String? image String? plan Plan @default(FREE) videosUsed Int @default(0) quotaResetAt DateTime cardLast4 String? subscribedAt DateTime? bonusQuota Int @default(0) apiRateLimitBonus Int @default(0) /** Prepaid pay-as-you-go video credits (1 credit = 1 video). Cap: 1000. */ videoCredits Int @default(0) apiKeyHash String? @unique apiKeyPrefix String? youtubeConnection YouTubeConnection? jobs Job[] quotaExtensionRequests QuotaExtensionRequest[] creditPurchases CreditPurchase[] createdAt DateTime @default(now()) } enum CreditPurchaseStatus { PENDING COMPLETED FAILED } model CreditPurchase { id String @id @default(cuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) credits Int amountCents Int status CreditPurchaseStatus @default(PENDING) stripeSessionId String? @unique stripePaymentIntentId String? createdAt DateTime @default(now()) completedAt DateTime? } enum JobItemBilling { QUOTA CREDIT } model QuotaExtensionRequest { id String @id @default(cuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) kind QuotaExtensionKind @default(VIDEO_QUOTA) status QuotaExtensionRequestStatus @default(PENDING) message String @default("") requestedAt DateTime @default(now()) processedAt DateTime? adminNote String? } model YouTubeConnection { id String @id @default(cuid()) userId String @unique user User @relation(fields: [userId], references: [id], onDelete: Cascade) accessToken String refreshToken String expiresAt DateTime channelId String channelTitle String } model Job { id String @id @default(cuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) status JobStatus @default(PENDING) imagePath String items JobItem[] createdAt DateTime @default(now()) completedAt DateTime? } model JobItem { id String @id @default(cuid()) jobId String job Job @relation(fields: [jobId], references: [id], onDelete: Cascade) audioPath String audioFilename String title String description String @default("") tags String @default("") privacy Privacy @default(PUBLIC) categoryId String @default("10") resolution String @default("1280x720") notifySubscribers Boolean @default(true) madeForKids Boolean @default(false) embeddable Boolean @default(true) creativeCommons Boolean @default(false) includeWatermark Boolean @default(true) playlistId String? billingSource JobItemBilling @default(QUOTA) status JobItemStatus @default(PENDING) outputPath String? youtubeVideoId String? error String? }