// Prisma Schema for Paper Burner X // 支持多租户系统、历史记录持久化、模型配置管理 generator client { provider = "prisma-client-js" binaryTargets = ["native", "linux-musl-openssl-3.0.x"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ==================== 用户与认证 ==================== model User { id String @id @default(uuid()) email String @unique password String // bcrypt 加密 name String? role Role @default(USER) isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // 关联 settings UserSettings? documents Document[] apiKeys ApiKey[] glossaries Glossary[] annotations Annotation[] processedFiles ProcessedFile[] quota UserQuota? chatMessages ChatMessage[] references Reference[] promptPool PromptPool? @@index([email]) @@map("users") } enum Role { USER ADMIN } // ==================== 用户设置 ==================== model UserSettings { id String @id @default(uuid()) userId String @unique user User @relation(fields: [userId], references: [id], onDelete: Cascade) // OCR 设置 ocrProvider String? // 'mineru' | 'doc2x' ocrApiKey String? @db.Text // 翻译设置 translationModel String? // 'deepseek' | 'gemini' | 'claude' | 'custom' targetLanguage String @default("chinese") customTargetLanguageName String? maxTokensPerChunk Int @default(2000) translationConcurrency Int @default(15) // 提示词设置 defaultSystemPrompt String? @db.Text defaultUserPromptTemplate String? @db.Text useCustomPrompts Boolean @default(false) // 其他设置 enableGlossary Boolean @default(false) batchModeEnabled Boolean @default(false) batchModeTemplate String? batchModeFormats String[] // ['original', 'markdown', 'pdf'] batchModeZipEnabled Boolean @default(false) // 扩展配置(JSON 字段) ocrConfig Json? // OCR 引擎和详细配置 academicSearchConfig Json? // 学术搜索配置 uiLayoutConfig Json? // UI 布局配置 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("user_settings") } // ==================== API Keys 管理 ==================== model ApiKey { id String @id @default(uuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) provider String // 'mistral' | 'deepseek' | 'gemini' | 'claude' | 'tongyi' | 'volcano' | 'custom_source_xxx' keyValue String @db.Text // 加密存储 remark String? status KeyStatus @default(UNTESTED) order Int @default(0) lastUsedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([userId, provider]) @@map("api_keys") } enum KeyStatus { UNTESTED VALID INVALID TESTING } // ==================== 自定义模型源站配置 ==================== model CustomSourceSite { id String @id @default(uuid()) userId String? // null = 管理员全局配置 displayName String apiBaseUrl String modelId String? availableModels String[] // JSON array requestFormat String @default("openai") // 'openai' | 'anthropic' | 'custom' temperature Float @default(0.5) maxTokens Int @default(8000) endpointMode String @default("auto") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([userId]) @@map("custom_source_sites") } // ==================== 文档处理历史 ==================== model Document { id String @id @default(uuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) // 基本信息 fileName String fileSize Int? fileType String filePath String? // 如果启用文件上传存储 // 处理状态 status DocStatus @default(PENDING) // OCR 结果 ocrProvider String? ocrText String? @db.Text ocrMetadata Json? // 翻译结果 translationModel String? translatedText String? @db.Text translationMetadata Json? // 其他数据 summary String? @db.Text toc Json? // Table of Contents metadata Json? // 其他元数据 processingTime Int? // 处理时间(毫秒) errorMessage String? @db.Text createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // 关联 annotations Annotation[] semanticGroups SemanticGroup[] chatMessages ChatMessage[] references Reference[] @@index([userId, createdAt]) @@index([status]) @@map("documents") } enum DocStatus { PENDING PROCESSING OCR_COMPLETED TRANSLATION_COMPLETED COMPLETED FAILED } // ==================== 高亮与标注 ==================== model Annotation { id String @id @default(uuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) documentId String document Document @relation(fields: [documentId], references: [id], onDelete: Cascade) type String // 'highlight' | 'note' color String? startIndex Int endIndex Int text String @db.Text note String? @db.Text createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([documentId]) @@index([userId]) @@map("annotations") } // ==================== 意群数据 ==================== model SemanticGroup { id String @id @default(uuid()) documentId String document Document @relation(fields: [documentId], references: [id], onDelete: Cascade) groups Json // 存储意群数组 version String? source String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([documentId]) @@map("semantic_groups") } // ==================== 翻译术语库 ==================== model Glossary { id String @id @default(uuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) name String enabled Boolean @default(true) entries Json // 存储术语条目数组 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([userId]) @@map("glossaries") } // ==================== 系统配置(管理员)==================== model SystemConfig { id String @id @default(uuid()) key String @unique value String @db.Text description String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("system_config") } // ==================== 已处理文件记录 ==================== model ProcessedFile { id String @id @default(uuid()) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) fileIdentifier String // 文件标识符 (name + size + lastModified) fileName String processedAt DateTime @default(now()) @@unique([userId, fileIdentifier]) @@index([userId]) @@map("processed_files") } // ==================== 用户配额管理 ==================== model UserQuota { id String @id @default(uuid()) userId String @unique user User @relation(fields: [userId], references: [id], onDelete: Cascade) // 配额限制 (-1 表示无限制) maxDocumentsPerDay Int @default(-1) maxDocumentsPerMonth Int @default(-1) maxStorageSize Int @default(-1) // MB maxApiKeysCount Int @default(-1) // 当前使用量 documentsThisMonth Int @default(0) currentStorageUsed Int @default(0) // MB // 重置时间 lastMonthlyReset DateTime @default(now()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("user_quotas") } // ==================== 使用量日志 ==================== model UsageLog { id String @id @default(uuid()) userId String action String // 'ocr', 'translate', 'document_create', etc. resourceId String? // 关联的资源ID(如文档ID) metadata Json? // 额外元数据 createdAt DateTime @default(now()) @@index([userId, createdAt]) @@index([action, createdAt]) @@map("usage_logs") } // ==================== 聊天消息 ==================== model ChatMessage { id String @id @default(uuid()) documentId String document Document @relation(fields: [documentId], references: [id], onDelete: Cascade) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) role String // 'user' | 'assistant' content String @db.Text timestamp DateTime @default(now()) metadata Json? // 扩展信息(模型、token 等) @@index([documentId, timestamp]) @@map("chat_messages") } // ==================== 文献引用 ==================== model Reference { id String @id @default(uuid()) documentId String document Document @relation(fields: [documentId], references: [id], onDelete: Cascade) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) citationKey String // 引用标识符(如 "[1]") doi String? title String? authors Json? // [{name, affiliation}] year Int? journal String? volume String? pages String? url String? metadata Json? // 完整元数据 createdAt DateTime @default(now()) @@unique([documentId, citationKey]) @@index([documentId]) @@map("references") } // ==================== 提示词池 ==================== model PromptPool { id String @id @default(uuid()) userId String @unique user User @relation(fields: [userId], references: [id], onDelete: Cascade) prompts Json // 提示词数组 healthConfig Json? // 健康检查配置 updatedAt DateTime @default(now()) @updatedAt @@map("prompt_pool") }