// Prisma Schema for DevFlix / InfoFlix Subscription Platform datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } enum Role { admin student } enum SubscriptionStatus { ACTIVE OVERDUE CANCELED TRIAL } enum VideoType { youtube direct } enum PaymentStatus { PENDING RECEIVED CONFIRMED OVERDUE REFUNDED } enum BillingType { PIX CREDIT_CARD BOLETO } enum CertificateMode { PER_MODULE FULL_COURSE } model User { id String @id @default(uuid()) name String email String @unique password String role Role @default(student) subscriptionStatus SubscriptionStatus @default(TRIAL) @map("subscription_status") asaasCustomerId String? @map("asaas_customer_id") cpf String? whatsapp String? birthDate String? @map("birth_date") avatarUrl String? @map("avatar_url") @db.Text trialEndsAt DateTime? @map("trial_ends_at") resetPasswordToken String? @map("reset_password_token") @db.Text resetPasswordExpires DateTime? @map("reset_password_expires") createdAt DateTime @default(now()) @map("created_at") notes Note[] progress Progress[] payments Payment[] moduleGrades ModuleGrade[] certificates Certificate[] unlockedCourses String[] @default([]) @map("unlocked_courses") @@map("users") } model Course { id String @id @default(uuid()) title String description String @db.Text thumbnail String category String certificateMode CertificateMode @default(FULL_COURSE) @map("certificate_mode") isLocked Boolean @default(false) @map("is_locked") price Float? createdAt DateTime @default(now()) @map("created_at") modules Module[] payments Payment[] @@map("courses") } model Module { id String @id @default(uuid()) courseId String @map("course_id") title String order Int createdAt DateTime @default(now()) @map("created_at") course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) lessons Lesson[] activity ModuleActivity? @@map("modules") } model Lesson { id String @id @default(uuid()) moduleId String @map("module_id") title String videoUrl String @map("video_url") @db.Text videoType VideoType @map("video_type") order Int content String? @db.Text thumbnailUrl String? @map("thumbnail_url") @db.Text createdAt DateTime @default(now()) @map("created_at") module Module @relation(fields: [moduleId], references: [id], onDelete: Cascade) notes Note[] progress Progress[] @@map("lessons") } model Note { id String @id @default(uuid()) userId String @map("user_id") lessonId String @map("lesson_id") content String @db.Text createdAt DateTime @default(now()) @map("created_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade) @@unique([userId, lessonId]) @@map("notes") } model Progress { id String @id @default(uuid()) userId String @map("user_id") lessonId String @map("lesson_id") watchedPercentage Int @default(0) @map("watched_percentage") completed Boolean @default(false) updatedAt DateTime @updatedAt @map("updated_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade) @@unique([userId, lessonId]) @@map("progress") } model Payment { id String @id userId String @map("user_id") value Decimal @db.Decimal(10, 2) status PaymentStatus billingType BillingType @map("billing_type") invoiceUrl String @map("invoice_url") @db.Text dueDate DateTime @map("due_date") @db.Date paidAt DateTime? @map("paid_at") planId String? @map("plan_id") courseId String? @map("course_id") description String? @db.Text createdAt DateTime @default(now()) @map("created_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) plan Plan? @relation(fields: [planId], references: [id], onDelete: SetNull) course Course? @relation(fields: [courseId], references: [id], onDelete: SetNull) @@map("payments") } model WebhookLog { id String @id @default(uuid()) event String payload String @db.Text receivedAt DateTime @default(now()) @map("received_at") @@map("webhook_logs") } model Notification { id String @id @default(uuid()) userId String @map("user_id") // Can be 'ALL' for system wide title String message String @db.Text type String @default("info") // 'info', 'success', 'warning', 'error' read Boolean @default(false) createdAt DateTime @default(now()) @map("created_at") @@map("notifications") } model ModuleActivity { id String @id @default(uuid()) moduleId String @unique @map("module_id") questions Json // e.g. [{ question: "...", options: ["A", "B"], correctIndex: 0 }] createdAt DateTime @default(now()) @map("created_at") module Module @relation(fields: [moduleId], references: [id], onDelete: Cascade) grades ModuleGrade[] @@map("module_activities") } model ModuleGrade { id String @id @default(uuid()) userId String @map("user_id") activityId String @map("activity_id") score Float passed Boolean @default(false) createdAt DateTime @default(now()) @map("created_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) activity ModuleActivity @relation(fields: [activityId], references: [id], onDelete: Cascade) @@unique([userId, activityId]) @@map("module_grades") } model Certificate { id String @id @default(uuid()) userId String @map("user_id") courseId String? @map("course_id") moduleId String? @map("module_id") certificateType String @map("certificate_type") // 'COURSE' or 'MODULE' unlockedAt DateTime @default(now()) @map("unlocked_at") finalGrade Float? @map("final_grade") courseName String @map("course_name") // Snapshot of course title moduleName String? @map("module_name") // Snapshot of module title user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@map("certificates") } model Plan { id String @id @default(uuid()) title String description String @db.Text price Float cycle String // 'MONTHLY', 'YEARLY', 'LIFETIME' active Boolean @default(true) includedCourses String[] @default([]) @map("included_courses") createdAt DateTime @default(now()) @map("created_at") payments Payment[] @@map("plans") } model SystemSettings { id String @id @default("default") trialDurationDays Int @default(7) @map("trial_duration_days") asaasEnvironment String @default("sandbox") @map("asaas_environment") asaasApiKey String @default("") @map("asaas_api_key") asaasWebhookUrl String @default("") @map("asaas_webhook_url") asaasWebhookSecret String @default("") @map("asaas_webhook_secret") helpText String @db.Text @default("# Central de Ajuda") @map("help_text") enableBoleto Boolean @default(true) @map("enable_boleto") enableInstallmentBoleto Boolean @default(false) @map("enable_installment_boleto") maxBoletoInstallments Int @default(3) @map("max_boleto_installments") evolutionApiUrl String @default("https://evolution.microtecinformaticacurso.com.br") @map("evolution_api_url") evolutionApiKey String @default("") @map("evolution_api_key") evolutionInstance String @default("microtecflix") @map("evolution_instance") whatsappConnected Boolean @default(false) @map("whatsapp_connected") whatsappPhoneNumber String? @map("whatsapp_phone_number") brandName String @default("MICROTEC") @map("brand_name") brandSlogan String @default("Acelere seus estudos em informática e pacote Office no estilo Netflix.") @map("brand_slogan") cnpj String @default("") @map("cnpj") address String @default("") @map("address") smtpHost String? @map("smtp_host") smtpPort Int? @default(587) @map("smtp_port") smtpUser String? @map("smtp_user") smtpPass String? @map("smtp_pass") smtpFrom String? @default("no-reply@microtecinformaticacurso.com.br") @map("smtp_from") smtpSecure Boolean @default(false) @map("smtp_secure") @@map("system_settings") }