// 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") } // ============================================ // MODELOS BASE // ============================================ model User { id String @id @default(cuid()) email String? @unique name String? externalId String? // ID externo (Telegram chatId, etc.) source String? // "telegram", "web", "onlyfans", etc. tier String @default("free") // free, basic, premium, pro stripeCustomerId String? totalSpent Float @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt chatSessions ChatSession[] assetDeliveries AssetDelivery[] influencerSubscriptions InfluencerSubscription[] @@unique([externalId, source]) } model Project { id String @id @default(cuid()) name String description String? style String @default("default") status String @default("active") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt repos Repo[] analyses Analysis[] contents Content[] } model Repo { id String @id @default(cuid()) url String name String status String @default("cloned") projectId String? project Project? @relation(fields: [projectId], references: [id]) analyses Analysis[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Analysis { id String @id @default(cuid()) type String result String summary String? repoId String? repo Repo? @relation(fields: [repoId], references: [id]) projectId String? project Project? @relation(fields: [projectId], references: [id]) createdAt DateTime @default(now()) } model AgentTask { id String @id @default(cuid()) type String status String @default("pending") input String output String? createdAt DateTime @default(now()) completedAt DateTime? } // ============================================ // MODELOS DE INFLUENCER (CHARACTER) // ============================================ model Character { id String @id @default(cuid()) name String slug String @unique displayName String? shortBio String? description String? referenceImage String? // Imagen canónica para consistencia facial bodyReference String? // Referencia corporal traits String? // JSON con rasgos de personalidad orientation String? // Orientación/estilo (mujer, hombre gay, etc.) styleDescription String? // Descripción visual para generación de imágenes systemPrompt String? // Prompt base para el chat telegramBotToken String? // Token del bot de Telegram específico // Storytelling backstory String? // Historia de fondo personality String? // Personalidad detallada interests String? // JSON array de intereses catchphrases String? // JSON array de frases típicas // Configuración de chat por tier chatFreeLimit Int @default(10) // Mensajes gratis por día chatBasicTone String? // Tono para tier basic chatPremiumTone String? // Tono para tier premium (íntimo) chatProTone String? // Tono para tier pro (novia IA) isActive Boolean @default(true) contents Content[] pets Pet[] chatSessions ChatSession[] assetDeliveries AssetDelivery[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // ============================================ // MODELOS DE CHAT / NOVIA IA // ============================================ model ChatSession { id String @id @default(cuid()) userId String user User @relation(fields: [userId], references: [id]) characterId String character Character @relation(fields: [characterId], references: [id]) channel String @default("telegram") // telegram, web, etc. heatScore Int @default(0) // 0-100, sube con interacción msgCountToday Int @default(0) lastMessageAt DateTime? isActive Boolean @default(true) messages ChatMessage[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([userId, characterId, channel]) } model ChatMessage { id String @id @default(cuid()) sessionId String session ChatSession @relation(fields: [sessionId], references: [id]) role String // "user", "assistant", "system" content String metadata String? // JSON (ej: si se envió un asset) createdAt DateTime @default(now()) } // ============================================ // MODELOS DE CONTENIDO MULTIMEDIA // ============================================ model Content { id String @id @default(cuid()) type String // "image", "video", "audio", "text", "reel", "story", "carousel" title String description String? prompt String optimizedPrompt String? filePath String? thumbnail String? platform String @default("general") status String @default("pending") nsfwLevel Int @default(0) // 0=SFW, 1=suggestive, 2=NSFW, 3=explicit metadata String? projectId String? project Project? @relation(fields: [projectId], references: [id]) characterId String? character Character? @relation(fields: [characterId], references: [id]) petId String? pet Pet? @relation(fields: [petId], references: [id]) censorFlags CensorFlag[] posts Post[] assetDeliveries AssetDelivery[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // Tracking de qué assets se han enviado a qué usuario model AssetDelivery { id String @id @default(cuid()) contentId String content Content @relation(fields: [contentId], references: [id]) userId String user User @relation(fields: [userId], references: [id]) characterId String character Character @relation(fields: [characterId], references: [id]) channel String @default("telegram") deliveredAt DateTime @default(now()) @@unique([contentId, userId]) // No repetir el mismo asset al mismo usuario } // ============================================ // MODELOS DE CENSURA // ============================================ model CensorRule { id String @id @default(cuid()) platform String category String rule String severity String @default("medium") autoAction String @default("warn") isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model CensorFlag { id String @id @default(cuid()) contentId String content Content @relation(fields: [contentId], references: [id]) category String reason String severity String action String createdAt DateTime @default(now()) } // ============================================ // MODELOS DE MONETIZACIÓN // ============================================ model MonetizationPlatform { id String @id @default(cuid()) name String // OnlyFans, Patreon, Fansly, etc. type String // "subscription", "tips", "ppv", "mixed" url String? apiKey String? accountId String? accountName String? legalTerms String? // JSON con términos legales contentRules String? // JSON con reglas de contenido feePercentage Float? payoutSchedule String? isActive Boolean @default(true) isVerified Boolean @default(false) metadata String? posts Post[] earnings Earning[] subscribers Subscriber[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Subscriber { id String @id @default(cuid()) platformId String platform MonetizationPlatform @relation(fields: [platformId], references: [id]) externalId String? username String? tier String? status String @default("active") joinedAt DateTime? expiresAt DateTime? totalSpent Float @default(0) metadata String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Earning { id String @id @default(cuid()) platformId String platform MonetizationPlatform @relation(fields: [platformId], references: [id]) subscriptionId String? subscription InfluencerSubscription? @relation(fields: [subscriptionId], references: [id]) type String // "subscription", "post", "tip", "ppv" amount Float currency String @default("USD") postId String? subscriberId String? status String @default("pending") // pending, completed, failed paymentMethod String? // "card", "bank_transfer", "paypal" stripePaymentIntentId String? // Para rastrear en Stripe isRecurring Boolean @default(false) description String? processedAt DateTime? metadata String? createdAt DateTime @default(now()) } // ============================================ // MODELOS DE PUBLICACIÓN // ============================================ model Post { id String @id @default(cuid()) title String? caption String? hashtags String? type String status String @default("draft") contentId String? content Content? @relation(fields: [contentId], references: [id]) platformId String? platform MonetizationPlatform? @relation(fields: [platformId], references: [id]) scheduledAt DateTime? publishedAt DateTime? externalPostId String? postUrl String? engagementStats String? storyId String? story Story? @relation(fields: [storyId], references: [id]) metadata String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // ============================================ // MODELOS DE STORYTELLING // ============================================ model Story { id String @id @default(cuid()) title String description String? genre String? targetAudience String? tone String? structure String? characterIds String? totalEpisodes Int @default(1) currentEpisode Int @default(1) status String @default("draft") monetizationStrategy String? posts Post[] episodes StoryEpisode[] analytics StoryAnalytics? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model StoryEpisode { id String @id @default(cuid()) storyId String story Story @relation(fields: [storyId], references: [id]) episodeNum Int title String synopsis String? content String hook String? cliffhanger String? status String @default("draft") scheduledAt DateTime? publishedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model StoryAnalytics { id String @id @default(cuid()) storyId String @unique story Story @relation(fields: [storyId], references: [id]) totalViews Int @default(0) totalEngagement Float @default(0) avgWatchTime Float? completionRate Float? revenue Float @default(0) subscriberGain Int @default(0) bestPerformingEpisode Int? metadata String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // ============================================ // MODELOS DE AUTOMATIZACIÓN // ============================================ model Automation { id String @id @default(cuid()) name String description String? type String trigger String triggerConfig String? actions String isActive Boolean @default(true) lastRunAt DateTime? nextRunAt DateTime? runCount Int @default(0) metadata String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model AutomationLog { id String @id @default(cuid()) automationId String? status String input String? output String? error String? duration Int? createdAt DateTime @default(now()) } // ============================================ // MODELOS DE TENDENCIAS // ============================================ model Trend { id String @id @default(cuid()) platform String type String name String description String? volume Int? growth Float? startDate DateTime? endDate DateTime? relatedTags String? contentIdeas String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // ============================================ // MODELOS DE PLANTILLAS // ============================================ model PromptTemplate { id String @id @default(cuid()) name String category String template String variables String platform String @default("general") isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model ContentTemplate { id String @id @default(cuid()) name String type String platform String structure String hooks String? ctas String? hashtags String? bestTimes String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // ============================================ // MODELOS DE MASCOTAS/COMPAÑEROS // ============================================ model Pet { id String @id @default(cuid()) name String type String breed String? description String? referenceImage String? traits String? personality String? color String? accessories String? characterId String? character Character? @relation(fields: [characterId], references: [id], onDelete: Cascade) contents Content[] isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // ============================================ // MODELOS DE INFLUENCERS IA DE REFERENCIA // ============================================ model AIInfluencer { id String @id @default(cuid()) name String handle String? platform String followers Int? engagement Float? niche String? style String? contentTypes String? postingSchedule String? visualStyle String? monetizationType String? signatureElements String? petCompanion Boolean @default(false) petType String? analysis String? lessons String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt influencerSubscriptions InfluencerSubscription[] } // Suscripciones por influencer: cada cliente se suscribe por separado a cada influencer model InfluencerSubscription { id String @id @default(cuid()) influencerId String influencer AIInfluencer @relation(fields: [influencerId], references: [id]) userId String? user User? @relation(fields: [userId], references: [id]) tier String // tier contratado para esta suscripción (basic, premium, etc.) status String @default("active") // active, paused, expired, cancelled joinedAt DateTime @default(now()) expiresAt DateTime? nextRenewalDate DateTime? // Próxima fecha de renovación automática autoRenew Boolean @default(true) // Renovación automática activada price Float? currency String @default("USD") // Integración con Stripe stripeSubscriptionId String? // ID de suscripción en Stripe stripeCustomerId String? // ID de cliente en Stripe paymentMethodId String? // ID del método de pago en Stripe metadata String? earnings Earning[] // Relación con pagos registrados createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // ============================================ // MODELOS DE ESTRATEGIAS VIRALES // ============================================ model ViralStrategy { id String @id @default(cuid()) name String description String? platform String contentType String hook String? structure String? elements String? estimatedReach Int? difficulty String @default("medium") timeframe String? examples String? tags String? successRate Float? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }