generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(uuid()) phone String @unique name String? role Role @default(STUDENT) language Language @default(FR) city String? activity String? // Business activity/sector createdAt DateTime @default(now()) updatedAt DateTime @updatedAt currentStreak Int @default(0) longestStreak Int @default(0) lastActivityAt DateTime? enrollments Enrollment[] responses Response[] messages Message[] payments Payment[] progress UserProgress[] businessProfile BusinessProfile? } model BusinessProfile { id String @id @default(uuid()) userId String @unique activityLabel String? // e.g. "Jus de Bissap" activityPhrase String? // Optimized elevator pitch activityType String? // e.g. "Production", "Service" locationCity String? mainCustomer String? mainProblem String? offerSimple String? promise String? marketData Json? // Stored Google Search results for TAM/SAM/SOM & Competition competitorList Json? // List of rivals found or declared financialProjections Json? // 3-year growth data fundingAsk String? // Amount and purpose lastUpdatedFromDay Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) } model Track { id String @id @default(uuid()) title String description String? duration Int // Duration in days language Language @default(FR) // Payment Integration Fields isPremium Boolean @default(false) priceAmount Int? // Price in smallest currency unit (e.g., cents/XOF) stripePriceId String? // Stripe Price ID createdAt DateTime @default(now()) updatedAt DateTime @updatedAt days TrackDay[] enrollments Enrollment[] payments Payment[] progress UserProgress[] } model TrackDay { id String @id @default(uuid()) trackId String dayNumber Float title String? audioUrl String? imageUrl String? videoUrl String? videoCaption String? lessonText String? exerciseType ExerciseType @default(TEXT) exercisePrompt String? validationKeyword String? buttonsJson Json? exerciseCriteria Json? badges Json? // Array of strings: ["B_MODULE_1_OK"] unlockCondition String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt track Track @relation(fields: [trackId], references: [id]) } model UserProgress { id String @id @default(uuid()) userId String trackId String score Int @default(0) lastInteraction DateTime @default(now()) exerciseStatus ExerciseStatus @default(PENDING) badges Json? // Array of strings: ["CLARTE", "CONFIANCE"] behavioralScoring Json? // { discipline_financiere: 0, organisation: 0, ... } confidenceScore Float? // STT Whisper avg_logprob mapped to 0-100% adminTranscription String? overrideAudioUrl String? reviewedBy String? iterationCount Int @default(0) // Tracks Deep Dive loops aiSource String? // Provider used (GEMINI, OPENAI) // Removed Enriched Data for Pitch Deck (Moved to BusinessProfile - Sprint 38) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) track Track @relation(fields: [trackId], references: [id]) @@unique([userId, trackId]) } model Enrollment { id String @id @default(uuid()) userId String trackId String status EnrollmentStatus @default(ACTIVE) currentDay Float @default(1) startedAt DateTime @default(now()) completedAt DateTime? lastActivityAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) track Track @relation(fields: [trackId], references: [id]) responses Response[] } model Response { id String @id @default(uuid()) enrollmentId String userId String dayNumber Int content String? // Text response mediaUrl String? // Voice/Image response createdAt DateTime @default(now()) aiSource String? // Provider used (GEMINI, OPENAI) enrollment Enrollment @relation(fields: [enrollmentId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id]) } model Message { id String @id @default(uuid()) userId String direction Direction // INBOUND, OUTBOUND channel String @default("WHATSAPP") content String? mediaUrl String? payload Json? // Raw payload from provider createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) @@index([userId, createdAt]) } enum Role { STUDENT ADMIN } enum EnrollmentStatus { ACTIVE COMPLETED DROPPED } enum Language { FR WOLOF } enum ContentType { TEXT AUDIO IMAGE VIDEO } enum Direction { INBOUND OUTBOUND } model Payment { id String @id @default(uuid()) userId String trackId String amount Int currency String @default("XOF") status PaymentStatus @default(PENDING) stripeSessionId String? @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) track Track @relation(fields: [trackId], references: [id]) } enum PaymentStatus { PENDING COMPLETED FAILED REFUNDED } enum ExerciseType { TEXT AUDIO BUTTON } enum ExerciseStatus { PENDING PENDING_REMEDIATION PENDING_REVIEW PENDING_DEEPDIVE COMPLETED } model TrainingData { id String @id @default(uuid()) audioUrl String transcription String @db.Text manualCorrection String? @db.Text rawWER Float? normalizedWER Float? status TrainingStatus @default(PENDING) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } enum TrainingStatus { PENDING REVIEWED IGNORED }