// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(cuid()) // Better Auth will generate IDs email String @unique name String // Better Auth required field emailVerified Boolean @default(false) // Better Auth required field image String? // Better Auth field (avatar) username String? @unique bio String? language String @default("en") isAdmin Boolean @default(false) versionLimit Int @default(3) subscriptionPlanId String @default("free") subscribePlan String @default("free") // Legacy field maxVersionLimit Int @default(3) promptLimit Int? creditBalance Float @default(0.0) stripeCustomerId String? @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Better Auth relationships sessions Session[] accounts Account[] // App relationships subscriptionPlan SubscriptionPlan @relation(fields: [subscriptionPlanId], references: [id]) prompts Prompt[] credits Credit[] subscriptions Subscription[] simulatorRuns SimulatorRun[] @@map("users") } // 订阅套餐模型 model SubscriptionPlan { id String @id // "free", "pro" 等 name String // 套餐名称 displayName String // 显示名称(支持国际化) description String? // 套餐描述 price Float @default(0) // 价格(美元) currency String @default("usd") // 货币 interval String @default("month") // 计费周期: "month", "year" stripePriceId String? @unique // Stripe 价格 ID isActive Boolean @default(true) // 是否激活 sortOrder Int @default(0) // 排序顺序 costMultiplier Float @default(1.0) // 费用倍率,默认1倍 // 权益配置 (JSON 格式存储) features Json // 功能特性配置 limits Json // 限制配置 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // 关联关系 users User[] subscriptions Subscription[] models Model[] @@map("subscription_plans") } model Prompt { id String @id @default(cuid()) name String content String description String? isPublic Boolean @default(false) // 保留用于向后兼容 permissions String @default("private") // "private" | "public" visibility String? // "under_review" | "published" | null createdAt DateTime @default(now()) updatedAt DateTime @updatedAt userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) tags PromptTag[] versions PromptVersion[] album PromptAlbum? @relation(fields: [albumId], references: [id]) albumId String? tests PromptTestRun[] stats PromptStats? simulatorRuns SimulatorRun[] @@map("prompts") } model PromptVersion { id String @id @default(cuid()) version Int content String changelog String? createdAt DateTime @default(now()) promptId String prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) simulatorRuns SimulatorRun[] @@unique([promptId, version]) @@map("prompt_versions") } model PromptTag { id String @id @default(cuid()) name String @unique color String @default("#3B82F6") prompts Prompt[] @@map("prompt_tags") } model PromptAlbum { id String @id @default(cuid()) name String description String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt prompts Prompt[] @@map("prompt_albums") } model PromptTestRun { id String @id @default(cuid()) input String output String? success Boolean @default(false) error String? createdAt DateTime @default(now()) promptId String prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) @@map("prompt_test_runs") } model PromptStats { id String @id @default(cuid()) promptId String @unique viewCount Int @default(0) // 浏览计数 likeCount Int @default(0) // 点赞计数 rating Float? // 平均评分 ratingCount Int @default(0) // 评分数量 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) @@map("prompt_stats") } model Credit { id String @id @default(cuid()) userId String amount Float // 交易金额(正数为充值,负数为消费) balance Float @default(5) // 执行该交易后的余额 type String // "system_gift", "subscription_monthly", "user_purchase", "consumption" category String? // 消费类别: "simulation", "api_call", "export" 等 note String? // 备注说明 referenceId String? // 关联的记录ID(如SimulatorRun的ID) referenceType String? // 关联记录类型(如"simulator_run") expiresAt DateTime? // 过期时间,null表示永久有效 isActive Boolean @default(true) // 是否激活状态 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@map("credits") } // 订阅记录模型 model Subscription { id String @id @default(cuid()) userId String // 用户 ID subscriptionPlanId String // 订阅套餐 ID stripeSubscriptionId String? @unique // Stripe 订阅 ID stripeCustomerId String? // Stripe 客户 ID(冗余存储,便于查询) // 订阅状态和时间 isActive Boolean @default(false) // 是否有效 startDate DateTime? // 开始时间(订阅激活时设置) endDate DateTime? // 结束时间(订阅激活时设置) // 订阅状态 status String @default("pending") // "pending", "active", "canceled", "expired", "failed" // 元数据 metadata Json? // 额外的元数据(如 Stripe 的原始数据) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // 关联关系 user User @relation(fields: [userId], references: [id], onDelete: Cascade) subscriptionPlan SubscriptionPlan @relation(fields: [subscriptionPlanId], references: [id]) @@map("subscriptions") } // AI 模型配置表 - 所有模型默认可用于所有套餐 model Model { id String @id @default(cuid()) subscriptionPlanId String @default("free") // 默认关联到 free 套餐 modelId String @unique // 全局唯一的模型 ID,如 "openai/gpt-4" name String // 显示名称,如 "GPT-4" provider String // 提供商,如 "OpenAI" serviceProvider String @default("openrouter") // 服务提供者,如 "openrouter", "replicate" outputType String @default("text") // 输出类型,如 "text", "image", "video", "audio" description String? // 模型描述 maxTokens Int? // 最大 token 数 inputCostPer1k Float? // 输入成本(每1K tokens) outputCostPer1k Float? // 输出成本(每1K tokens) supportedFeatures Json? // 支持的特性(如 function_calling, vision 等) metadata Json? // 其他元数据 customLimits Json? // 自定义限制(如每日调用次数、最大 tokens 等) isActive Boolean @default(true) // 是否启用 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // 关联关系 subscriptionPlan SubscriptionPlan @relation(fields: [subscriptionPlanId], references: [id], onDelete: Cascade) simulatorRuns SimulatorRun[] @@map("models") } // 模拟器运行记录 model SimulatorRun { id String @id @default(cuid()) userId String name String @default("Simulation Run") // 运行名称 promptId String promptVersionId String? // 可选,如果选择了特定版本 modelId String userInput String // 用户输入内容 promptContent String? // 自定义提示词内容(如果用户修改了原提示词) output String? // AI响应输出 error String? // 错误信息 status String @default("pending") // "pending", "running", "completed", "failed" permissions String @default("private") // "private" | "public" visibility String? // "under_review" | "published" | null // 运行配置 temperature Float? @default(0.7) maxTokens Int? topP Float? frequencyPenalty Float? presencePenalty Float? // 消耗和统计 inputTokens Int? // 输入token数 outputTokens Int? // 输出token数 totalCost Float? // 总消费 duration Int? // 运行时长(毫秒) creditId String? // 关联的信用消费记录ID // 调试信息(仅开发环境) debugRequest Json? // 原始请求参数 debugResponse Json? // 原始响应内容 // 生成的文件路径 generatedFilePath String? // S3存储路径 createdAt DateTime @default(now()) completedAt DateTime? // 关联关系 user User @relation(fields: [userId], references: [id], onDelete: Cascade) prompt Prompt @relation(fields: [promptId], references: [id], onDelete: Cascade) promptVersion PromptVersion? @relation(fields: [promptVersionId], references: [id], onDelete: SetNull) model Model @relation(fields: [modelId], references: [id]) // 添加索引优化查询性能 @@index([userId, createdAt(sort: Desc)]) @@index([userId, status, createdAt(sort: Desc)]) @@map("simulator_runs") } model Session { id String @id expiresAt DateTime token String createdAt DateTime updatedAt DateTime ipAddress String? userAgent String? userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([token]) @@map("session") } model Account { id String @id accountId String providerId String userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) accessToken String? refreshToken String? idToken String? accessTokenExpiresAt DateTime? refreshTokenExpiresAt DateTime? scope String? password String? createdAt DateTime updatedAt DateTime @@map("account") } model Verification { id String @id identifier String value String expiresAt DateTime createdAt DateTime? updatedAt DateTime? @@map("verification") }