// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ============================================ // Core Models // ============================================ model User { id String @id @default(uuid()) email String @unique password String firstName String? lastName String? isActive Boolean @default(true) // Relations roles UserRole[] refreshTokens RefreshToken[] projects Project[] // Multi-tenancy (optional) tenantId String? tenant Tenant? @relation(fields: [tenantId], references: [id]) // Timestamps & Soft Delete createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? @@index([email]) @@index([tenantId]) } model Role { id String @id @default(uuid()) name String @unique description String? isSystem Boolean @default(false) // Relations users UserRole[] permissions RolePermission[] // Timestamps & Soft Delete createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? @@index([name]) } model Permission { id String @id @default(uuid()) name String @unique description String? resource String // e.g., "users", "posts" action String // e.g., "create", "read", "update", "delete" // Relations roles RolePermission[] // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([resource, action]) @@index([resource]) } // Many-to-many: User <-> Role model UserRole { id String @id @default(uuid()) userId String roleId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) @@unique([userId, roleId]) @@index([userId]) @@index([roleId]) } // Many-to-many: Role <-> Permission model RolePermission { id String @id @default(uuid()) roleId String permissionId String role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) @@unique([roleId, permissionId]) @@index([roleId]) @@index([permissionId]) } // ============================================ // Authentication // ============================================ model RefreshToken { id String @id @default(uuid()) token String @unique userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) expiresAt DateTime createdAt DateTime @default(now()) @@index([token]) @@index([userId]) } // ============================================ // Multi-tenancy (Optional) // ============================================ model Tenant { id String @id @default(uuid()) name String slug String @unique isActive Boolean @default(true) // Relations users User[] // Timestamps & Soft Delete createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? @@index([slug]) } // ============================================ // i18n / Translations (Optional - DB driven) // ============================================ model Translation { id String @id @default(uuid()) key String locale String // e.g., "en", "tr", "de" value String namespace String @default("common") // e.g., "common", "errors", "validation" // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([key, locale, namespace]) @@index([key]) @@index([locale]) @@index([namespace]) } // ============================================ // SkriptAI Core Models // ============================================ model Project { id String @id @default(uuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) topic String contentType String // e.g., "YouTube Documentary" targetAudience String[] // Array of strings speechStyle String[] targetDuration String tone String language String includeInterviews Boolean @default(true) userNotes String? @db.Text // JSON Blobs for structured but flexible data creativeBrief Json? // QAItem[] seo Json? // Title, desc, tags postProduction Json? // Brief commercial Json? // Sponsors, viability pacing Json? // PacingData[] neuroAnalysis Json? // NeuroAnalysisResult youtubeAudit Json? // YoutubeAudit // Relations script ScriptSegment[] characters CharacterProfile[] sources ResearchSource[] visualAssets VisualAsset[] // Meta createdAt DateTime @default(now()) updatedAt DateTime @updatedAt lastModified DateTime @default(now()) @@index([userId]) } model ScriptSegment { id String @id @default(uuid()) projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) segmentType String // Hook, Intro, Body... timeStart String duration String narratorScript String @db.Text visualDescription String @db.Text audioCues String? onScreenText String? stockQuery String? editorNotes String? generalNotes String? // AI Prompts videoPrompt String? @db.Text imagePrompt String? @db.Text generatedImageUrl String? orderIndex Int @default(0) // To keep sequence @@index([projectId]) } model CharacterProfile { id String @id @default(uuid()) projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) name String role String // Protagonist, Antagonist... values String @db.Text traits String @db.Text mannerisms String @db.Text @@index([projectId]) } model ResearchSource { id String @id @default(uuid()) projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) title String url String snippet String @db.Text type String // article, video, etc. selected Boolean @default(true) isNew Boolean @default(false) @@index([projectId]) } model VisualAsset { id String @id @default(uuid()) projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) url String desc String selected Boolean @default(true) @@index([projectId]) }