generated from fahricansecer/boilerplate-be
This commit is contained in:
@@ -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;
|
||||
@@ -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");
|
||||
@@ -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