generator client { provider = "prisma-client-js" previewFeatures = ["multiSchema"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") schemas = ["admin_schema", "aia_schema", "asl_schema", "capability_schema", "common_schema", "dc_schema", "iit_schema", "pkb_schema", "platform_schema", "public", "rvw_schema", "ssa_schema", "st_schema"] } /// 应用缓存表 - Postgres-Only架构 /// 用于替代Redis缓存,支持LLM结果缓存、健康检查缓存等 model AppCache { id Int @id @default(autoincrement()) key String @unique @db.VarChar(500) value Json expiresAt DateTime @map("expires_at") @db.Timestamp(6) createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(6) @@index([expiresAt], map: "idx_app_cache_expires") @@index([key, expiresAt], map: "idx_app_cache_key_expires") @@map("app_cache") @@schema("platform_schema") } model User { id String @id @default(uuid()) phone String @unique password String email String? @unique is_default_password Boolean @default(true) password_changed_at DateTime? name String tenant_id String department_id String? avatarUrl String? @map("avatar_url") role UserRole @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") tenant_members tenant_members[] user_modules user_modules[] departments departments? @relation(fields: [department_id], references: [id]) tenants tenants @relation(fields: [tenant_id], references: [id]) @@index([createdAt], map: "idx_platform_users_created_at") @@index([email], map: "idx_platform_users_email") @@index([status], map: "idx_platform_users_status") @@index([phone], map: "idx_platform_users_phone") @@index([tenant_id], map: "idx_platform_users_tenant_id") @@map("users") @@schema("platform_schema") } model Project { id String @id @default(uuid()) userId String @map("user_id") name String background String @default("") 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") conversations Conversation[] @relation("ProjectConversations") @@index([createdAt], map: "idx_aia_projects_created_at") @@index([deletedAt], map: "idx_aia_projects_deleted_at") @@index([userId], map: "idx_aia_projects_user_id") @@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") project Project? @relation("ProjectConversations", fields: [projectId], references: [id]) messages Message[] @relation("ConversationMessages") @@index([agentId], map: "idx_aia_conversations_agent_id") @@index([createdAt], map: "idx_aia_conversations_created_at") @@index([deletedAt], map: "idx_aia_conversations_deleted_at") @@index([projectId], map: "idx_aia_conversations_project_id") @@index([userId], map: "idx_aia_conversations_user_id") @@map("conversations") @@schema("aia_schema") } model Message { id String @id @default(uuid()) conversationId String @map("conversation_id") role String content String model String? metadata Json? tokens Int? isPinned Boolean @default(false) @map("is_pinned") createdAt DateTime @default(now()) @map("created_at") // V2.1 新增字段 thinkingContent String? @map("thinking_content") @db.Text // 深度思考内容 ... attachments Json? @db.JsonB // 附件数组(上限5个,单个≤20MB,提取文本≤30K tokens) conversation Conversation @relation("ConversationMessages", fields: [conversationId], references: [id], onDelete: Cascade) @@index([conversationId], map: "idx_aia_messages_conversation_id") @@index([createdAt], map: "idx_aia_messages_created_at") @@index([isPinned], map: "idx_aia_messages_is_pinned") @@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") batchTasks BatchTask[] @relation("KnowledgeBaseBatchTasks") documents Document[] @relation("KnowledgeBaseDocuments") @@index([difyDatasetId], map: "idx_pkb_knowledge_bases_dify_dataset_id") @@index([userId], map: "idx_pkb_knowledge_bases_user_id") @@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") extractionMethod String? @map("extraction_method") extractionQuality Float? @map("extraction_quality") charCount Int? @map("char_count") language String? extractedText String? @map("extracted_text") uploadedAt DateTime @default(now()) @map("uploaded_at") processedAt DateTime? @map("processed_at") batchResults BatchResult[] @relation("DocumentBatchResults") knowledgeBase KnowledgeBase @relation("KnowledgeBaseDocuments", fields: [kbId], references: [id], onDelete: Cascade) @@index([difyDocumentId], map: "idx_pkb_documents_dify_document_id") @@index([extractionMethod], map: "idx_pkb_documents_extraction_method") @@index([kbId], map: "idx_pkb_documents_kb_id") @@index([status], map: "idx_pkb_documents_status") @@index([userId], map: "idx_pkb_documents_user_id") @@map("documents") @@schema("pkb_schema") } model BatchTask { id String @id @default(uuid()) userId String @map("user_id") kbId String @map("kb_id") name String templateType String @map("template_type") templateId String? @map("template_id") prompt String status String 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) startedAt DateTime? @map("started_at") completedAt DateTime? @map("completed_at") durationSeconds Int? @map("duration_seconds") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") results BatchResult[] @relation("TaskBatchResults") knowledgeBase KnowledgeBase @relation("KnowledgeBaseBatchTasks", fields: [kbId], references: [id], onDelete: Cascade) @@index([createdAt], map: "idx_pkb_batch_tasks_created_at") @@index([kbId], map: "idx_pkb_batch_tasks_kb_id") @@index([status], map: "idx_pkb_batch_tasks_status") @@index([userId], map: "idx_pkb_batch_tasks_user_id") @@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 data Json? rawOutput String? @map("raw_output") errorMessage String? @map("error_message") processingTimeMs Int? @map("processing_time_ms") tokensUsed Int? @map("tokens_used") createdAt DateTime @default(now()) @map("created_at") document Document @relation("DocumentBatchResults", fields: [documentId], references: [id], onDelete: Cascade) task BatchTask @relation("TaskBatchResults", fields: [taskId], references: [id], onDelete: Cascade) @@index([documentId], map: "idx_pkb_batch_results_document_id") @@index([status], map: "idx_pkb_batch_results_status") @@index([taskId], map: "idx_pkb_batch_results_task_id") @@map("batch_results") @@schema("pkb_schema") } model TaskTemplate { id String @id @default(uuid()) userId String @map("user_id") name String description String? prompt String isPublic Boolean @default(false) @map("is_public") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") outputFields Json @@index([userId], map: "idx_pkb_task_templates_user_id") @@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 users @relation(fields: [adminId], references: [id], onDelete: Cascade) @@index([adminId]) @@index([createdAt]) @@index([action]) @@map("admin_logs") @@schema("public") } // GeneralConversation 和 GeneralMessage 已删除(2026-01-11) // 原因:与 Conversation/Message 功能重叠,使用 conversations.project_id = NULL 表示无项目对话 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") wordCount Int? @map("word_count") status String @default("pending") selectedAgents String[] @default(["editorial", "methodology"]) @map("selected_agents") editorialReview Json? @map("editorial_review") methodologyReview Json? @map("methodology_review") overallScore Float? @map("overall_score") editorialScore Float? @map("editorial_score") methodologyScore Float? @map("methodology_score") methodologyStatus String? @map("methodology_status") picoExtract Json? @map("pico_extract") isArchived Boolean @default(false) @map("is_archived") archivedAt DateTime? @map("archived_at") 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") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // 注意:userId 暂不添加外键约束,因为用户来自不同 schema (platform_schema.users) // 跨 schema 外键在 PostgreSQL 中需要特殊处理 @@index([userId]) @@index([status]) @@index([createdAt]) @@index([isArchived]) @@map("review_tasks") @@schema("rvw_schema") } model AslScreeningProject { id String @id @default(uuid()) userId String @map("user_id") projectName String @map("project_name") picoCriteria Json @map("pico_criteria") inclusionCriteria String @map("inclusion_criteria") exclusionCriteria String @map("exclusion_criteria") status String @default("draft") screeningConfig Json? @map("screening_config") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") fulltextResults AslFulltextScreeningResult[] @relation("ProjectFulltextResults") fulltextTasks AslFulltextScreeningTask[] @relation("ProjectFulltextTasks") literatures AslLiterature[] @relation("ProjectLiteratures") screeningResults AslScreeningResult[] @relation("ProjectScreeningResults") screeningTasks AslScreeningTask[] @relation("ProjectScreeningTasks") @@index([status], map: "idx_screening_projects_status") @@index([userId], map: "idx_screening_projects_user_id") @@map("screening_projects") @@schema("asl_schema") } model AslLiterature { id String @id @default(uuid()) projectId String @map("project_id") pmid String? title String abstract String authors String? journal String? publicationYear Int? @map("publication_year") doi String? pdfUrl String? @map("pdf_url") pdfOssKey String? @map("pdf_oss_key") pdfFileSize Int? @map("pdf_file_size") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") stage String @default("imported") @map("stage") hasPdf Boolean @default(false) @map("has_pdf") pdfStorageType String? @map("pdf_storage_type") pdfStorageRef String? @map("pdf_storage_ref") pdfStatus String? @map("pdf_status") pdfUploadedAt DateTime? @map("pdf_uploaded_at") fullTextStorageType String? @map("full_text_storage_type") fullTextStorageRef String? @map("full_text_storage_ref") fullTextUrl String? @map("full_text_url") fullTextFormat String? @map("full_text_format") fullTextSource String? @map("full_text_source") fullTextTokenCount Int? @map("full_text_token_count") fullTextExtractedAt DateTime? @map("full_text_extracted_at") fulltextResults AslFulltextScreeningResult[] @relation("LiteratureFulltextResults") project AslScreeningProject @relation("ProjectLiteratures", fields: [projectId], references: [id], onDelete: Cascade) screeningResults AslScreeningResult[] @relation("LiteratureScreeningResults") @@unique([projectId, pmid], map: "unique_project_pmid") @@index([doi], map: "idx_literatures_doi") @@index([hasPdf], map: "idx_literatures_has_pdf") @@index([pdfStatus], map: "idx_literatures_pdf_status") @@index([projectId], map: "idx_literatures_project_id") @@index([stage], map: "idx_literatures_stage") @@map("literatures") @@schema("asl_schema") } model AslScreeningResult { id String @id @default(uuid()) projectId String @map("project_id") literatureId String @map("literature_id") dsModelName String @map("ds_model_name") dsPJudgment String? @map("ds_p_judgment") dsIJudgment String? @map("ds_i_judgment") dsCJudgment String? @map("ds_c_judgment") dsSJudgment String? @map("ds_s_judgment") dsConclusion String? @map("ds_conclusion") dsConfidence Float? @map("ds_confidence") dsPEvidence String? @map("ds_p_evidence") dsIEvidence String? @map("ds_i_evidence") dsCEvidence String? @map("ds_c_evidence") dsSEvidence String? @map("ds_s_evidence") dsReason String? @map("ds_reason") qwenModelName String @map("qwen_model_name") 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") qwenPEvidence String? @map("qwen_p_evidence") qwenIEvidence String? @map("qwen_i_evidence") qwenCEvidence String? @map("qwen_c_evidence") qwenSEvidence String? @map("qwen_s_evidence") qwenReason String? @map("qwen_reason") conflictStatus String @default("none") @map("conflict_status") conflictFields Json? @map("conflict_fields") finalDecision String? @map("final_decision") finalDecisionBy String? @map("final_decision_by") finalDecisionAt DateTime? @map("final_decision_at") exclusionReason String? @map("exclusion_reason") aiProcessingStatus String @default("pending") @map("ai_processing_status") aiProcessedAt DateTime? @map("ai_processed_at") aiErrorMessage String? @map("ai_error_message") promptVersion String @default("v1.0.0") @map("prompt_version") rawOutput Json? @map("raw_output") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") literature AslLiterature @relation("LiteratureScreeningResults", fields: [literatureId], references: [id], onDelete: Cascade) project AslScreeningProject @relation("ProjectScreeningResults", fields: [projectId], references: [id], onDelete: Cascade) @@unique([projectId, literatureId], map: "unique_project_literature") @@index([conflictStatus], map: "idx_screening_results_conflict_status") @@index([finalDecision], map: "idx_screening_results_final_decision") @@index([literatureId], map: "idx_screening_results_literature_id") @@index([projectId], map: "idx_screening_results_project_id") @@map("screening_results") @@schema("asl_schema") } model AslScreeningTask { id String @id @default(uuid()) projectId String @map("project_id") taskType String @map("task_type") status String @default("pending") 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") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") project AslScreeningProject @relation("ProjectScreeningTasks", fields: [projectId], references: [id], onDelete: Cascade) @@index([projectId], map: "idx_screening_tasks_project_id") @@index([status], map: "idx_screening_tasks_status") @@map("screening_tasks") @@schema("asl_schema") } model AslFulltextScreeningTask { id String @id @default(uuid()) projectId String @map("project_id") modelA String @map("model_a") modelB String @map("model_b") promptVersion String @default("v1.0.0") @map("prompt_version") status String @default("pending") totalCount Int @map("total_count") processedCount Int @default(0) @map("processed_count") successCount Int @default(0) @map("success_count") failedCount Int @default(0) @map("failed_count") degradedCount Int @default(0) @map("degraded_count") totalTokens Int @default(0) @map("total_tokens") totalCost Float @default(0) @map("total_cost") startedAt DateTime? @map("started_at") completedAt DateTime? @map("completed_at") estimatedEndAt DateTime? @map("estimated_end_at") errorMessage String? @map("error_message") errorStack String? @map("error_stack") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") results AslFulltextScreeningResult[] @relation("TaskFulltextResults") project AslScreeningProject @relation("ProjectFulltextTasks", fields: [projectId], references: [id], onDelete: Cascade) @@index([createdAt], map: "idx_fulltext_tasks_created_at") @@index([projectId], map: "idx_fulltext_tasks_project_id") @@index([status], map: "idx_fulltext_tasks_status") @@map("fulltext_screening_tasks") @@schema("asl_schema") } /// 智能文献检索任务(DeepSearch) model AslResearchTask { id String @id @default(uuid()) // 关联 projectId String @map("project_id") userId String @map("user_id") // 检索输入 query String // 用户的自然语言查询 filters Json? // 🔜 后续:高级筛选 { yearFrom, yearTo, articleTypes } // unifuncs 任务 externalTaskId String? @map("external_task_id") // 状态 status String @default("pending") // pending/processing/completed/failed errorMessage String? @map("error_message") // 结果 resultCount Int? @map("result_count") rawResult String? @map("raw_result") @db.Text reasoningContent String? @map("reasoning_content") @db.Text // AI思考过程 literatures Json? // 解析后的文献列表 // 统计(🔜 后续展示) tokenUsage Json? @map("token_usage") searchCount Int? @map("search_count") readCount Int? @map("read_count") iterations Int? // 时间 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") completedAt DateTime? @map("completed_at") @@index([projectId], map: "idx_research_tasks_project_id") @@index([userId], map: "idx_research_tasks_user_id") @@index([status], map: "idx_research_tasks_status") @@index([createdAt], map: "idx_research_tasks_created_at") @@map("research_tasks") @@schema("asl_schema") } model AslFulltextScreeningResult { id String @id @default(uuid()) taskId String @map("task_id") projectId String @map("project_id") literatureId String @map("literature_id") modelAName String @map("model_a_name") modelAStatus String @map("model_a_status") modelAFields Json @map("model_a_fields") modelAOverall Json @map("model_a_overall") modelAProcessingLog Json? @map("model_a_processing_log") modelAVerification Json? @map("model_a_verification") modelATokens Int? @map("model_a_tokens") modelACost Float? @map("model_a_cost") modelAError String? @map("model_a_error") modelBName String @map("model_b_name") modelBStatus String @map("model_b_status") modelBFields Json @map("model_b_fields") modelBOverall Json @map("model_b_overall") modelBProcessingLog Json? @map("model_b_processing_log") modelBVerification Json? @map("model_b_verification") modelBTokens Int? @map("model_b_tokens") modelBCost Float? @map("model_b_cost") modelBError String? @map("model_b_error") medicalLogicIssues Json? @map("medical_logic_issues") evidenceChainIssues Json? @map("evidence_chain_issues") isConflict Boolean @default(false) @map("is_conflict") conflictSeverity String? @map("conflict_severity") conflictFields String[] @map("conflict_fields") conflictDetails Json? @map("conflict_details") reviewPriority Int? @map("review_priority") reviewDeadline DateTime? @map("review_deadline") finalDecision String? @map("final_decision") finalDecisionBy String? @map("final_decision_by") finalDecisionAt DateTime? @map("final_decision_at") exclusionReason String? @map("exclusion_reason") reviewNotes String? @map("review_notes") processingStatus String @default("pending") @map("processing_status") isDegraded Boolean @default(false) @map("is_degraded") degradedModel String? @map("degraded_model") processedAt DateTime? @map("processed_at") promptVersion String @default("v1.0.0") @map("prompt_version") rawOutputA Json? @map("raw_output_a") rawOutputB Json? @map("raw_output_b") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") literature AslLiterature @relation("LiteratureFulltextResults", fields: [literatureId], references: [id], onDelete: Cascade) project AslScreeningProject @relation("ProjectFulltextResults", fields: [projectId], references: [id], onDelete: Cascade) task AslFulltextScreeningTask @relation("TaskFulltextResults", fields: [taskId], references: [id], onDelete: Cascade) @@unique([projectId, literatureId], map: "unique_project_literature_fulltext") @@index([finalDecision], map: "idx_fulltext_results_final_decision") @@index([isConflict], map: "idx_fulltext_results_is_conflict") @@index([literatureId], map: "idx_fulltext_results_literature_id") @@index([projectId], map: "idx_fulltext_results_project_id") @@index([reviewPriority], map: "idx_fulltext_results_review_priority") @@index([taskId], map: "idx_fulltext_results_task_id") @@map("fulltext_screening_results") @@schema("asl_schema") } model DCHealthCheck { id String @id @default(uuid()) userId String @map("user_id") fileName String @map("file_name") columnName String @map("column_name") emptyRate Float @map("empty_rate") avgLength Float @map("avg_length") totalRows Int @map("total_rows") estimatedTokens Int @map("estimated_tokens") status String @map("status") message String @map("message") createdAt DateTime @default(now()) @map("created_at") @@index([userId, fileName]) @@map("dc_health_checks") @@schema("dc_schema") } model DCTemplate { id String @id @default(uuid()) diseaseType String @map("disease_type") reportType String @map("report_type") displayName String @map("display_name") fields Json @map("fields") promptTemplate String @map("prompt_template") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@unique([diseaseType, reportType]) @@map("dc_templates") @@schema("dc_schema") } model DCExtractionTask { id String @id @default(uuid()) userId String @map("user_id") projectName String @map("project_name") sourceFileKey String @map("source_file_key") textColumn String @map("text_column") diseaseType String @map("disease_type") reportType String @map("report_type") targetFields Json @map("target_fields") modelA String @default("deepseek-v3") @map("model_a") modelB String @default("qwen-max") @map("model_b") status String @default("pending") @map("status") totalCount Int @default(0) @map("total_count") processedCount Int @default(0) @map("processed_count") cleanCount Int @default(0) @map("clean_count") conflictCount Int @default(0) @map("conflict_count") failedCount Int @default(0) @map("failed_count") totalTokens Int @default(0) @map("total_tokens") totalCost Float @default(0) @map("total_cost") error String? @map("error") createdAt DateTime @default(now()) @map("created_at") startedAt DateTime? @map("started_at") completedAt DateTime? @map("completed_at") items DCExtractionItem[] @@index([userId, status]) @@map("dc_extraction_tasks") @@schema("dc_schema") } model DCExtractionItem { id String @id @default(uuid()) taskId String @map("task_id") rowIndex Int @map("row_index") originalText String @map("original_text") resultA Json? @map("result_a") resultB Json? @map("result_b") status String @default("pending") @map("status") conflictFields String[] @default([]) @map("conflict_fields") finalResult Json? @map("final_result") tokensA Int @default(0) @map("tokens_a") tokensB Int @default(0) @map("tokens_b") error String? @map("error") createdAt DateTime @default(now()) @map("created_at") resolvedAt DateTime? @map("resolved_at") task DCExtractionTask @relation(fields: [taskId], references: [id], onDelete: Cascade) @@index([taskId, status]) @@map("dc_extraction_items") @@schema("dc_schema") } model DcToolCSession { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid userId String @map("user_id") @db.VarChar(255) fileName String @map("file_name") @db.VarChar(500) fileKey String @map("file_key") @db.VarChar(500) totalRows Int? @map("total_rows") totalCols Int? @map("total_cols") columns Json? @map("columns") encoding String? @map("encoding") @db.VarChar(50) fileSize Int @map("file_size") createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6) updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamp(6) expiresAt DateTime @map("expires_at") @db.Timestamp(6) dataStats Json? @map("data_stats") columnMapping Json? @map("column_mapping") cleanDataKey String? @map("clean_data_key") @db.VarChar(1000) @@index([expiresAt], map: "idx_dc_tool_c_sessions_expires_at") @@index([userId], map: "idx_dc_tool_c_sessions_user_id") @@map("dc_tool_c_sessions") @@schema("dc_schema") } model DcToolCAiHistory { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid sessionId String @map("session_id") @db.VarChar(255) userId String @map("user_id") @db.VarChar(255) role String @map("role") @db.VarChar(50) content String generatedCode String? @map("generated_code") codeExplanation String? @map("code_explanation") executeStatus String? @map("execute_status") @db.VarChar(50) executeResult Json? @map("execute_result") executeError String? @map("execute_error") retryCount Int? @default(0) @map("retry_count") model String? @map("model") @db.VarChar(100) createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6) @@index([createdAt], map: "idx_dc_tool_c_ai_history_created_at") @@index([sessionId], map: "idx_dc_tool_c_ai_history_session_id") @@index([userId], map: "idx_dc_tool_c_ai_history_user_id") @@map("dc_tool_c_ai_history") @@schema("dc_schema") } /// This table is a partition table and requires additional setup for migrations. Visit https://pris.ly/d/partition-tables for more info. model job { id String @default(dbgenerated("gen_random_uuid()")) @db.Uuid name String priority Int @default(0) data Json? state job_state @default(created) retry_limit Int @default(2) retry_count Int @default(0) retry_delay Int @default(0) retry_backoff Boolean @default(false) retry_delay_max Int? expire_seconds Int @default(900) deletion_seconds Int @default(604800) singleton_key String? singleton_on DateTime? @db.Timestamp(6) start_after DateTime @default(now()) @db.Timestamptz(6) created_on DateTime @default(now()) @db.Timestamptz(6) started_on DateTime? @db.Timestamptz(6) completed_on DateTime? @db.Timestamptz(6) keep_until DateTime @default(dbgenerated("(now() + '336:00:00'::interval)")) @db.Timestamptz(6) output Json? dead_letter String? policy String? @@id([name, id]) @@schema("platform_schema") } /// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info. model queue { name String @id policy String retry_limit Int retry_delay Int retry_backoff Boolean retry_delay_max Int? expire_seconds Int retention_seconds Int deletion_seconds Int dead_letter String? partition Boolean table_name String deferred_count Int @default(0) queued_count Int @default(0) warning_queued Int @default(0) active_count Int @default(0) total_count Int @default(0) singletons_active String[] monitor_on DateTime? @db.Timestamptz(6) maintain_on DateTime? @db.Timestamptz(6) created_on DateTime @default(now()) @db.Timestamptz(6) updated_on DateTime @default(now()) @db.Timestamptz(6) queue queue? @relation("queueToqueue", fields: [dead_letter], references: [name], onDelete: NoAction, onUpdate: NoAction) other_queue queue[] @relation("queueToqueue") schedule schedule[] subscription subscription[] @@schema("platform_schema") } model schedule { name String key String @default("") cron String timezone String? data Json? options Json? created_on DateTime @default(now()) @db.Timestamptz(6) updated_on DateTime @default(now()) @db.Timestamptz(6) queue queue @relation(fields: [name], references: [name], onDelete: Cascade, onUpdate: NoAction) @@id([name, key]) @@schema("platform_schema") } model subscription { event String name String created_on DateTime @default(now()) @db.Timestamptz(6) updated_on DateTime @default(now()) @db.Timestamptz(6) queue queue @relation(fields: [name], references: [name], onDelete: Cascade, onUpdate: NoAction) @@id([event, name]) @@schema("platform_schema") } model version { version Int @id cron_on DateTime? @db.Timestamptz(6) @@schema("platform_schema") } model users { id String @id email String @unique password String name String? avatar_url String? role String @default("user") status String @default("active") kb_quota Int @default(3) kb_used Int @default(0) trial_ends_at DateTime? is_trial Boolean @default(true) last_login_at DateTime? created_at DateTime @default(now()) updated_at DateTime adminLogs AdminLog[] // reviewTasks 已移除,因为 ReviewTask.userId 现在不再引用此表 @@index([created_at]) @@index([email]) @@index([status]) @@schema("public") } /// IIT项目表 model IitProject { id String @id @default(uuid()) name String description String? difyDatasetId String? @unique @map("dify_dataset_id") protocolFileKey String? @map("protocol_file_key") cachedRules Json? @map("cached_rules") fieldMappings Json @map("field_mappings") redcapProjectId String @map("redcap_project_id") redcapApiToken String @map("redcap_api_token") redcapUrl String @map("redcap_url") lastSyncAt DateTime? @map("last_sync_at") status String @default("active") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") deletedAt DateTime? @map("deleted_at") auditLogs IitAuditLog[] pendingActions IitPendingAction[] taskRuns IitTaskRun[] userMappings IitUserMapping[] @@index([status, deletedAt]) @@map("projects") @@schema("iit_schema") } /// 影子状态表(核心) model IitPendingAction { id String @id @default(uuid()) projectId String @map("project_id") recordId String @map("record_id") fieldName String @map("field_name") currentValue Json? @map("current_value") suggestedValue Json? @map("suggested_value") status String agentType String @map("agent_type") reasoning String evidence Json approvedBy String? @map("approved_by") approvedAt DateTime? @map("approved_at") rejectionReason String? @map("rejection_reason") executedAt DateTime? @map("executed_at") errorMessage String? @map("error_message") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") project IitProject @relation(fields: [projectId], references: [id]) @@index([projectId, status]) @@index([projectId, recordId]) @@index([status, createdAt]) @@map("pending_actions") @@schema("iit_schema") } /// 任务运行记录(与 pg-boss 关联) model IitTaskRun { id String @id @default(uuid()) projectId String @map("project_id") taskType String @map("task_type") jobId String? @unique @map("job_id") status String 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") startedAt DateTime? @map("started_at") completedAt DateTime? @map("completed_at") duration Int? createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") project IitProject @relation(fields: [projectId], references: [id]) @@index([projectId, taskType, status]) @@index([jobId]) @@map("task_runs") @@schema("iit_schema") } /// 用户映射表(异构系统身份关联) model IitUserMapping { id String @id @default(uuid()) projectId String @map("project_id") systemUserId String @map("system_user_id") redcapUsername String @map("redcap_username") wecomUserId String? @map("wecom_user_id") miniProgramOpenId String? @unique @map("mini_program_open_id") sessionKey String? @map("session_key") role String createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") project IitProject @relation(fields: [projectId], references: [id]) @@unique([projectId, systemUserId]) @@unique([projectId, redcapUsername]) @@index([wecomUserId]) @@index([miniProgramOpenId]) @@map("user_mappings") @@schema("iit_schema") } /// 审计日志表 model IitAuditLog { id String @id @default(uuid()) projectId String @map("project_id") userId String @map("user_id") actionType String @map("action_type") entityType String @map("entity_type") entityId String @map("entity_id") details Json? traceId String @map("trace_id") createdAt DateTime @default(now()) @map("created_at") project IitProject @relation(fields: [projectId], references: [id]) @@index([projectId, createdAt]) @@index([userId, createdAt]) @@index([actionType, createdAt]) @@index([traceId]) @@map("audit_logs") @@schema("iit_schema") } model admin_operation_logs { id Int @id @default(autoincrement()) admin_id String operation_type String target_type String target_id String module String? before_data Json? after_data Json? ip_address String? user_agent String? created_at DateTime @default(now()) @@index([admin_id], map: "idx_admin_logs_admin_id") @@index([created_at], map: "idx_admin_logs_created_at") @@index([module], map: "idx_admin_logs_module") @@index([operation_type], map: "idx_admin_logs_operation_type") @@schema("admin_schema") } model departments { id String @id tenant_id String name String parent_id String? description String? created_at DateTime @default(now()) updated_at DateTime departments departments? @relation("departmentsTodepartments", fields: [parent_id], references: [id]) other_departments departments[] @relation("departmentsTodepartments") tenants tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) users User[] @@index([parent_id], map: "idx_departments_parent_id") @@index([tenant_id], map: "idx_departments_tenant_id") @@schema("platform_schema") } /// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by Prisma Client. model job_common { id String @default(dbgenerated("gen_random_uuid()")) @db.Uuid name String priority Int @default(0) data Json? state job_state @default(created) retry_limit Int @default(2) retry_count Int @default(0) retry_delay Int @default(0) retry_backoff Boolean @default(false) retry_delay_max Int? expire_seconds Int @default(900) deletion_seconds Int @default(604800) singleton_key String? singleton_on DateTime? @db.Timestamp(6) start_after DateTime @default(now()) @db.Timestamptz(6) created_on DateTime @default(now()) @db.Timestamptz(6) started_on DateTime? @db.Timestamptz(6) completed_on DateTime? @db.Timestamptz(6) keep_until DateTime @default(dbgenerated("(now() + '336:00:00'::interval)")) @db.Timestamptz(6) output Json? dead_letter String? policy String? @@ignore @@schema("platform_schema") } model permissions { id Int @id @default(autoincrement()) code String @unique name String description String? module String? created_at DateTime @default(now()) role_permissions role_permissions[] @@schema("platform_schema") } model role_permissions { id Int @id @default(autoincrement()) role UserRole permission_id Int created_at DateTime @default(now()) permissions permissions @relation(fields: [permission_id], references: [id], onDelete: Cascade) @@unique([role, permission_id]) @@schema("platform_schema") } model tenant_members { id String @id tenant_id String user_id String role UserRole joined_at DateTime @default(now()) tenants tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) users User @relation(fields: [user_id], references: [id], onDelete: Cascade) @@unique([tenant_id, user_id]) @@index([tenant_id], map: "idx_tenant_members_tenant_id") @@index([user_id], map: "idx_tenant_members_user_id") @@schema("platform_schema") } /// 系统模块配置表(动态管理可用模块) model modules { code String @id // 模块代码: RVW, PKB, ASL, DC, IIT, AIA name String // 显示名称 description String? // 模块描述 icon String? // 图标(可选) is_active Boolean @default(true) // 是否上线 sort_order Int @default(0) // 排序 created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([is_active]) @@index([sort_order]) @@schema("platform_schema") } /// 租户模块订阅表 model tenant_modules { id String @id @default(uuid()) tenant_id String module_code String is_enabled Boolean @default(true) expires_at DateTime? created_at DateTime @default(now()) tenants tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) @@unique([tenant_id, module_code]) @@index([tenant_id]) @@index([module_code]) @@schema("platform_schema") } /// 用户模块权限表(精细控制用户可访问的模块) model user_modules { id String @id @default(uuid()) user_id String tenant_id String /// 在哪个租户内的权限 module_code String /// 模块代码: RVW, PKB, ASL, DC, IIT, AIA is_enabled Boolean @default(true) /// 是否启用 created_at DateTime @default(now()) updated_at DateTime @updatedAt user User @relation(fields: [user_id], references: [id], onDelete: Cascade) tenant tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) @@unique([user_id, tenant_id, module_code]) @@index([user_id]) @@index([tenant_id]) @@index([module_code]) @@map("user_modules") @@schema("platform_schema") } model tenant_quota_allocations { id Int @id @default(autoincrement()) tenant_id String target_type String target_key String limit_amount BigInt used_amount BigInt @default(0) created_at DateTime @default(now()) updated_at DateTime tenants tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) @@unique([tenant_id, target_type, target_key]) @@index([tenant_id], map: "idx_quota_allocations_tenant_id") @@schema("platform_schema") } model tenant_quotas { id String @id tenant_id String quota_type String total_amount BigInt used_amount BigInt @default(0) reset_period String? last_reset_at DateTime? created_at DateTime @default(now()) updated_at DateTime tenants tenants @relation(fields: [tenant_id], references: [id], onDelete: Cascade) @@unique([tenant_id, quota_type]) @@schema("platform_schema") } model tenants { id String @id code String @unique name String type TenantType status TenantStatus @default(ACTIVE) config Json? @default("{}") total_quota BigInt @default(0) used_quota BigInt @default(0) contact_name String? contact_phone String? contact_email String? created_at DateTime @default(now()) updated_at DateTime expires_at DateTime? departments departments[] tenant_members tenant_members[] tenant_modules tenant_modules[] tenant_quota_allocations tenant_quota_allocations[] tenant_quotas tenant_quotas[] users User[] user_modules user_modules[] @@index([code], map: "idx_tenants_code") @@index([status], map: "idx_tenants_status") @@index([type], map: "idx_tenants_type") @@schema("platform_schema") } model verification_codes { id Int @id @default(autoincrement()) phone String code String @db.VarChar(6) type VerificationType expires_at DateTime is_used Boolean @default(false) attempts Int @default(0) created_at DateTime @default(now()) @@index([expires_at], map: "idx_verification_codes_expires") @@index([phone, type, is_used], map: "idx_verification_codes_phone_type") @@schema("platform_schema") } enum job_state { created retry active completed cancelled failed @@schema("platform_schema") } enum TenantStatus { ACTIVE SUSPENDED EXPIRED @@schema("platform_schema") } enum TenantType { HOSPITAL // 医院 PHARMA // 药企 INTERNAL // 内部(公司自己) PUBLIC // 个人用户公共池 @@schema("platform_schema") } enum UserRole { SUPER_ADMIN PROMPT_ENGINEER HOSPITAL_ADMIN PHARMA_ADMIN DEPARTMENT_ADMIN USER @@schema("platform_schema") } enum VerificationType { LOGIN RESET_PASSWORD BIND_PHONE @@schema("platform_schema") } // ============================================ // Prompt Management System (capability_schema) // ============================================ /// Prompt模板 - 存储Prompt的元信息 model prompt_templates { id Int @id @default(autoincrement()) code String @unique /// 唯一标识符,如 'RVW_EDITORIAL' name String /// 人类可读名称,如 "稿约规范性评估" module String /// 所属模块: RVW, ASL, DC, IIT, PKB, AIA description String? /// 描述 variables Json? /// 预期变量列表,如 ["title", "abstract"] versions prompt_versions[] created_at DateTime @default(now()) updated_at DateTime @updatedAt @@index([module], map: "idx_prompt_templates_module") @@map("prompt_templates") @@schema("capability_schema") } /// Prompt版本 - 存储Prompt的具体内容和版本历史 model prompt_versions { id Int @id @default(autoincrement()) template_id Int /// 关联的模板ID version Int /// 版本号: 1, 2, 3... content String @db.Text /// Prompt内容(支持Handlebars模板) model_config Json? /// 模型参数: {"temperature": 0.3, "model": "deepseek-v3"} status PromptStatus @default(DRAFT) changelog String? /// 变更说明 created_by String? /// 修改人userId(审计用) template prompt_templates @relation(fields: [template_id], references: [id]) created_at DateTime @default(now()) @@index([template_id, status], map: "idx_prompt_versions_template_status") @@index([status], map: "idx_prompt_versions_status") @@map("prompt_versions") @@schema("capability_schema") } /// Prompt状态枚举 enum PromptStatus { DRAFT /// 草稿(仅调试者可见) ACTIVE /// 线上生效(默认可见) ARCHIVED /// 归档 @@schema("capability_schema") }