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

@@ -0,0 +1,401 @@
-- CreateEnum
CREATE TYPE "ProjectStatus" AS ENUM ('DRAFT', 'GENERATING_SCRIPT', 'PENDING', 'GENERATING_MEDIA', 'RENDERING', 'COMPLETED', 'FAILED');
-- CreateEnum
CREATE TYPE "AspectRatio" AS ENUM ('PORTRAIT_9_16', 'SQUARE_1_1', 'LANDSCAPE_16_9');
-- CreateEnum
CREATE TYPE "VideoStyle" AS ENUM ('CINEMATIC', 'DOCUMENTARY', 'EDUCATIONAL', 'STORYTELLING', 'NEWS', 'PROMOTIONAL', 'ARTISTIC', 'MINIMALIST');
-- CreateEnum
CREATE TYPE "MediaType" AS ENUM ('VIDEO_CLIP', 'AUDIO_NARRATION', 'AUDIO_MUSIC', 'SUBTITLE', 'THUMBNAIL', 'FINAL_VIDEO');
-- CreateEnum
CREATE TYPE "TransitionType" AS ENUM ('CUT', 'FADE', 'DISSOLVE', 'SLIDE_LEFT', 'SLIDE_RIGHT', 'SLIDE_UP', 'ZOOM_IN', 'ZOOM_OUT', 'WIPE');
-- CreateEnum
CREATE TYPE "RenderJobStatus" AS ENUM ('QUEUED', 'PROCESSING', 'COMPLETED', 'FAILED', 'CANCELLED');
-- CreateEnum
CREATE TYPE "RenderStage" AS ENUM ('VIDEO_GENERATION', 'TTS_GENERATION', 'MUSIC_GENERATION', 'MEDIA_MERGE', 'SUBTITLE_OVERLAY', 'FINALIZATION', 'UPLOAD');
-- CreateTable
CREATE TABLE "Project" (
"id" TEXT NOT NULL,
"title" VARCHAR(200) NOT NULL,
"description" VARCHAR(1000),
"prompt" VARCHAR(2000) NOT NULL,
"scriptJson" JSONB,
"scriptVersion" INTEGER NOT NULL DEFAULT 0,
"language" VARCHAR(5) NOT NULL DEFAULT 'tr',
"aspectRatio" "AspectRatio" NOT NULL DEFAULT 'PORTRAIT_9_16',
"videoStyle" "VideoStyle" NOT NULL DEFAULT 'CINEMATIC',
"targetDuration" INTEGER NOT NULL DEFAULT 60,
"status" "ProjectStatus" NOT NULL DEFAULT 'DRAFT',
"progress" INTEGER NOT NULL DEFAULT 0,
"errorMessage" TEXT,
"finalVideoUrl" TEXT,
"thumbnailUrl" TEXT,
"creditsUsed" INTEGER NOT NULL DEFAULT 0,
"viewCount" INTEGER NOT NULL DEFAULT 0,
"isTemplate" BOOLEAN NOT NULL DEFAULT false,
"templateId" TEXT,
"userId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"completedAt" TIMESTAMP(3),
"deletedAt" TIMESTAMP(3),
CONSTRAINT "Project_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Scene" (
"id" TEXT NOT NULL,
"order" INTEGER NOT NULL,
"title" VARCHAR(200),
"narrationText" TEXT NOT NULL,
"visualPrompt" TEXT NOT NULL,
"subtitleText" TEXT,
"duration" DOUBLE PRECISION NOT NULL DEFAULT 5.0,
"transitionType" "TransitionType" NOT NULL DEFAULT 'CUT',
"projectId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Scene_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "MediaAsset" (
"id" TEXT NOT NULL,
"type" "MediaType" NOT NULL,
"s3Key" TEXT,
"s3Bucket" VARCHAR(100),
"url" TEXT,
"fileName" VARCHAR(255),
"mimeType" VARCHAR(100),
"sizeBytes" BIGINT,
"durationMs" INTEGER,
"aiProvider" VARCHAR(50),
"aiJobId" TEXT,
"projectId" TEXT NOT NULL,
"sceneId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "MediaAsset_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "RenderJob" (
"id" TEXT NOT NULL,
"status" "RenderJobStatus" NOT NULL DEFAULT 'QUEUED',
"currentStage" "RenderStage",
"queueName" VARCHAR(100) NOT NULL DEFAULT 'video-generation',
"bullJobId" VARCHAR(100),
"attemptNumber" INTEGER NOT NULL DEFAULT 1,
"maxAttempts" INTEGER NOT NULL DEFAULT 3,
"workerHostname" VARCHAR(100),
"processingTimeMs" INTEGER,
"errorMessage" TEXT,
"finalVideoUrl" TEXT,
"finalVideoS3Key" TEXT,
"projectId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"startedAt" TIMESTAMP(3),
"completedAt" TIMESTAMP(3),
CONSTRAINT "RenderJob_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "RenderLog" (
"id" TEXT NOT NULL,
"stage" "RenderStage" NOT NULL,
"level" VARCHAR(10) NOT NULL DEFAULT 'info',
"message" TEXT NOT NULL,
"durationMs" INTEGER,
"metadata" JSONB,
"renderJobId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "RenderLog_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Template" (
"id" TEXT NOT NULL,
"title" VARCHAR(200) NOT NULL,
"description" VARCHAR(500),
"thumbnailUrl" TEXT,
"previewVideoUrl" TEXT,
"category" VARCHAR(50) NOT NULL DEFAULT 'general',
"tags" TEXT[],
"language" VARCHAR(5) NOT NULL DEFAULT 'tr',
"originalProjectId" TEXT NOT NULL,
"usageCount" INTEGER NOT NULL DEFAULT 0,
"rating" DOUBLE PRECISION NOT NULL DEFAULT 0,
"ratingCount" INTEGER NOT NULL DEFAULT 0,
"isFeatured" BOOLEAN NOT NULL DEFAULT false,
"isPublished" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Template_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "TemplateUsage" (
"id" TEXT NOT NULL,
"templateId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"clonedProjectId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "TemplateUsage_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Plan" (
"id" TEXT NOT NULL,
"name" VARCHAR(50) NOT NULL,
"displayName" VARCHAR(100) NOT NULL,
"description" VARCHAR(500),
"monthlyPrice" INTEGER NOT NULL DEFAULT 0,
"yearlyPrice" INTEGER,
"currency" VARCHAR(3) NOT NULL DEFAULT 'usd',
"monthlyCredits" INTEGER NOT NULL DEFAULT 3,
"maxDuration" INTEGER NOT NULL DEFAULT 30,
"maxResolution" VARCHAR(10) NOT NULL DEFAULT '720p',
"maxProjects" INTEGER NOT NULL DEFAULT 5,
"stripePriceId" VARCHAR(100),
"stripeYearlyPriceId" VARCHAR(100),
"features" JSONB,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"sortOrder" INTEGER NOT NULL DEFAULT 0,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Plan_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Subscription" (
"id" TEXT NOT NULL,
"status" VARCHAR(20) NOT NULL DEFAULT 'active',
"stripeSubscriptionId" VARCHAR(100),
"stripeCustomerId" VARCHAR(100),
"currentPeriodStart" TIMESTAMP(3),
"currentPeriodEnd" TIMESTAMP(3),
"cancelAtPeriodEnd" BOOLEAN NOT NULL DEFAULT false,
"userId" TEXT NOT NULL,
"planId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"canceledAt" TIMESTAMP(3),
CONSTRAINT "Subscription_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "CreditTransaction" (
"id" TEXT NOT NULL,
"amount" INTEGER NOT NULL,
"type" VARCHAR(30) NOT NULL,
"description" VARCHAR(200),
"userId" TEXT NOT NULL,
"projectId" TEXT,
"balanceAfter" INTEGER NOT NULL DEFAULT 0,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "CreditTransaction_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "UserPreference" (
"id" TEXT NOT NULL,
"defaultLanguage" VARCHAR(5) NOT NULL DEFAULT 'tr',
"defaultVideoStyle" "VideoStyle" NOT NULL DEFAULT 'CINEMATIC',
"defaultDuration" INTEGER NOT NULL DEFAULT 60,
"theme" VARCHAR(10) NOT NULL DEFAULT 'dark',
"emailNotifications" BOOLEAN NOT NULL DEFAULT true,
"pushNotifications" BOOLEAN NOT NULL DEFAULT true,
"userId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "UserPreference_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Notification" (
"id" TEXT NOT NULL,
"type" VARCHAR(30) NOT NULL,
"title" VARCHAR(200) NOT NULL,
"message" TEXT,
"isRead" BOOLEAN NOT NULL DEFAULT false,
"metadata" JSONB,
"userId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"readAt" TIMESTAMP(3),
CONSTRAINT "Notification_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "Project_userId_idx" ON "Project"("userId");
-- CreateIndex
CREATE INDEX "Project_status_idx" ON "Project"("status");
-- CreateIndex
CREATE INDEX "Project_isTemplate_idx" ON "Project"("isTemplate");
-- CreateIndex
CREATE INDEX "Project_createdAt_idx" ON "Project"("createdAt");
-- CreateIndex
CREATE INDEX "Scene_projectId_idx" ON "Scene"("projectId");
-- CreateIndex
CREATE INDEX "Scene_order_idx" ON "Scene"("order");
-- CreateIndex
CREATE INDEX "MediaAsset_projectId_idx" ON "MediaAsset"("projectId");
-- CreateIndex
CREATE INDEX "MediaAsset_sceneId_idx" ON "MediaAsset"("sceneId");
-- CreateIndex
CREATE INDEX "MediaAsset_type_idx" ON "MediaAsset"("type");
-- CreateIndex
CREATE INDEX "RenderJob_projectId_idx" ON "RenderJob"("projectId");
-- CreateIndex
CREATE INDEX "RenderJob_status_idx" ON "RenderJob"("status");
-- CreateIndex
CREATE INDEX "RenderJob_bullJobId_idx" ON "RenderJob"("bullJobId");
-- CreateIndex
CREATE INDEX "RenderLog_renderJobId_idx" ON "RenderLog"("renderJobId");
-- CreateIndex
CREATE INDEX "RenderLog_stage_idx" ON "RenderLog"("stage");
-- CreateIndex
CREATE UNIQUE INDEX "Template_originalProjectId_key" ON "Template"("originalProjectId");
-- CreateIndex
CREATE INDEX "Template_category_idx" ON "Template"("category");
-- CreateIndex
CREATE INDEX "Template_language_idx" ON "Template"("language");
-- CreateIndex
CREATE INDEX "Template_isFeatured_idx" ON "Template"("isFeatured");
-- CreateIndex
CREATE INDEX "Template_usageCount_idx" ON "Template"("usageCount");
-- CreateIndex
CREATE INDEX "TemplateUsage_templateId_idx" ON "TemplateUsage"("templateId");
-- CreateIndex
CREATE INDEX "TemplateUsage_userId_idx" ON "TemplateUsage"("userId");
-- CreateIndex
CREATE UNIQUE INDEX "Plan_name_key" ON "Plan"("name");
-- CreateIndex
CREATE INDEX "Plan_name_idx" ON "Plan"("name");
-- CreateIndex
CREATE INDEX "Plan_isActive_idx" ON "Plan"("isActive");
-- CreateIndex
CREATE UNIQUE INDEX "Subscription_stripeSubscriptionId_key" ON "Subscription"("stripeSubscriptionId");
-- CreateIndex
CREATE INDEX "Subscription_userId_idx" ON "Subscription"("userId");
-- CreateIndex
CREATE INDEX "Subscription_planId_idx" ON "Subscription"("planId");
-- CreateIndex
CREATE INDEX "Subscription_stripeSubscriptionId_idx" ON "Subscription"("stripeSubscriptionId");
-- CreateIndex
CREATE INDEX "Subscription_status_idx" ON "Subscription"("status");
-- CreateIndex
CREATE INDEX "CreditTransaction_userId_idx" ON "CreditTransaction"("userId");
-- CreateIndex
CREATE INDEX "CreditTransaction_type_idx" ON "CreditTransaction"("type");
-- CreateIndex
CREATE INDEX "CreditTransaction_createdAt_idx" ON "CreditTransaction"("createdAt");
-- CreateIndex
CREATE UNIQUE INDEX "UserPreference_userId_key" ON "UserPreference"("userId");
-- CreateIndex
CREATE INDEX "UserPreference_userId_idx" ON "UserPreference"("userId");
-- CreateIndex
CREATE INDEX "Notification_userId_idx" ON "Notification"("userId");
-- CreateIndex
CREATE INDEX "Notification_isRead_idx" ON "Notification"("isRead");
-- CreateIndex
CREATE INDEX "Notification_createdAt_idx" ON "Notification"("createdAt");
-- AddForeignKey
ALTER TABLE "Project" ADD CONSTRAINT "Project_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Project" ADD CONSTRAINT "Project_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Scene" ADD CONSTRAINT "Scene_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "MediaAsset" ADD CONSTRAINT "MediaAsset_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "MediaAsset" ADD CONSTRAINT "MediaAsset_sceneId_fkey" FOREIGN KEY ("sceneId") REFERENCES "Scene"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "RenderJob" ADD CONSTRAINT "RenderJob_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "RenderLog" ADD CONSTRAINT "RenderLog_renderJobId_fkey" FOREIGN KEY ("renderJobId") REFERENCES "RenderJob"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Template" ADD CONSTRAINT "Template_originalProjectId_fkey" FOREIGN KEY ("originalProjectId") REFERENCES "Project"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "TemplateUsage" ADD CONSTRAINT "TemplateUsage_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "TemplateUsage" ADD CONSTRAINT "TemplateUsage_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_planId_fkey" FOREIGN KEY ("planId") REFERENCES "Plan"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CreditTransaction" ADD CONSTRAINT "CreditTransaction_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "UserPreference" ADD CONSTRAINT "UserPreference_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,18 @@
-- CreateEnum
CREATE TYPE "SourceType" AS ENUM ('MANUAL', 'X_TWEET', 'YOUTUBE');
-- AlterEnum
ALTER TYPE "RenderStage" ADD VALUE 'AMBIENT_GENERATION';
-- AlterTable
ALTER TABLE "Project" ADD COLUMN "referenceUrl" VARCHAR(500),
ADD COLUMN "seoDescription" VARCHAR(500),
ADD COLUMN "seoKeywords" TEXT[],
ADD COLUMN "seoSchemaJson" JSONB,
ADD COLUMN "seoTitle" VARCHAR(200),
ADD COLUMN "socialContent" JSONB,
ADD COLUMN "sourceTweetData" JSONB,
ADD COLUMN "sourceType" "SourceType" NOT NULL DEFAULT 'MANUAL';
-- CreateIndex
CREATE INDEX "Project_sourceType_idx" ON "Project"("sourceType");

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