Files
AIclinicalresearch/backend/prisma/schema.prisma
HaHafeng 3634933ece refactor(asl): ASL frontend architecture refactoring with left navigation
- feat: Create ASLLayout component with 7-module left navigation
- feat: Implement Title Screening Settings page with optimized PICOS layout
- feat: Add placeholder pages for Workbench and Results
- fix: Fix nested routing structure for React Router v6
- fix: Resolve Spin component warning in MainLayout
- fix: Add QueryClientProvider to App.tsx
- style: Optimize PICOS form layout (P+I left, C+O+S right)
- style: Align Inclusion/Exclusion criteria side-by-side
- docs: Add architecture refactoring and routing fix reports

Ref: Week 2 Frontend Development
Scope: ASL module MVP - Title Abstract Screening
2025-11-18 21:51:51 +08:00

569 lines
20 KiB
Plaintext
Raw 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
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
schemas = ["platform_schema", "aia_schema", "pkb_schema", "asl_schema", "common_schema", "dc_schema", "rvw_schema", "admin_schema", "ssa_schema", "st_schema", "public"]
}
// ==================== 用户模块 ====================
model User {
id String @id @default(uuid())
email String @unique
password String
name String?
avatarUrl String? @map("avatar_url")
role String @default("user")
status String @default("active")
kbQuota Int @default(3) @map("kb_quota")
kbUsed Int @default(0) @map("kb_used")
trialEndsAt DateTime? @map("trial_ends_at")
isTrial Boolean @default(true) @map("is_trial")
lastLoginAt DateTime? @map("last_login_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
projects Project[]
conversations Conversation[]
knowledgeBases KnowledgeBase[]
documents Document[]
adminLogs AdminLog[]
generalConversations GeneralConversation[]
batchTasks BatchTask[] // Phase 3: 批处理任务
taskTemplates TaskTemplate[] // Phase 3: 任务模板
reviewTasks ReviewTask[] // 稿件审查任务
aslProjects AslScreeningProject[] @relation("AslProjects") // ASL智能文献项目
@@index([email])
@@index([status])
@@index([createdAt])
@@map("users")
@@schema("platform_schema")
}
// ==================== 项目模块 ====================
model Project {
id String @id @default(uuid())
userId String @map("user_id")
name String
background String @default("") @db.Text
researchType String @default("observational") @map("research_type")
conversationCount Int @default(0) @map("conversation_count")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
conversations Conversation[]
@@index([userId])
@@index([createdAt])
@@index([deletedAt])
@@map("projects")
@@schema("aia_schema")
}
// ==================== 对话模块 ====================
model Conversation {
id String @id @default(uuid())
userId String @map("user_id")
projectId String? @map("project_id")
agentId String @map("agent_id")
title String
modelName String @default("deepseek-v3") @map("model_name")
messageCount Int @default(0) @map("message_count")
totalTokens Int @default(0) @map("total_tokens")
metadata Json?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
messages Message[]
@@index([userId])
@@index([projectId])
@@index([agentId])
@@index([createdAt])
@@index([deletedAt])
@@map("conversations")
@@schema("aia_schema")
}
model Message {
id String @id @default(uuid())
conversationId String @map("conversation_id")
role String
content String @db.Text
model String?
metadata Json?
tokens Int?
isPinned Boolean @default(false) @map("is_pinned")
createdAt DateTime @default(now()) @map("created_at")
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
@@index([conversationId])
@@index([createdAt])
@@index([isPinned])
@@map("messages")
@@schema("aia_schema")
}
// ==================== 知识库模块 ====================
model KnowledgeBase {
id String @id @default(uuid())
userId String @map("user_id")
name String
description String?
difyDatasetId String @map("dify_dataset_id")
fileCount Int @default(0) @map("file_count")
totalSizeBytes BigInt @default(0) @map("total_size_bytes")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
documents Document[]
batchTasks BatchTask[] // Phase 3: 批处理任务
@@index([userId])
@@index([difyDatasetId])
@@map("knowledge_bases")
@@schema("pkb_schema")
}
model Document {
id String @id @default(uuid())
kbId String @map("kb_id")
userId String @map("user_id")
filename String
fileType String @map("file_type")
fileSizeBytes BigInt @map("file_size_bytes")
fileUrl String @map("file_url")
difyDocumentId String @map("dify_document_id")
status String @default("uploading")
progress Int @default(0)
errorMessage String? @map("error_message")
segmentsCount Int? @map("segments_count")
tokensCount Int? @map("tokens_count")
// Phase 2: 全文阅读模式新增字段
extractionMethod String? @map("extraction_method") // pymupdf/nougat/mammoth/direct
extractionQuality Float? @map("extraction_quality") // 0-1质量分数
charCount Int? @map("char_count") // 字符数
language String? // 检测到的语言 (chinese/english)
extractedText String? @map("extracted_text") @db.Text // 提取的文本内容
uploadedAt DateTime @default(now()) @map("uploaded_at")
processedAt DateTime? @map("processed_at")
knowledgeBase KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
batchResults BatchResult[] // Phase 3: 批处理结果
@@index([kbId])
@@index([userId])
@@index([status])
@@index([difyDocumentId])
@@index([extractionMethod])
@@map("documents")
@@schema("pkb_schema")
}
// ==================== Phase 3: 批处理模块 ====================
// 批处理任务
model BatchTask {
id String @id @default(uuid())
userId String @map("user_id")
kbId String @map("kb_id")
// 任务基本信息
name String // 任务名称(用户可自定义)
templateType String @map("template_type") // 'preset' | 'custom'
templateId String? @map("template_id") // 预设模板ID如'clinical_research'
prompt String @db.Text // 提示词(完整的)
// 执行状态
status String // 'processing' | 'completed' | 'failed' | 'paused'
totalDocuments Int @map("total_documents")
completedCount Int @default(0) @map("completed_count")
failedCount Int @default(0) @map("failed_count")
// 配置
modelType String @map("model_type") // 使用的模型
concurrency Int @default(3) // 固定为3
// 时间统计
startedAt DateTime? @map("started_at")
completedAt DateTime? @map("completed_at")
durationSeconds Int? @map("duration_seconds") // 执行时长(秒)
// 关联
results BatchResult[]
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
knowledgeBase KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([userId])
@@index([kbId])
@@index([status])
@@index([createdAt])
@@map("batch_tasks")
@@schema("pkb_schema")
}
// 批处理结果(每篇文献一条)
model BatchResult {
id String @id @default(uuid())
taskId String @map("task_id")
documentId String @map("document_id")
// 执行结果
status String // 'success' | 'failed'
data Json? // 提取的结构化数据(预设模板)或文本(自定义)
rawOutput String? @db.Text @map("raw_output") // AI原始输出备份
errorMessage String? @db.Text @map("error_message") // 错误信息
// 性能指标
processingTimeMs Int? @map("processing_time_ms") // 处理时长(毫秒)
tokensUsed Int? @map("tokens_used") // Token使用量
// 关联
task BatchTask @relation(fields: [taskId], references: [id], onDelete: Cascade)
document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) @map("created_at")
@@index([taskId])
@@index([documentId])
@@index([status])
@@map("batch_results")
@@schema("pkb_schema")
}
// 任务模板(暂不实现,预留)
model TaskTemplate {
id String @id @default(uuid())
userId String @map("user_id")
name String
description String?
prompt String @db.Text
outputFields Json // 期望的输出字段定义
isPublic Boolean @default(false) @map("is_public")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([userId])
@@map("task_templates")
@@schema("pkb_schema")
}
// ==================== 运营管理模块 ====================
model AdminLog {
id Int @id @default(autoincrement())
adminId String @map("admin_id")
action String
resourceType String? @map("resource_type")
resourceId String? @map("resource_id")
details Json?
ipAddress String? @map("ip_address")
userAgent String? @map("user_agent")
createdAt DateTime @default(now()) @map("created_at")
admin User @relation(fields: [adminId], references: [id], onDelete: Cascade)
@@index([adminId])
@@index([createdAt])
@@index([action])
@@map("admin_logs")
@@schema("public")
}
// ==================== 通用对话模块 ====================
model GeneralConversation {
id String @id @default(uuid())
userId String @map("user_id")
title String
modelName String? @map("model_name")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
messages GeneralMessage[]
@@index([userId])
@@index([createdAt])
@@index([updatedAt])
@@map("general_conversations")
@@schema("aia_schema")
}
model GeneralMessage {
id String @id @default(uuid())
conversationId String @map("conversation_id")
role String
content String @db.Text
model String?
metadata Json?
tokens Int?
createdAt DateTime @default(now()) @map("created_at")
conversation GeneralConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
@@index([conversationId])
@@index([createdAt])
@@map("general_messages")
@@schema("aia_schema")
}
// ==================== 稿件审查模块 ====================
// 稿件审查任务
model ReviewTask {
id String @id @default(uuid())
userId String @map("user_id")
// 文件信息
fileName String @map("file_name")
fileSize Int @map("file_size")
filePath String? @map("file_path")
// 文档内容
extractedText String @map("extracted_text") @db.Text
wordCount Int? @map("word_count")
// 执行状态
status String @default("pending")
// pending, extracting, reviewing_editorial, reviewing_methodology, completed, failed
// 评估结果JSON
editorialReview Json? @map("editorial_review")
methodologyReview Json? @map("methodology_review")
overallScore Float? @map("overall_score")
// 执行信息
modelUsed String? @map("model_used")
startedAt DateTime? @map("started_at")
completedAt DateTime? @map("completed_at")
durationSeconds Int? @map("duration_seconds")
errorMessage String? @map("error_message") @db.Text
// 元数据
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
// 关联
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([status])
@@index([createdAt])
@@map("review_tasks")
@@schema("public")
}
// ==================== ASL智能文献模块 ====================
// ASL 筛选项目表
model AslScreeningProject {
id String @id @default(uuid())
userId String @map("user_id")
user User @relation("AslProjects", fields: [userId], references: [id], onDelete: Cascade)
projectName String @map("project_name")
// PICO标准
picoCriteria Json @map("pico_criteria") // { population, intervention, comparison, outcome, studyDesign }
// 筛选标准
inclusionCriteria String @map("inclusion_criteria") @db.Text
exclusionCriteria String @map("exclusion_criteria") @db.Text
// 状态
status String @default("draft") // draft, screening, completed
// 筛选配置
screeningConfig Json? @map("screening_config") // { models: ["deepseek", "qwen"], temperature: 0 }
// 关联
literatures AslLiterature[]
screeningTasks AslScreeningTask[]
screeningResults AslScreeningResult[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("screening_projects")
@@schema("asl_schema")
@@index([userId])
@@index([status])
}
// ASL 文献条目表
model AslLiterature {
id String @id @default(uuid())
projectId String @map("project_id")
project AslScreeningProject @relation(fields: [projectId], references: [id], onDelete: Cascade)
// 文献基本信息
pmid String?
title String @db.Text
abstract String @db.Text
authors String?
journal String?
publicationYear Int? @map("publication_year")
doi String?
// 云原生存储字段V1.0 阶段使用MVP阶段预留
pdfUrl String? @map("pdf_url") // PDF访问URL
pdfOssKey String? @map("pdf_oss_key") // OSS存储Key用于删除
pdfFileSize Int? @map("pdf_file_size") // 文件大小(字节)
// 关联
screeningResults AslScreeningResult[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("literatures")
@@schema("asl_schema")
@@index([projectId])
@@index([doi])
@@unique([projectId, pmid])
}
// ASL 筛选结果表
model AslScreeningResult {
id String @id @default(uuid())
projectId String @map("project_id")
project AslScreeningProject @relation(fields: [projectId], references: [id], onDelete: Cascade)
literatureId String @map("literature_id")
literature AslLiterature @relation(fields: [literatureId], references: [id], onDelete: Cascade)
// DeepSeek模型判断
dsModelName String @map("ds_model_name") // "deepseek-chat"
dsPJudgment String? @map("ds_p_judgment") // "match" | "partial" | "mismatch"
dsIJudgment String? @map("ds_i_judgment")
dsCJudgment String? @map("ds_c_judgment")
dsSJudgment String? @map("ds_s_judgment")
dsConclusion String? @map("ds_conclusion") // "include" | "exclude" | "uncertain"
dsConfidence Float? @map("ds_confidence") // 0-1
// DeepSeek模型证据
dsPEvidence String? @map("ds_p_evidence") @db.Text
dsIEvidence String? @map("ds_i_evidence") @db.Text
dsCEvidence String? @map("ds_c_evidence") @db.Text
dsSEvidence String? @map("ds_s_evidence") @db.Text
dsReason String? @map("ds_reason") @db.Text
// Qwen模型判断
qwenModelName String @map("qwen_model_name") // "qwen-max"
qwenPJudgment String? @map("qwen_p_judgment")
qwenIJudgment String? @map("qwen_i_judgment")
qwenCJudgment String? @map("qwen_c_judgment")
qwenSJudgment String? @map("qwen_s_judgment")
qwenConclusion String? @map("qwen_conclusion")
qwenConfidence Float? @map("qwen_confidence")
// Qwen模型证据
qwenPEvidence String? @map("qwen_p_evidence") @db.Text
qwenIEvidence String? @map("qwen_i_evidence") @db.Text
qwenCEvidence String? @map("qwen_c_evidence") @db.Text
qwenSEvidence String? @map("qwen_s_evidence") @db.Text
qwenReason String? @map("qwen_reason") @db.Text
// 冲突状态
conflictStatus String @default("none") @map("conflict_status") // "none" | "conflict" | "resolved"
conflictFields Json? @map("conflict_fields") // ["P", "I", "conclusion"]
// 最终决策
finalDecision String? @map("final_decision") // "include" | "exclude" | "pending"
finalDecisionBy String? @map("final_decision_by") // userId
finalDecisionAt DateTime? @map("final_decision_at")
exclusionReason String? @map("exclusion_reason") @db.Text
// AI处理状态
aiProcessingStatus String @default("pending") @map("ai_processing_status") // "pending" | "processing" | "completed" | "failed"
aiProcessedAt DateTime? @map("ai_processed_at")
aiErrorMessage String? @map("ai_error_message") @db.Text
// 可追溯信息
promptVersion String @default("v1.0.0") @map("prompt_version")
rawOutput Json? @map("raw_output") // 原始LLM输出备份
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("screening_results")
@@schema("asl_schema")
@@index([projectId])
@@index([literatureId])
@@index([conflictStatus])
@@index([finalDecision])
@@unique([projectId, literatureId])
}
// ASL 筛选任务表
model AslScreeningTask {
id String @id @default(uuid())
projectId String @map("project_id")
project AslScreeningProject @relation(fields: [projectId], references: [id], onDelete: Cascade)
taskType String @map("task_type") // "title_abstract" | "full_text"
status String @default("pending") // "pending" | "running" | "completed" | "failed"
// 进度统计
totalItems Int @map("total_items")
processedItems Int @default(0) @map("processed_items")
successItems Int @default(0) @map("success_items")
failedItems Int @default(0) @map("failed_items")
conflictItems Int @default(0) @map("conflict_items")
// 时间信息
startedAt DateTime? @map("started_at")
completedAt DateTime? @map("completed_at")
estimatedEndAt DateTime? @map("estimated_end_at")
// 错误信息
errorMessage String? @map("error_message") @db.Text
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("screening_tasks")
@@schema("asl_schema")
@@index([projectId])
@@index([status])
}