| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- // DoTouch.AI - Prisma Schema
- // PostgreSQL 16 datasource, client generated via `pnpm db:generate`
- generator client {
- provider = "prisma-client-js"
- }
- datasource db {
- provider = "postgresql"
- url = env("DATABASE_URL")
- }
- // ---- 用户 ----
- model User {
- id String @id @default(cuid())
- email String @unique
- passwordHash String @map("password_hash")
- // 社交登录:provider = local | google | facebook;providerId 为平台唯一 ID(同邮箱绑定后记录)
- provider String @default("local")
- providerId String? @unique @map("provider_id")
- role String @default("user") // user | admin
- currency String @default("USD")
- balanceCents BigInt @default(0) @map("balance_cents")
- status String @default("active") // active | suspended | banned
- createdAt DateTime @default(now()) @map("created_at")
- updatedAt DateTime @updatedAt @map("updated_at")
- // 用量配额(null = 不限)
- dailyRequestLimit Int? @map("daily_request_limit")
- dailyTokenLimit BigInt? @map("daily_token_limit")
- dailyCostCentsLimit Int? @map("daily_cost_cents_limit")
- totalRequestLimit Int? @map("total_request_limit")
- totalTokenLimit BigInt? @map("total_token_limit")
- totalCostCentsLimit Int? @map("total_cost_cents_limit")
- alertPct Int @default(80) @map("alert_pct")
- apiKeys ApiKey[]
- balanceTransactions BalanceTransaction[]
- usageRecords UsageRecord[]
- orders Order[]
- @@map("users")
- }
- // ---- API 密钥 ----
- model ApiKey {
- id String @id @default(cuid())
- userId String @map("user_id")
- name String
- keyHash String @unique @map("key_hash")
- prefix String // 前 12 位用于展示(dt_ + 32 hex = 36 chars)
- expiresAt DateTime? @map("expires_at")
- lastUsedAt DateTime? @map("last_used_at")
- status String @default("active") // active | revoked
- createdAt DateTime @default(now()) @map("created_at")
- updatedAt DateTime @updatedAt @map("updated_at")
- // 用量配额(null = 不限)
- dailyRequestLimit Int? @map("daily_request_limit")
- dailyTokenLimit BigInt? @map("daily_token_limit")
- dailyCostCentsLimit Int? @map("daily_cost_cents_limit")
- totalRequestLimit Int? @map("total_request_limit")
- totalTokenLimit BigInt? @map("total_token_limit")
- totalCostCentsLimit Int? @map("total_cost_cents_limit")
- alertPct Int @default(80) @map("alert_pct")
- user User @relation(fields: [userId], references: [id])
- usageRecords UsageRecord[]
- events ApiKeyEvent[]
- @@map("api_keys")
- }
- // ---- API Key 事件审计日志 ----
- model ApiKeyEvent {
- id String @id @default(cuid())
- apiKeyId String @map("api_key_id")
- userId String @map("user_id")
- action String // created | rotated | revoked | used
- ip String?
- createdAt DateTime @default(now()) @map("created_at")
- apiKey ApiKey @relation(fields: [apiKeyId], references: [id])
- @@map("api_key_events")
- }
- // ---- 模型目录(DB-backed) ----
- model ModelCatalog {
- id String @id @default(cuid())
- publicId String @unique @map("public_id")
- upstreamId String @map("upstream_id")
- name String
- provider String // Zhipu | DeepSeek | Alibaba | MiniMax | Kimi | SiliconFlow | Other
- category String // chat | vision | image | speech
- description String?
- contextWindow Int? @map("context_window")
- maxOutput Int? @map("max_output")
- inputPriceCents Int @default(0) @map("input_price_cents")
- outputPriceCents Int @default(0) @map("output_price_cents")
- isRecommended Boolean @default(false) @map("is_recommended")
- status String @default("active") // active | hidden | disabled
- sortOrder Int @default(0) @map("sort_order")
- createdAt DateTime @default(now()) @map("created_at")
- updatedAt DateTime @updatedAt @map("updated_at")
- @@map("models")
- }
- // ---- 余额变动记录 ----
- model BalanceTransaction {
- id String @id @default(cuid())
- userId String @map("user_id")
- amountCents BigInt @map("amount_cents")
- type String // topup | charge | refund | usage | refund
- refId String? @map("ref_id")
- createdAt DateTime @default(now()) @map("created_at")
- user User @relation(fields: [userId], references: [id])
- @@map("balance_transactions")
- }
- // ---- 用量记录 ----
- model UsageRecord {
- id String @id @default(cuid())
- userId String @map("user_id")
- apiKeyId String @map("api_key_id")
- model String
- promptTokens Int @map("prompt_tokens")
- completionTokens Int @map("completion_tokens")
- costCents Int @map("cost_cents")
- createdAt DateTime @default(now()) @map("created_at")
- user User @relation(fields: [userId], references: [id])
- apiKey ApiKey @relation(fields: [apiKeyId], references: [id])
- @@map("usage_records")
- }
- // ---- 配额事件(预警 + 超限审计) ----
- model QuotaEvent {
- id String @id @default(cuid())
- userId String @map("user_id")
- apiKeyId String? @map("api_key_id")
- dimension String // request | token | cost
- windowType String @map("window_type") // daily | total
- scopeType String @map("scope_type") // account | key
- threshold Int
- current BigInt
- action String // alert | block
- createdAt DateTime @default(now()) @map("created_at")
- @@map("quota_events")
- }
- // ---- 订单 ----
- model Order {
- id String @id @default(cuid())
- userId String @map("user_id")
- provider String // alipay | stripe | ...
- providerOrderId String? @map("provider_order_id")
- amountCents BigInt @map("amount_cents")
- status String @default("pending") // pending | paid | failed | refunded
- currency String @default("USD")
- paidAt DateTime? @map("paid_at")
- createdAt DateTime @default(now()) @map("created_at")
- updatedAt DateTime @updatedAt @map("updated_at")
- user User @relation(fields: [userId], references: [id])
- @@map("orders")
- }
|