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