generated from fahricansecer/boilerplate-be
This commit is contained in:
@@ -22,10 +22,18 @@ model User {
|
||||
lastName String?
|
||||
isActive Boolean @default(true)
|
||||
|
||||
// Relations
|
||||
// Core Relations
|
||||
roles UserRole[]
|
||||
refreshTokens RefreshToken[]
|
||||
|
||||
// Video SaaS Relations
|
||||
projects Project[]
|
||||
subscriptions Subscription[]
|
||||
creditTransactions CreditTransaction[]
|
||||
templateUsages TemplateUsage[]
|
||||
notifications Notification[]
|
||||
preferences UserPreference?
|
||||
|
||||
// Multi-tenancy (optional)
|
||||
tenantId String?
|
||||
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
||||
@@ -160,3 +168,472 @@ model Translation {
|
||||
@@index([locale])
|
||||
@@index([namespace])
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Video SaaS — Enums
|
||||
// ============================================
|
||||
|
||||
enum ProjectStatus {
|
||||
DRAFT
|
||||
GENERATING_SCRIPT
|
||||
PENDING
|
||||
GENERATING_MEDIA
|
||||
RENDERING
|
||||
COMPLETED
|
||||
FAILED
|
||||
}
|
||||
|
||||
enum AspectRatio {
|
||||
PORTRAIT_9_16
|
||||
SQUARE_1_1
|
||||
LANDSCAPE_16_9
|
||||
}
|
||||
|
||||
enum VideoStyle {
|
||||
CINEMATIC
|
||||
DOCUMENTARY
|
||||
EDUCATIONAL
|
||||
STORYTELLING
|
||||
NEWS
|
||||
PROMOTIONAL
|
||||
ARTISTIC
|
||||
MINIMALIST
|
||||
}
|
||||
|
||||
enum MediaType {
|
||||
VIDEO_CLIP
|
||||
AUDIO_NARRATION
|
||||
AUDIO_MUSIC
|
||||
SUBTITLE
|
||||
THUMBNAIL
|
||||
FINAL_VIDEO
|
||||
}
|
||||
|
||||
enum TransitionType {
|
||||
CUT
|
||||
FADE
|
||||
DISSOLVE
|
||||
SLIDE_LEFT
|
||||
SLIDE_RIGHT
|
||||
SLIDE_UP
|
||||
ZOOM_IN
|
||||
ZOOM_OUT
|
||||
WIPE
|
||||
}
|
||||
|
||||
enum RenderJobStatus {
|
||||
QUEUED
|
||||
PROCESSING
|
||||
COMPLETED
|
||||
FAILED
|
||||
CANCELLED
|
||||
}
|
||||
|
||||
enum RenderStage {
|
||||
VIDEO_GENERATION
|
||||
TTS_GENERATION
|
||||
MUSIC_GENERATION
|
||||
AMBIENT_GENERATION
|
||||
MEDIA_MERGE
|
||||
SUBTITLE_OVERLAY
|
||||
FINALIZATION
|
||||
UPLOAD
|
||||
}
|
||||
|
||||
enum SourceType {
|
||||
MANUAL
|
||||
X_TWEET
|
||||
YOUTUBE
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Video SaaS — Project & Scenes
|
||||
// ============================================
|
||||
|
||||
model Project {
|
||||
id String @id @default(uuid())
|
||||
title String @db.VarChar(200)
|
||||
description String? @db.VarChar(1000)
|
||||
prompt String @db.VarChar(2000)
|
||||
|
||||
// AI Generated Script
|
||||
scriptJson Json? // Gemini API raw JSON output
|
||||
scriptVersion Int @default(0)
|
||||
|
||||
// Configuration
|
||||
language String @default("tr") @db.VarChar(5) // ISO 639-1
|
||||
aspectRatio AspectRatio @default(PORTRAIT_9_16)
|
||||
videoStyle VideoStyle @default(CINEMATIC)
|
||||
targetDuration Int @default(60) // saniye
|
||||
|
||||
// SEO & Social Content (skill-enhanced)
|
||||
seoKeywords String[] // Hedeflenen SEO anahtar kelimeler
|
||||
seoTitle String? @db.VarChar(200)
|
||||
seoDescription String? @db.VarChar(500)
|
||||
seoSchemaJson Json? // VideoObject structured data
|
||||
socialContent Json? // { youtubeTitle, tiktokCaption, instagramCaption, twitterText }
|
||||
referenceUrl String? @db.VarChar(500)
|
||||
|
||||
// İçerik Kaynağı
|
||||
sourceType SourceType @default(MANUAL) // MANUAL, X_TWEET, YOUTUBE
|
||||
sourceTweetData Json? // X/Twitter tweet verisi (id, author, metrics, media)
|
||||
|
||||
// Processing
|
||||
status ProjectStatus @default(DRAFT)
|
||||
progress Int @default(0) // 0-100
|
||||
errorMessage String?
|
||||
|
||||
// Output
|
||||
finalVideoUrl String?
|
||||
thumbnailUrl String?
|
||||
|
||||
// Stats
|
||||
creditsUsed Int @default(0)
|
||||
viewCount Int @default(0)
|
||||
|
||||
// Template Support
|
||||
isTemplate Boolean @default(false)
|
||||
templateId String? // Hangi şablondan klonlandı?
|
||||
template Template? @relation("ClonedFrom", fields: [templateId], references: [id])
|
||||
|
||||
// Relations
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
scenes Scene[]
|
||||
mediaAssets MediaAsset[]
|
||||
renderJobs RenderJob[]
|
||||
templateEntry Template? @relation("SourceProject")
|
||||
|
||||
// Timestamps & Soft Delete
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
completedAt DateTime?
|
||||
deletedAt DateTime?
|
||||
|
||||
@@index([userId])
|
||||
@@index([status])
|
||||
@@index([sourceType])
|
||||
@@index([isTemplate])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
model Scene {
|
||||
id String @id @default(uuid())
|
||||
order Int // Sahne sırası (1, 2, 3...)
|
||||
title String? @db.VarChar(200)
|
||||
|
||||
// Content
|
||||
narrationText String @db.Text // Hedef dildeki anlatım metni
|
||||
visualPrompt String @db.Text // İngilizce — Higgsfield AI prompt
|
||||
subtitleText String? @db.Text // Ekranda görünecek altyazı
|
||||
|
||||
// Timing
|
||||
duration Float @default(5.0) // saniye
|
||||
transitionType TransitionType @default(CUT)
|
||||
|
||||
// Relations
|
||||
projectId String
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
mediaAssets MediaAsset[]
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([projectId])
|
||||
@@index([order])
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Video SaaS — Media & Render
|
||||
// ============================================
|
||||
|
||||
model MediaAsset {
|
||||
id String @id @default(uuid())
|
||||
type MediaType
|
||||
|
||||
// Storage
|
||||
s3Key String? // Cloudflare R2 / S3 object key
|
||||
s3Bucket String? @db.VarChar(100)
|
||||
url String? // Public CDN URL
|
||||
|
||||
// Metadata
|
||||
fileName String? @db.VarChar(255)
|
||||
mimeType String? @db.VarChar(100)
|
||||
sizeBytes BigInt?
|
||||
durationMs Int? // Medya süresi (video/audio için)
|
||||
|
||||
// AI Provider Info
|
||||
aiProvider String? @db.VarChar(50) // higgsfield, elevenlabs, suno
|
||||
aiJobId String? // Dış API job ID'si
|
||||
|
||||
// Relations
|
||||
projectId String
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
sceneId String? // null = proje genelinde (müzik, final vb.)
|
||||
scene Scene? @relation(fields: [sceneId], references: [id], onDelete: SetNull)
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([projectId])
|
||||
@@index([sceneId])
|
||||
@@index([type])
|
||||
}
|
||||
|
||||
model RenderJob {
|
||||
id String @id @default(uuid())
|
||||
status RenderJobStatus @default(QUEUED)
|
||||
currentStage RenderStage?
|
||||
|
||||
// Queue Info
|
||||
queueName String @default("video-generation") @db.VarChar(100)
|
||||
bullJobId String? @db.VarChar(100) // BullMQ job ID
|
||||
|
||||
// Retry
|
||||
attemptNumber Int @default(1)
|
||||
maxAttempts Int @default(3)
|
||||
|
||||
// Processing
|
||||
workerHostname String? @db.VarChar(100)
|
||||
processingTimeMs Int? // Toplam render süresi
|
||||
errorMessage String?
|
||||
|
||||
// Output
|
||||
finalVideoUrl String?
|
||||
finalVideoS3Key String?
|
||||
|
||||
// Relations
|
||||
projectId String
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
logs RenderLog[]
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
startedAt DateTime?
|
||||
completedAt DateTime?
|
||||
|
||||
@@index([projectId])
|
||||
@@index([status])
|
||||
@@index([bullJobId])
|
||||
}
|
||||
|
||||
model RenderLog {
|
||||
id String @id @default(uuid())
|
||||
stage RenderStage
|
||||
level String @default("info") @db.VarChar(10) // info, warn, error
|
||||
message String @db.Text
|
||||
durationMs Int? // Bu aşamanın süresi
|
||||
metadata Json? // Ek JSON veri
|
||||
|
||||
// Relations
|
||||
renderJobId String
|
||||
renderJob RenderJob @relation(fields: [renderJobId], references: [id], onDelete: Cascade)
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([renderJobId])
|
||||
@@index([stage])
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Video SaaS — Template Marketplace
|
||||
// ============================================
|
||||
|
||||
model Template {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Display
|
||||
title String @db.VarChar(200)
|
||||
description String? @db.VarChar(500)
|
||||
thumbnailUrl String?
|
||||
previewVideoUrl String?
|
||||
|
||||
// Categorization
|
||||
category String @default("general") @db.VarChar(50)
|
||||
tags String[] // PostgreSQL array
|
||||
language String @default("tr") @db.VarChar(5)
|
||||
|
||||
// Source
|
||||
originalProjectId String @unique
|
||||
originalProject Project @relation("SourceProject", fields: [originalProjectId], references: [id])
|
||||
|
||||
// Stats
|
||||
usageCount Int @default(0)
|
||||
rating Float @default(0)
|
||||
ratingCount Int @default(0)
|
||||
isFeatured Boolean @default(false)
|
||||
isPublished Boolean @default(true)
|
||||
|
||||
// Relations
|
||||
clonedProjects Project[] @relation("ClonedFrom")
|
||||
usages TemplateUsage[]
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([category])
|
||||
@@index([language])
|
||||
@@index([isFeatured])
|
||||
@@index([usageCount])
|
||||
}
|
||||
|
||||
model TemplateUsage {
|
||||
id String @id @default(uuid())
|
||||
templateId String
|
||||
template Template @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
clonedProjectId String? // Oluşturulan projenin ID'si
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([templateId])
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Video SaaS — Billing & Credits
|
||||
// ============================================
|
||||
|
||||
model Plan {
|
||||
id String @id @default(uuid())
|
||||
name String @unique @db.VarChar(50) // free, pro, business
|
||||
displayName String @db.VarChar(100)
|
||||
description String? @db.VarChar(500)
|
||||
|
||||
// Pricing
|
||||
monthlyPrice Int @default(0) // cent cinsinden (1900 = $19)
|
||||
yearlyPrice Int? // Yıllık indirimli fiyat
|
||||
currency String @default("usd") @db.VarChar(3)
|
||||
|
||||
// Limits
|
||||
monthlyCredits Int @default(3)
|
||||
maxDuration Int @default(30) // saniye
|
||||
maxResolution String @default("720p") @db.VarChar(10)
|
||||
maxProjects Int @default(5)
|
||||
|
||||
// Stripe
|
||||
stripePriceId String? @db.VarChar(100)
|
||||
stripeYearlyPriceId String? @db.VarChar(100)
|
||||
|
||||
// Features
|
||||
features Json? // { "templates": true, "priorityQueue": false, ... }
|
||||
isActive Boolean @default(true)
|
||||
sortOrder Int @default(0)
|
||||
|
||||
// Relations
|
||||
subscriptions Subscription[]
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([name])
|
||||
@@index([isActive])
|
||||
}
|
||||
|
||||
model Subscription {
|
||||
id String @id @default(uuid())
|
||||
status String @default("active") @db.VarChar(20) // active, canceled, past_due, trialing
|
||||
|
||||
// Stripe
|
||||
stripeSubscriptionId String? @unique @db.VarChar(100)
|
||||
stripeCustomerId String? @db.VarChar(100)
|
||||
|
||||
// Billing Cycle
|
||||
currentPeriodStart DateTime?
|
||||
currentPeriodEnd DateTime?
|
||||
cancelAtPeriodEnd Boolean @default(false)
|
||||
|
||||
// Relations
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
planId String
|
||||
plan Plan @relation(fields: [planId], references: [id])
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
canceledAt DateTime?
|
||||
|
||||
@@index([userId])
|
||||
@@index([planId])
|
||||
@@index([stripeSubscriptionId])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model CreditTransaction {
|
||||
id String @id @default(uuid())
|
||||
amount Int // Pozitif: ekleme, Negatif: harcama
|
||||
type String @db.VarChar(30) // grant, usage, refund, bonus
|
||||
description String? @db.VarChar(200)
|
||||
|
||||
// Relations
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
projectId String? // Hangi projede harcandı
|
||||
|
||||
// Balance Snapshot
|
||||
balanceAfter Int @default(0)
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId])
|
||||
@@index([type])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Video SaaS — User Preferences & Notifications
|
||||
// ============================================
|
||||
|
||||
model UserPreference {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Defaults
|
||||
defaultLanguage String @default("tr") @db.VarChar(5)
|
||||
defaultVideoStyle VideoStyle @default(CINEMATIC)
|
||||
defaultDuration Int @default(60)
|
||||
|
||||
// UI
|
||||
theme String @default("dark") @db.VarChar(10)
|
||||
emailNotifications Boolean @default(true)
|
||||
pushNotifications Boolean @default(true)
|
||||
|
||||
// Relations
|
||||
userId String @unique
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model Notification {
|
||||
id String @id @default(uuid())
|
||||
type String @db.VarChar(30) // render_complete, render_failed, credit_low, system
|
||||
title String @db.VarChar(200)
|
||||
message String? @db.Text
|
||||
isRead Boolean @default(false)
|
||||
metadata Json? // { projectId, renderJobId, ... }
|
||||
|
||||
// Relations
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
readAt DateTime?
|
||||
|
||||
@@index([userId])
|
||||
@@index([isRead])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user