// 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") } // Enum for user subscription plans enum Plan { BASIC // 50 images per month PRO // 500 images per month MAX // 1000 images per month } // Enum for batch processing status enum BatchStatus { PROCESSING COMPLETED FAILED } // Enum for individual image processing status enum ImageStatus { PENDING PROCESSING COMPLETED FAILED } // Enum for payment status enum PaymentStatus { PENDING COMPLETED FAILED CANCELLED REFUNDED } // Users table - OAuth ready with Google integration model User { id String @id @default(uuid()) googleUid String? @unique @map("google_uid") // Google OAuth UID emailHash String @unique @map("email_hash") // Hashed email for privacy email String @unique // Actual email for communication plan Plan @default(BASIC) quotaRemaining Int @default(50) @map("quota_remaining") // Monthly quota quotaResetDate DateTime @default(now()) @map("quota_reset_date") // When quota resets isActive Boolean @default(true) @map("is_active") stripeCustomerId String? @unique @map("stripe_customer_id") // Stripe customer ID createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relations batches Batch[] payments Payment[] apiKeys ApiKey[] downloads Download[] @@map("users") @@index([emailHash]) @@index([googleUid]) @@index([plan]) } // Batches table - Groups of images processed together model Batch { id String @id @default(uuid()) userId String @map("user_id") name String? // Batch name status BatchStatus @default(PROCESSING) totalImages Int @default(0) @map("total_images") processedImages Int @default(0) @map("processed_images") failedImages Int @default(0) @map("failed_images") metadata Json? // Additional batch metadata (e.g., processing settings) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") completedAt DateTime? @map("completed_at") // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) images Image[] downloads Download[] @@map("batches") @@index([userId]) @@index([status]) @@index([createdAt]) } // Images table - Individual images within batches model Image { id String @id @default(uuid()) batchId String @map("batch_id") originalName String @map("original_name") proposedName String? @map("proposed_name") // AI-generated name finalName String? @map("final_name") // User-approved final name visionTags Json? @map("vision_tags") // AI vision analysis results status ImageStatus @default(PENDING) fileSize Int? @map("file_size") // File size in bytes dimensions Json? // Width/height as JSON object mimeType String? @map("mime_type") s3Key String? @map("s3_key") // S3 object key for storage originalImageUrl String? @map("original_image_url") // URL to original image processedImageUrl String? @map("processed_image_url") // URL to processed image generatedFilename String? @map("generated_filename") // AI-generated filename processingError String? @map("processing_error") // Error message if processing failed createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") processedAt DateTime? @map("processed_at") // Relations batch Batch @relation(fields: [batchId], references: [id], onDelete: Cascade) @@map("images") @@index([batchId]) @@index([status]) @@index([originalName]) @@index([createdAt]) } // Payments table - Stripe integration for subscription management model Payment { id String @id @default(uuid()) userId String @map("user_id") stripeSessionId String? @unique @map("stripe_session_id") // Stripe Checkout Session ID stripePaymentId String? @unique @map("stripe_payment_id") // Stripe Payment Intent ID plan Plan // The plan being purchased amount Int // Amount in cents currency String @default("usd") status PaymentStatus @default(PENDING) metadata Json? // Additional payment metadata createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") paidAt DateTime? @map("paid_at") // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@map("payments") @@index([userId]) @@index([status]) @@index([stripeSessionId]) @@index([createdAt]) } // API Keys table - For potential API access model ApiKey { id String @id @default(uuid()) userId String @map("user_id") keyHash String @unique @map("key_hash") // Hashed API key name String // User-friendly name for the key isActive Boolean @default(true) @map("is_active") lastUsed DateTime? @map("last_used") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") expiresAt DateTime? @map("expires_at") // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) usage ApiKeyUsage[] @@map("api_keys") @@index([userId]) @@index([keyHash]) @@index([isActive]) } // API Key Usage tracking model ApiKeyUsage { id String @id @default(uuid()) apiKeyId String @map("api_key_id") endpoint String // Which API endpoint was called createdAt DateTime @default(now()) @map("created_at") // Relations apiKey ApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade) @@map("api_key_usage") @@index([apiKeyId]) @@index([createdAt]) } // Downloads table - Track ZIP file downloads model Download { id String @id @default(uuid()) batchId String @map("batch_id") userId String @map("user_id") zipPath String @map("zip_path") // Path to generated ZIP file fileSize Int @map("file_size") // ZIP file size in bytes totalSize Int? @map("total_size") // Total size of all files fileCount Int? @map("file_count") // Number of files in ZIP downloadUrl String? @map("download_url") // Pre-signed download URL status String @default("PENDING") // PENDING, READY, EXPIRED, FAILED expiresAt DateTime @map("expires_at") // When download link expires createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // Relations batch Batch @relation(fields: [batchId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@map("downloads") @@index([batchId]) @@index([userId]) @@index([status]) @@index([expiresAt]) }