main
Some checks failed
Backend Deploy 🚀 / build-and-deploy (push) Has been cancelled

This commit is contained in:
Harun CAN
2026-03-29 12:43:49 +03:00
parent 829413f05d
commit 85c35c73e8
41 changed files with 6127 additions and 36 deletions

View File

@@ -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])
}