Prmbr/prisma/schema.prisma

339 lines
11 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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")
}