From 61cdc97eeb56b1e124453326f2132a4f3fe193e0 Mon Sep 17 00:00:00 2001 From: HaHafeng Date: Fri, 23 Jan 2026 22:07:26 +0800 Subject: [PATCH] feat(platform): Fix pg-boss queue conflict and add safety standards Summary: - Fix pg-boss queue conflict (duplicate key violation on queue_pkey) - Add global error listener to prevent process crash - Reduce connection pool from 10 to 4 - Add graceful shutdown handling (SIGTERM/SIGINT) - Fix researchWorker recursive call bug in catch block - Make screeningWorker idempotent using upsert Security Standards (v1.1): - Prohibit recursive retry in Worker catch blocks - Prohibit payload bloat (only store fileKey/ID in job.data) - Require Worker idempotency (upsert + unique constraint) - Recommend task-specific expireInSeconds settings - Document graceful shutdown pattern New Features: - PKB signed URL endpoint for document preview/download - pg_bigm installation guide for Docker - Dockerfile.postgres-with-extensions for pgvector + pg_bigm Documentation: - Update Postgres-Only async task processing guide (v1.1) - Add troubleshooting SQL queries - Update safety checklist Tested: Local verification passed --- COMMIT_DAY1.txt | 1 + DC模块代码恢复指南.md | 1 + Dockerfile.postgres-with-extensions | 54 +++++ SAE_WECHAT_MP_DEPLOY_STEPS.md | 1 + backend/DEPLOY_TO_SAE_FOR_WECHAT_MP.md | 1 + backend/RESTART_SERVER_NOW.md | 1 + backend/WECHAT_MP_CONFIG_READY.md | 1 + backend/WECHAT_MP_QUICK_FIX.md | 1 + backend/check_db.ts | 1 + backend/check_db_data.ts | 1 + backend/check_iit.ts | 1 + backend/check_iit_asl_data.ts | 1 + backend/check_queue_table.ts | 1 + backend/check_rvw_issue.ts | 1 + backend/check_tables.ts | 1 + backend/compare_db.ts | 1 + backend/compare_dc_asl.ts | 1 + backend/compare_pkb_aia_rvw.ts | 1 + backend/compare_schema_db.ts | 1 + backend/create_mock_user.sql | 1 + backend/create_mock_user_platform.sql | 1 + backend/env.example.md | 1 + .../add_data_stats_to_tool_c_session.sql | 1 + .../001_add_postgres_cache_and_checkpoint.sql | 1 + .../manual-migrations/run-migration-002.ts | 1 + .../20251208_add_column_mapping/migration.sql | 1 + .../migrations/create_tool_c_session.sql | 1 + .../migrations/manual/ekb_create_indexes.sql | 1 + .../manual/ekb_create_indexes_mvp.sql | 1 + backend/rebuild-and-push.ps1 | 1 + backend/recover-code-from-cursor-db.js | 1 + backend/restore_job_common.sql | 1 + backend/restore_pgboss_functions.sql | 1 + backend/scripts/check-dc-tables.mjs | 1 + backend/scripts/create-capability-schema.sql | 1 + .../create-tool-c-ai-history-table.mjs | 1 + backend/scripts/create-tool-c-table.js | 1 + backend/scripts/create-tool-c-table.mjs | 1 + backend/scripts/migrate-aia-prompts.ts | 1 + backend/scripts/setup-prompt-system.ts | 1 + backend/scripts/test-pkb-apis-simple.ts | 1 + backend/scripts/test-prompt-api.ts | 1 + backend/scripts/test-unifuncs-deepsearch.ts | 1 + backend/scripts/verify-pkb-rvw-schema.ts | 1 + backend/src/common/auth/jwt.service.ts | 1 + backend/src/common/jobs/PgBossQueue.ts | 36 ++- backend/src/common/jobs/utils.ts | 1 + backend/src/common/prompt/prompt.types.ts | 1 + backend/src/common/rag/ChunkService.ts | 1 + backend/src/common/rag/DifyClient.ts | 1 + .../common/streaming/OpenAIStreamAdapter.ts | 1 + .../src/common/streaming/StreamingService.ts | 1 + backend/src/common/streaming/index.ts | 1 + backend/src/common/streaming/types.ts | 1 + backend/src/index.ts | 30 +++ .../src/modules/admin/routes/tenantRoutes.ts | 1 + .../src/modules/admin/types/tenant.types.ts | 1 + backend/src/modules/admin/types/user.types.ts | 1 + .../aia/controllers/agentController.ts | 1 + .../aia/controllers/attachmentController.ts | 1 + backend/src/modules/aia/index.ts | 1 + .../__tests__/api-integration-test.ts | 1 + .../__tests__/e2e-real-test-v2.ts | 1 + .../__tests__/fulltext-screening-api.http | 1 + .../modules/asl/services/screeningWorker.ts | 14 +- .../src/modules/asl/workers/researchWorker.ts | 8 +- .../services/ConflictDetectionService.ts | 1 + backend/src/modules/dc/tool-c/README.md | 1 + .../tool-c/controllers/StreamAIController.ts | 1 + .../iit-manager/agents/SessionMemory.ts | 1 + .../iit-manager/check-iit-table-structure.ts | 1 + .../iit-manager/check-project-config.ts | 1 + .../iit-manager/check-test-project-in-db.ts | 1 + .../iit-manager/docs/微信服务号接入指南.md | 1 + .../iit-manager/generate-wechat-tokens.ts | 1 + .../services/PatientWechatService.ts | 1 + .../iit-manager/test-chatservice-dify.ts | 1 + .../modules/iit-manager/test-iit-database.ts | 1 + .../iit-manager/test-patient-wechat-config.ts | 1 + .../test-patient-wechat-url-verify.ts | 1 + .../iit-manager/test-redcap-query-from-db.ts | 1 + .../iit-manager/test-wechat-mp-local.ps1 | 1 + .../src/modules/iit-manager/types/index.ts | 1 + .../pkb/controllers/documentController.ts | 91 +++++++ backend/src/modules/pkb/routes/health.ts | 1 + .../src/modules/pkb/routes/knowledgeBases.ts | 4 + backend/src/modules/rvw/__tests__/api.http | 1 + .../src/modules/rvw/__tests__/test-api.ps1 | 1 + backend/src/modules/rvw/index.ts | 1 + backend/src/modules/rvw/services/utils.ts | 1 + backend/src/tests/README.md | 1 + .../src/tests/test-cross-language-search.ts | 1 + backend/src/tests/test-query-rewrite.ts | 1 + backend/src/tests/test-rerank.ts | 1 + backend/src/tests/verify-test1-database.sql | 1 + backend/src/tests/verify-test1-database.ts | 1 + backend/src/types/global.d.ts | 1 + backend/sync-dc-database.ps1 | 1 + backend/temp_check.sql | 1 + backend/test-pkb-migration.http | 1 + backend/test-tool-c-advanced-scenarios.mjs | 1 + backend/test-tool-c-day2.mjs | 1 + backend/test-tool-c-day3.mjs | 1 + backend/verify_all_users.ts | 1 + backend/verify_functions.ts | 1 + backend/verify_job_common.ts | 1 + backend/verify_mock_user.ts | 1 + backend/verify_system.ts | 1 + deploy-to-sae.ps1 | 1 + .../02-存储服务/OSS账号与配置信息.md | 1 + .../02-存储服务/OSS集成开发记录-2026-01-22.md | 1 + .../03-RAG引擎/05-RAG引擎使用指南.md | 1 + .../03-RAG引擎/06-pg_bigm安装指南.md | 212 ++++++++++++++++ .../Postgres-Only异步任务处理指南.md | 203 +++++++++++++++- docs/02-通用能力层/快速引用卡片.md | 1 + ...术方案文档_Postgres-Only队列架构优化方案 (1).md | 229 ++++++++++++++++++ docs/02-通用能力层/通用能力层技术债务清单.md | 1 + .../ADMIN-运营管理端/00-Phase3.5完成总结.md | 1 + .../2026-01-16_用户管理功能与模块权限系统完成.md | 1 + docs/03-业务模块/ADMIN-运营管理端/README.md | 1 + .../ADMIN运营与INST机构管理端-文档体系建立完成.md | 1 + .../AIA-AI智能问答/04-开发计划/03-前端组件设计.md | 1 + .../06-开发记录/2026-01-18-Prompt管理系统集成.md | 1 + .../04-开发计划/05-全文复筛前端开发计划.md | 1 + .../05-开发记录/2025-01-23_全文复筛前端开发完成.md | 1 + .../05-开发记录/2025-01-23_全文复筛前端逻辑调整.md | 1 + .../05-开发记录/2025-11-23_Day5_全文复筛API开发.md | 1 + .../2026-01-18_智能文献检索DeepSearch集成.md | 1 + .../04-开发计划/工具C_AI_Few-shot示例库.md | 1 + .../04-开发计划/工具C_Bug修复总结_2025-12-08.md | 1 + .../04-开发计划/工具C_Day3开发计划.md | 1 + .../04-开发计划/工具C_Day4-5前端开发计划.md | 1 + .../04-开发计划/工具C_Pivot列顺序优化总结.md | 1 + .../04-开发计划/工具C_方案B实施总结_2025-12-09.md | 1 + .../04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md | 1 + .../04-开发计划/工具C_缺失值处理功能_更新说明.md | 1 + .../06-开发记录/2025-12-02_工作总结.md | 1 + .../06-开发记录/2025-12-06_工具C_Day1开发完成总结.md | 1 + .../06-开发记录/2025-12-06_工具C_Day2开发完成总结.md | 1 + .../06-开发记录/2025-12-07_AI对话核心功能增强总结.md | 1 + .../2025-12-07_Bug修复_DataGrid空数据防御.md | 1 + .../06-开发记录/2025-12-07_Day5_Ant-Design-X重构完成.md | 1 + .../06-开发记录/2025-12-07_Day5最终总结.md | 1 + .../06-开发记录/2025-12-07_UI优化与Bug修复.md | 1 + .../06-开发记录/2025-12-07_后端API完整对接完成.md | 1 + .../06-开发记录/2025-12-07_完整UI优化与功能增强.md | 1 + .../06-开发记录/2025-12-07_工具C_Day4前端基础完成.md | 1 + .../06-开发记录/DC模块重建完成总结-Day1.md | 1 + .../06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md | 1 + .../Phase2-ToolB-Step1-2开发完成-2025-12-03.md | 1 + .../06-开发记录/Portal页面UI优化-2025-12-02.md | 1 + .../06-开发记录/Tool-B-MVP完成总结-2025-12-03.md | 1 + .../06-开发记录/ToolB-UI优化-2025-12-03.md | 1 + .../06-开发记录/ToolB-UI优化-Round2-2025-12-03.md | 1 + .../06-开发记录/ToolB浏览器测试计划-2025-12-03.md | 1 + .../06-开发记录/后端API测试报告-2025-12-02.md | 1 + .../06-开发记录/待办事项-下一步工作.md | 1 + .../06-开发记录/数据库验证报告-2025-12-02.md | 1 + .../07-技术债务/Tool-B技术债务清单.md | 1 + .../IIT Manager Agent 技术路径与架构设计.md | 1 + .../04-开发计划/REDCap对接技术方案与实施指南.md | 1 + .../04-开发计划/企业微信注册指南.md | 1 + .../2026-01-04-Dify知识库集成开发记录.md | 1 + .../Day2-REDCap实时集成开发完成记录.md | 1 + .../Day3-企业微信集成与端到端测试完成记录.md | 1 + .../06-开发记录/Day3-企业微信集成开发完成记录.md | 1 + .../Phase1.5-AI对话集成REDCap完成记录.md | 1 + .../06-开发记录/V1.1更新完成报告.md | 1 + .../07-技术债务/IIT Manager Agent 技术债务清单.md | 1 + .../INST-机构管理端/00-模块当前状态与开发指南.md | 1 + docs/03-业务模块/INST-机构管理端/README.md | 1 + .../06-开发记录/2026-01-07-前端迁移与批处理功能完善.md | 1 + .../06-开发记录/2026-01-07_PKB模块前端V3设计实现.md | 1 + .../01-部署与配置/10-REDCap_Docker部署操作手册.md | 1 + docs/03-业务模块/Redcap/README.md | 1 + docs/04-开发规范/09-数据库开发规范.md | 1 + docs/04-开发规范/10-模块认证规范.md | 1 + .../02-SAE部署完全指南(产品经理版).md | 1 + .../07-前端Nginx-SAE部署操作手册.md | 1 + .../08-PostgreSQL数据库部署操作手册.md | 1 + .../10-Node.js后端-Docker镜像构建手册.md | 1 + .../11-Node.js后端-SAE部署配置清单.md | 1 + .../12-Node.js后端-SAE部署操作手册.md | 1 + .../13-Node.js后端-镜像修复记录.md | 1 + .../14-Node.js后端-pino-pretty问题修复.md | 1 + docs/05-部署文档/16-前端Nginx-部署成功总结.md | 1 + .../05-部署文档/17-完整部署实战手册-2025版.md | 1 + docs/05-部署文档/18-部署文档使用指南.md | 1 + docs/05-部署文档/19-日常更新快速操作手册.md | 1 + docs/05-部署文档/文档修正报告-20251214.md | 1 + docs/07-运维文档/03-SAE环境变量配置指南.md | 1 + .../05-Redis缓存与队列的区别说明.md | 1 + docs/07-运维文档/06-长时间任务可靠性分析.md | 1 + .../07-Redis使用需求分析(按模块).md | 1 + .../2025-12-13-Postgres-Only架构改造完成.md | 1 + .../05-技术债务/通用对话服务抽取计划.md | 1 + docs/08-项目管理/2026-01-11-数据库事故总结.md | 1 + docs/08-项目管理/PKB前端问题修复报告.md | 1 + docs/08-项目管理/PKB前端验证指南.md | 1 + docs/08-项目管理/PKB功能审查报告-阶段0.md | 1 + docs/08-项目管理/PKB和RVW功能迁移计划.md | 1 + docs/08-项目管理/PKB精细化优化报告.md | 1 + docs/08-项目管理/PKB迁移-超级安全执行计划.md | 1 + docs/08-项目管理/PKB迁移-阶段1完成报告.md | 1 + docs/08-项目管理/PKB迁移-阶段2完成报告.md | 1 + docs/08-项目管理/PKB迁移-阶段2进行中.md | 1 + docs/08-项目管理/PKB迁移-阶段3完成报告.md | 1 + docs/08-项目管理/PKB迁移-阶段4完成报告.md | 1 + extraction_service/.dockerignore | 1 + extraction_service/operations/__init__.py | 1 + extraction_service/operations/dropna.py | 1 + extraction_service/operations/filter.py | 1 + extraction_service/operations/unpivot.py | 1 + .../services/pdf_markdown_processor.py | 1 + extraction_service/test_dc_api.py | 1 + extraction_service/test_execute_simple.py | 1 + extraction_service/test_module.py | 1 + frontend-v2/.dockerignore | 1 + frontend-v2/docker-entrypoint.sh | 1 + frontend-v2/nginx.conf | 1 + frontend-v2/src/common/api/axios.ts | 1 + frontend-v2/src/framework/auth/api.ts | 1 + frontend-v2/src/framework/auth/index.ts | 1 + frontend-v2/src/framework/auth/moduleApi.ts | 1 + .../components/ModulePermissionModal.tsx | 1 + frontend-v2/src/modules/admin/index.tsx | 1 + frontend-v2/src/modules/admin/types/user.ts | 1 + .../src/modules/aia/components/AgentCard.tsx | 1 + .../src/modules/aia/components/index.ts | 1 + frontend-v2/src/modules/aia/constants.ts | 1 + .../src/modules/aia/styles/agent-card.css | 1 + .../asl/components/FulltextDetailDrawer.tsx | 1 + frontend-v2/src/modules/dc/hooks/useAssets.ts | 1 + .../src/modules/dc/hooks/useRecentTasks.ts | 1 + .../dc/pages/tool-c/hooks/useSessionStatus.ts | 1 + .../modules/dc/pages/tool-c/types/index.ts | 1 + frontend-v2/src/modules/dc/types/portal.ts | 1 + .../src/modules/pkb/pages/KnowledgePage.tsx | 1 + .../src/modules/pkb/types/workspace.ts | 1 + .../src/modules/rvw/components/AgentModal.tsx | 1 + .../modules/rvw/components/BatchToolbar.tsx | 1 + .../modules/rvw/components/FilterChips.tsx | 1 + .../src/modules/rvw/components/Header.tsx | 1 + .../modules/rvw/components/ReportDetail.tsx | 1 + .../src/modules/rvw/components/ScoreRing.tsx | 1 + .../src/modules/rvw/components/Sidebar.tsx | 1 + .../src/modules/rvw/components/index.ts | 1 + .../src/modules/rvw/pages/Dashboard.tsx | 1 + frontend-v2/src/modules/rvw/styles/index.css | 1 + .../pages/admin/tenants/TenantListPage.tsx | 1 + .../src/pages/admin/tenants/api/tenantApi.ts | 1 + .../shared/components/Chat/AIStreamChat.tsx | 1 + .../components/Chat/ConversationList.tsx | 1 + .../src/shared/components/Chat/hooks/index.ts | 1 + .../components/Chat/hooks/useAIStream.ts | 1 + .../components/Chat/hooks/useConversations.ts | 1 + .../components/Chat/styles/ai-stream-chat.css | 1 + .../Chat/styles/conversation-list.css | 1 + .../components/Chat/styles/thinking.css | 1 + frontend-v2/src/shared/components/index.ts | 1 + frontend-v2/src/vite-env.d.ts | 1 + .../src/pages/rvw/components/BatchToolbar.tsx | 1 + .../pages/rvw/components/EditorialReport.tsx | 1 + .../src/pages/rvw/components/FilterChips.tsx | 1 + frontend/src/pages/rvw/components/Header.tsx | 1 + .../src/pages/rvw/components/ReportDetail.tsx | 1 + .../src/pages/rvw/components/ScoreRing.tsx | 1 + frontend/src/pages/rvw/components/Sidebar.tsx | 1 + frontend/src/pages/rvw/index.ts | 1 + frontend/src/pages/rvw/styles.css | 1 + git-cleanup-redcap.ps1 | 1 + git-commit-day1.ps1 | 1 + git-fix-lock.ps1 | 1 + python-microservice/operations/__init__.py | 1 + python-microservice/operations/binning.py | 1 + python-microservice/operations/filter.py | 1 + python-microservice/operations/recode.py | 1 + recover_dc_code.py | 1 + redcap-docker-dev/.gitattributes | 1 + redcap-docker-dev/.gitignore | 1 + redcap-docker-dev/README.md | 1 + redcap-docker-dev/docker-compose.prod.yml | 1 + redcap-docker-dev/docker-compose.yml | 1 + redcap-docker-dev/env.template | 1 + redcap-docker-dev/scripts/clean-redcap.ps1 | 1 + .../scripts/create-redcap-password.php | 1 + redcap-docker-dev/scripts/logs-redcap.ps1 | 1 + .../scripts/reset-admin-password.php | 1 + redcap-docker-dev/scripts/start-redcap.ps1 | 1 + redcap-docker-dev/scripts/stop-redcap.ps1 | 1 + run_recovery.ps1 | 1 + tests/QUICKSTART_快速开始.md | 1 + tests/README_测试说明.md | 1 + tests/run_tests.bat | 1 + tests/run_tests.sh | 1 + 快速部署到SAE.md | 1 + 部署检查清单.md | 1 + 297 files changed, 1147 insertions(+), 21 deletions(-) create mode 100644 Dockerfile.postgres-with-extensions create mode 100644 docs/02-通用能力层/03-RAG引擎/06-pg_bigm安装指南.md create mode 100644 docs/02-通用能力层/技术方案文档_Postgres-Only队列架构优化方案 (1).md diff --git a/COMMIT_DAY1.txt b/COMMIT_DAY1.txt index c27cc2d2..1e61f8bb 100644 --- a/COMMIT_DAY1.txt +++ b/COMMIT_DAY1.txt @@ -58,5 +58,6 @@ Status: Day 1 complete (11/11 tasks), ready for Day 2 + diff --git a/DC模块代码恢复指南.md b/DC模块代码恢复指南.md index 101fa591..9f1403c4 100644 --- a/DC模块代码恢复指南.md +++ b/DC模块代码恢复指南.md @@ -288,5 +288,6 @@ + diff --git a/Dockerfile.postgres-with-extensions b/Dockerfile.postgres-with-extensions new file mode 100644 index 00000000..9998d23c --- /dev/null +++ b/Dockerfile.postgres-with-extensions @@ -0,0 +1,54 @@ +# PostgreSQL 15 with pgvector + pg_bigm extensions +# 用于 AI 临床研究平台的向量检索和中文关键词检索 +# +# 扩展版本: +# - pgvector: 0.8.1 (向量相似度搜索) +# - pg_bigm: 1.2 (中日韩文本全文搜索) +# +# 构建命令: +# docker build -f Dockerfile.postgres-with-extensions -t ai-clinical-postgres:v1.1 . +# +# 使用方法: +# 1. 构建镜像后,修改 docker-compose.yml: +# image: ai-clinical-postgres:v1.1 +# 2. 重启服务:docker compose down && docker compose up -d +# 3. 启用扩展: +# docker exec -it ai-clinical-postgres psql -U postgres -d ai_clinical_research -c "CREATE EXTENSION IF NOT EXISTS pg_bigm;" + +FROM pgvector/pgvector:pg15 + +# 使用阿里云镜像源加速(如果在国内) +# RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list.d/*.sources 2>/dev/null || true + +# 安装编译依赖 +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + postgresql-server-dev-15 \ + wget \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# 下载并编译 pg_bigm +# pg_bigm 是专门为中日韩(CJK)字符优化的全文搜索扩展 +RUN cd /tmp \ + && wget -q https://github.com/pgbigm/pg_bigm/archive/refs/tags/v1.2-20200228.tar.gz \ + && tar -xzf v1.2-20200228.tar.gz \ + && cd pg_bigm-1.2-20200228 \ + && make USE_PGXS=1 \ + && make USE_PGXS=1 install \ + && cd / \ + && rm -rf /tmp/pg_bigm* /tmp/v1.2-20200228.tar.gz + +# 清理编译依赖 +RUN apt-get purge -y --auto-remove \ + build-essential \ + postgresql-server-dev-15 \ + wget \ + && rm -rf /var/lib/apt/lists/* + +# 添加初始化脚本(自动创建扩展) +COPY docker-init-extensions.sql /docker-entrypoint-initdb.d/ + +# 暴露端口 +EXPOSE 5432 + diff --git a/SAE_WECHAT_MP_DEPLOY_STEPS.md b/SAE_WECHAT_MP_DEPLOY_STEPS.md index f888b4b6..6e19166b 100644 --- a/SAE_WECHAT_MP_DEPLOY_STEPS.md +++ b/SAE_WECHAT_MP_DEPLOY_STEPS.md @@ -234,5 +234,6 @@ https://iit.xunzhengyixue.com/api/v1/iit/health + diff --git a/backend/DEPLOY_TO_SAE_FOR_WECHAT_MP.md b/backend/DEPLOY_TO_SAE_FOR_WECHAT_MP.md index e17c5a16..47bc263d 100644 --- a/backend/DEPLOY_TO_SAE_FOR_WECHAT_MP.md +++ b/backend/DEPLOY_TO_SAE_FOR_WECHAT_MP.md @@ -163,5 +163,6 @@ https://iit.xunzhengyixue.com/api/v1/iit/health + diff --git a/backend/RESTART_SERVER_NOW.md b/backend/RESTART_SERVER_NOW.md index 226660dd..8f5f5d54 100644 --- a/backend/RESTART_SERVER_NOW.md +++ b/backend/RESTART_SERVER_NOW.md @@ -64,5 +64,6 @@ + diff --git a/backend/WECHAT_MP_CONFIG_READY.md b/backend/WECHAT_MP_CONFIG_READY.md index abbd8461..7f6f4c6a 100644 --- a/backend/WECHAT_MP_CONFIG_READY.md +++ b/backend/WECHAT_MP_CONFIG_READY.md @@ -324,5 +324,6 @@ npx tsx src/modules/iit-manager/test-patient-wechat-url-verify.ts + diff --git a/backend/WECHAT_MP_QUICK_FIX.md b/backend/WECHAT_MP_QUICK_FIX.md index 1ea4a126..0cf0c435 100644 --- a/backend/WECHAT_MP_QUICK_FIX.md +++ b/backend/WECHAT_MP_QUICK_FIX.md @@ -186,5 +186,6 @@ npm run dev + diff --git a/backend/check_db.ts b/backend/check_db.ts index 74aa50ff..0c7fabeb 100644 --- a/backend/check_db.ts +++ b/backend/check_db.ts @@ -65,3 +65,4 @@ main() + diff --git a/backend/check_db_data.ts b/backend/check_db_data.ts index 22a9dc60..39c81b3f 100644 --- a/backend/check_db_data.ts +++ b/backend/check_db_data.ts @@ -59,3 +59,4 @@ main() + diff --git a/backend/check_iit.ts b/backend/check_iit.ts index 06a73861..b5123c7f 100644 --- a/backend/check_iit.ts +++ b/backend/check_iit.ts @@ -54,3 +54,4 @@ main() + diff --git a/backend/check_iit_asl_data.ts b/backend/check_iit_asl_data.ts index a017b742..838efd92 100644 --- a/backend/check_iit_asl_data.ts +++ b/backend/check_iit_asl_data.ts @@ -86,3 +86,4 @@ main() + diff --git a/backend/check_queue_table.ts b/backend/check_queue_table.ts index d2dc142c..fce065bc 100644 --- a/backend/check_queue_table.ts +++ b/backend/check_queue_table.ts @@ -49,3 +49,4 @@ main() + diff --git a/backend/check_rvw_issue.ts b/backend/check_rvw_issue.ts index 03b9fe23..a9bfc829 100644 --- a/backend/check_rvw_issue.ts +++ b/backend/check_rvw_issue.ts @@ -90,3 +90,4 @@ main() + diff --git a/backend/check_tables.ts b/backend/check_tables.ts index 0635ec56..444fcf8b 100644 --- a/backend/check_tables.ts +++ b/backend/check_tables.ts @@ -37,3 +37,4 @@ main() + diff --git a/backend/compare_db.ts b/backend/compare_db.ts index 664a1ea8..b1b119e2 100644 --- a/backend/compare_db.ts +++ b/backend/compare_db.ts @@ -125,3 +125,4 @@ main() + diff --git a/backend/compare_dc_asl.ts b/backend/compare_dc_asl.ts index 8b254c03..c65d175c 100644 --- a/backend/compare_dc_asl.ts +++ b/backend/compare_dc_asl.ts @@ -96,3 +96,4 @@ main() + diff --git a/backend/compare_pkb_aia_rvw.ts b/backend/compare_pkb_aia_rvw.ts index 438ee7a3..57fbb0cf 100644 --- a/backend/compare_pkb_aia_rvw.ts +++ b/backend/compare_pkb_aia_rvw.ts @@ -82,3 +82,4 @@ main() + diff --git a/backend/compare_schema_db.ts b/backend/compare_schema_db.ts index e6318487..58e53161 100644 --- a/backend/compare_schema_db.ts +++ b/backend/compare_schema_db.ts @@ -124,3 +124,4 @@ main() + diff --git a/backend/create_mock_user.sql b/backend/create_mock_user.sql index 52212f6e..9bfa95c9 100644 --- a/backend/create_mock_user.sql +++ b/backend/create_mock_user.sql @@ -35,3 +35,4 @@ ON CONFLICT (id) DO NOTHING; + diff --git a/backend/create_mock_user_platform.sql b/backend/create_mock_user_platform.sql index ff038be9..55ef3b19 100644 --- a/backend/create_mock_user_platform.sql +++ b/backend/create_mock_user_platform.sql @@ -67,3 +67,4 @@ ON CONFLICT (id) DO NOTHING; + diff --git a/backend/env.example.md b/backend/env.example.md index 6d53e2d1..5303def9 100644 --- a/backend/env.example.md +++ b/backend/env.example.md @@ -77,3 +77,4 @@ OSS_INTERNAL=true # 🔴 生产必须用内网 OSS_SIGNED_URL_EXPIRES=3600 ``` + diff --git a/backend/migrations/add_data_stats_to_tool_c_session.sql b/backend/migrations/add_data_stats_to_tool_c_session.sql index a8fc4a83..da798ff2 100644 --- a/backend/migrations/add_data_stats_to_tool_c_session.sql +++ b/backend/migrations/add_data_stats_to_tool_c_session.sql @@ -83,5 +83,6 @@ WHERE table_schema = 'dc_schema' + diff --git a/backend/prisma/manual-migrations/001_add_postgres_cache_and_checkpoint.sql b/backend/prisma/manual-migrations/001_add_postgres_cache_and_checkpoint.sql index 84059cf1..a90297aa 100644 --- a/backend/prisma/manual-migrations/001_add_postgres_cache_and_checkpoint.sql +++ b/backend/prisma/manual-migrations/001_add_postgres_cache_and_checkpoint.sql @@ -121,5 +121,6 @@ ORDER BY ordinal_position; + diff --git a/backend/prisma/manual-migrations/run-migration-002.ts b/backend/prisma/manual-migrations/run-migration-002.ts index 157f421b..f1371a47 100644 --- a/backend/prisma/manual-migrations/run-migration-002.ts +++ b/backend/prisma/manual-migrations/run-migration-002.ts @@ -134,5 +134,6 @@ runMigration() + diff --git a/backend/prisma/migrations/20251208_add_column_mapping/migration.sql b/backend/prisma/migrations/20251208_add_column_mapping/migration.sql index 29c3a130..7859499b 100644 --- a/backend/prisma/migrations/20251208_add_column_mapping/migration.sql +++ b/backend/prisma/migrations/20251208_add_column_mapping/migration.sql @@ -68,5 +68,6 @@ COMMENT ON COLUMN "dc_schema"."dc_tool_c_sessions"."column_mapping" IS '列名 + diff --git a/backend/prisma/migrations/create_tool_c_session.sql b/backend/prisma/migrations/create_tool_c_session.sql index 06696b3c..3f82701f 100644 --- a/backend/prisma/migrations/create_tool_c_session.sql +++ b/backend/prisma/migrations/create_tool_c_session.sql @@ -95,5 +95,6 @@ COMMENT ON COLUMN dc_schema.dc_tool_c_sessions.expires_at IS '过期时间(创 + diff --git a/backend/prisma/migrations/manual/ekb_create_indexes.sql b/backend/prisma/migrations/manual/ekb_create_indexes.sql index 716b850a..a6c8443a 100644 --- a/backend/prisma/migrations/manual/ekb_create_indexes.sql +++ b/backend/prisma/migrations/manual/ekb_create_indexes.sql @@ -65,3 +65,4 @@ USING gin (metadata jsonb_path_ops); + diff --git a/backend/prisma/migrations/manual/ekb_create_indexes_mvp.sql b/backend/prisma/migrations/manual/ekb_create_indexes_mvp.sql index aa3fa357..38c78a73 100644 --- a/backend/prisma/migrations/manual/ekb_create_indexes_mvp.sql +++ b/backend/prisma/migrations/manual/ekb_create_indexes_mvp.sql @@ -32,3 +32,4 @@ USING gin (tags); + diff --git a/backend/rebuild-and-push.ps1 b/backend/rebuild-and-push.ps1 index 046dfa65..726ddeed 100644 --- a/backend/rebuild-and-push.ps1 +++ b/backend/rebuild-and-push.ps1 @@ -135,5 +135,6 @@ Write-Host "" + diff --git a/backend/recover-code-from-cursor-db.js b/backend/recover-code-from-cursor-db.js index 0bcbba22..0ee79904 100644 --- a/backend/recover-code-from-cursor-db.js +++ b/backend/recover-code-from-cursor-db.js @@ -245,5 +245,6 @@ function extractCodeBlocks(obj, blocks = []) { + diff --git a/backend/restore_job_common.sql b/backend/restore_job_common.sql index 090b8608..5c06766f 100644 --- a/backend/restore_job_common.sql +++ b/backend/restore_job_common.sql @@ -44,3 +44,4 @@ CREATE TABLE IF NOT EXISTS platform_schema.job_common ( + diff --git a/backend/restore_pgboss_functions.sql b/backend/restore_pgboss_functions.sql index cd6b03b1..88d52a99 100644 --- a/backend/restore_pgboss_functions.sql +++ b/backend/restore_pgboss_functions.sql @@ -118,3 +118,4 @@ CREATE OR REPLACE FUNCTION platform_schema.delete_queue(queue_name text) RETURNS + diff --git a/backend/scripts/check-dc-tables.mjs b/backend/scripts/check-dc-tables.mjs index e1ab44e2..4bf6760d 100644 --- a/backend/scripts/check-dc-tables.mjs +++ b/backend/scripts/check-dc-tables.mjs @@ -264,5 +264,6 @@ checkDCTables(); + diff --git a/backend/scripts/create-capability-schema.sql b/backend/scripts/create-capability-schema.sql index 115b527e..e94f323d 100644 --- a/backend/scripts/create-capability-schema.sql +++ b/backend/scripts/create-capability-schema.sql @@ -19,3 +19,4 @@ CREATE SCHEMA IF NOT EXISTS capability_schema; + diff --git a/backend/scripts/create-tool-c-ai-history-table.mjs b/backend/scripts/create-tool-c-ai-history-table.mjs index 6786889b..c4c0d750 100644 --- a/backend/scripts/create-tool-c-ai-history-table.mjs +++ b/backend/scripts/create-tool-c-ai-history-table.mjs @@ -216,5 +216,6 @@ createAiHistoryTable() + diff --git a/backend/scripts/create-tool-c-table.js b/backend/scripts/create-tool-c-table.js index 1ab957d8..d023beda 100644 --- a/backend/scripts/create-tool-c-table.js +++ b/backend/scripts/create-tool-c-table.js @@ -203,5 +203,6 @@ createToolCTable() + diff --git a/backend/scripts/create-tool-c-table.mjs b/backend/scripts/create-tool-c-table.mjs index b5052618..80092fdb 100644 --- a/backend/scripts/create-tool-c-table.mjs +++ b/backend/scripts/create-tool-c-table.mjs @@ -200,5 +200,6 @@ createToolCTable() + diff --git a/backend/scripts/migrate-aia-prompts.ts b/backend/scripts/migrate-aia-prompts.ts index 53ef20f7..ecf0300b 100644 --- a/backend/scripts/migrate-aia-prompts.ts +++ b/backend/scripts/migrate-aia-prompts.ts @@ -322,3 +322,4 @@ main() + diff --git a/backend/scripts/setup-prompt-system.ts b/backend/scripts/setup-prompt-system.ts index 37646844..24ff23c5 100644 --- a/backend/scripts/setup-prompt-system.ts +++ b/backend/scripts/setup-prompt-system.ts @@ -129,3 +129,4 @@ main() + diff --git a/backend/scripts/test-pkb-apis-simple.ts b/backend/scripts/test-pkb-apis-simple.ts index be902210..b6e3ad20 100644 --- a/backend/scripts/test-pkb-apis-simple.ts +++ b/backend/scripts/test-pkb-apis-simple.ts @@ -347,5 +347,6 @@ runTests().catch(error => { + diff --git a/backend/scripts/test-prompt-api.ts b/backend/scripts/test-prompt-api.ts index 8eb2b88f..57e8df47 100644 --- a/backend/scripts/test-prompt-api.ts +++ b/backend/scripts/test-prompt-api.ts @@ -95,3 +95,4 @@ testAPI().catch(console.error); + diff --git a/backend/scripts/test-unifuncs-deepsearch.ts b/backend/scripts/test-unifuncs-deepsearch.ts index 95e3f7b1..c6df9ffa 100644 --- a/backend/scripts/test-unifuncs-deepsearch.ts +++ b/backend/scripts/test-unifuncs-deepsearch.ts @@ -125,3 +125,4 @@ testDeepSearch().catch(console.error); + diff --git a/backend/scripts/verify-pkb-rvw-schema.ts b/backend/scripts/verify-pkb-rvw-schema.ts index 38c39832..ecae9959 100644 --- a/backend/scripts/verify-pkb-rvw-schema.ts +++ b/backend/scripts/verify-pkb-rvw-schema.ts @@ -312,5 +312,6 @@ verifySchemas() + diff --git a/backend/src/common/auth/jwt.service.ts b/backend/src/common/auth/jwt.service.ts index ebac7aeb..e43ad06e 100644 --- a/backend/src/common/auth/jwt.service.ts +++ b/backend/src/common/auth/jwt.service.ts @@ -202,3 +202,4 @@ export const jwtService = new JWTService(); + diff --git a/backend/src/common/jobs/PgBossQueue.ts b/backend/src/common/jobs/PgBossQueue.ts index bbcf5308..14d38f10 100644 --- a/backend/src/common/jobs/PgBossQueue.ts +++ b/backend/src/common/jobs/PgBossQueue.ts @@ -50,7 +50,7 @@ export class PgBossQueue implements JobQueue { this.boss = new PgBoss({ connectionString, schema, // 使用platform_schema - max: 10, // 最大连接数 + max: 4, // 🛡️ 限制连接数,避免挤占 Prisma 连接配额(RDS 限制 100) application_name: 'aiclinical-queue', // 调度配置 @@ -61,6 +61,17 @@ export class PgBossQueue implements JobQueue { maintenanceIntervalSeconds: 300, // 每5分钟运行维护任务 }) + // 🛡️ 全局错误监听:防止未捕获错误导致进程崩溃 + this.boss.on('error', (err: any) => { + // 静默处理 duplicate key 错误(队列并发初始化时的正常现象) + if (err.code === '23505' && err.constraint === 'queue_pkey') { + console.log(`[PgBossQueue] ℹ️ Queue concurrency conflict auto-resolved: ${err.detail}`); + } else { + console.error('[PgBossQueue] ❌ Critical error:', err); + // 记录到日志但不崩溃进程 + } + }); + console.log('[PgBossQueue] Initialized with schema:', schema) } @@ -192,13 +203,22 @@ export class PgBossQueue implements JobQueue { console.log(`[PgBossQueue] 🔧 开始注册 Handler: ${type}`); try { - // pg-boss 9.x 需要显式创建队列 - await this.boss.createQueue(type, { - retryLimit: 3, - retryDelay: 60, - expireInSeconds: 6 * 60 * 60 // 6小时 - }); - console.log(`[PgBossQueue] ✅ Queue created: ${type}`); + // pg-boss 9.x 需要显式创建队列(幂等操作) + try { + await this.boss.createQueue(type, { + retryLimit: 3, + retryDelay: 60, + expireInSeconds: 6 * 60 * 60 // 6小时 + }); + console.log(`[PgBossQueue] ✅ Queue created: ${type}`); + } catch (createError: any) { + // 队列已存在时会报 duplicate key 错误,忽略 + if (createError.code === '23505' || createError.message?.includes('already exists')) { + console.log(`[PgBossQueue] ℹ️ Queue already exists: ${type}`); + } else { + throw createError; + } + } await this.boss.work>(type, { batchSize: 1, // 每次处理1个任务 diff --git a/backend/src/common/jobs/utils.ts b/backend/src/common/jobs/utils.ts index bd69232f..a68a90c4 100644 --- a/backend/src/common/jobs/utils.ts +++ b/backend/src/common/jobs/utils.ts @@ -332,5 +332,6 @@ export function getBatchItems( + diff --git a/backend/src/common/prompt/prompt.types.ts b/backend/src/common/prompt/prompt.types.ts index 07ddb7b8..5aded3b2 100644 --- a/backend/src/common/prompt/prompt.types.ts +++ b/backend/src/common/prompt/prompt.types.ts @@ -85,3 +85,4 @@ export interface VariableValidation { + diff --git a/backend/src/common/rag/ChunkService.ts b/backend/src/common/rag/ChunkService.ts index adb681b2..8176bf9c 100644 --- a/backend/src/common/rag/ChunkService.ts +++ b/backend/src/common/rag/ChunkService.ts @@ -355,3 +355,4 @@ export default ChunkService; + diff --git a/backend/src/common/rag/DifyClient.ts b/backend/src/common/rag/DifyClient.ts index 05e804d0..237f403b 100644 --- a/backend/src/common/rag/DifyClient.ts +++ b/backend/src/common/rag/DifyClient.ts @@ -51,3 +51,4 @@ export const DifyClient = DeprecatedDifyClient; + diff --git a/backend/src/common/streaming/OpenAIStreamAdapter.ts b/backend/src/common/streaming/OpenAIStreamAdapter.ts index f9aca224..e496c59f 100644 --- a/backend/src/common/streaming/OpenAIStreamAdapter.ts +++ b/backend/src/common/streaming/OpenAIStreamAdapter.ts @@ -206,3 +206,4 @@ export function createOpenAIStreamAdapter( + diff --git a/backend/src/common/streaming/StreamingService.ts b/backend/src/common/streaming/StreamingService.ts index 66344eec..a856f80d 100644 --- a/backend/src/common/streaming/StreamingService.ts +++ b/backend/src/common/streaming/StreamingService.ts @@ -212,3 +212,4 @@ export async function streamChat( + diff --git a/backend/src/common/streaming/index.ts b/backend/src/common/streaming/index.ts index f0d98ab2..654a4759 100644 --- a/backend/src/common/streaming/index.ts +++ b/backend/src/common/streaming/index.ts @@ -30,3 +30,4 @@ export { THINKING_TAGS } from './types'; + diff --git a/backend/src/common/streaming/types.ts b/backend/src/common/streaming/types.ts index 31bc1f9d..e1bfd612 100644 --- a/backend/src/common/streaming/types.ts +++ b/backend/src/common/streaming/types.ts @@ -105,3 +105,4 @@ export type SSEEventType = + diff --git a/backend/src/index.ts b/backend/src/index.ts index c17f5484..ed1de09b 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -280,3 +280,33 @@ const start = async () => { }; start(); + +// ============================================ +// 🛡️ 优雅关闭处理(Graceful Shutdown) +// ============================================ +const gracefulShutdown = async (signal: string) => { + console.log(`\n⚠️ 收到 ${signal} 信号,开始优雅关闭...`); + + try { + // 1. 停止接收新请求 + await fastify.close(); + console.log('✅ HTTP 服务已停止'); + + // 2. 停止队列(等待当前任务完成) + await jobQueue.stop(); + console.log('✅ 任务队列已停止'); + + // 3. 关闭数据库连接 + await prisma.$disconnect(); + console.log('✅ 数据库连接已关闭'); + + console.log('👋 优雅关闭完成,再见!'); + process.exit(0); + } catch (error) { + console.error('❌ 优雅关闭失败:', error); + process.exit(1); + } +}; + +process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); +process.on('SIGINT', () => gracefulShutdown('SIGINT')); diff --git a/backend/src/modules/admin/routes/tenantRoutes.ts b/backend/src/modules/admin/routes/tenantRoutes.ts index 33d13ed8..cf2a24e7 100644 --- a/backend/src/modules/admin/routes/tenantRoutes.ts +++ b/backend/src/modules/admin/routes/tenantRoutes.ts @@ -91,3 +91,4 @@ export async function moduleRoutes(fastify: FastifyInstance) { + diff --git a/backend/src/modules/admin/types/tenant.types.ts b/backend/src/modules/admin/types/tenant.types.ts index 4ab42908..6b91ab40 100644 --- a/backend/src/modules/admin/types/tenant.types.ts +++ b/backend/src/modules/admin/types/tenant.types.ts @@ -121,3 +121,4 @@ export interface PaginatedResponse { + diff --git a/backend/src/modules/admin/types/user.types.ts b/backend/src/modules/admin/types/user.types.ts index f44b3aa8..f796b32a 100644 --- a/backend/src/modules/admin/types/user.types.ts +++ b/backend/src/modules/admin/types/user.types.ts @@ -168,3 +168,4 @@ export const ROLE_DISPLAY_NAMES: Record = { + diff --git a/backend/src/modules/aia/controllers/agentController.ts b/backend/src/modules/aia/controllers/agentController.ts index ac267463..5dcfc0a5 100644 --- a/backend/src/modules/aia/controllers/agentController.ts +++ b/backend/src/modules/aia/controllers/agentController.ts @@ -243,3 +243,4 @@ async function matchIntent(query: string): Promise<{ + diff --git a/backend/src/modules/aia/controllers/attachmentController.ts b/backend/src/modules/aia/controllers/attachmentController.ts index c25cb67a..e4cc6172 100644 --- a/backend/src/modules/aia/controllers/attachmentController.ts +++ b/backend/src/modules/aia/controllers/attachmentController.ts @@ -97,3 +97,4 @@ export async function uploadAttachment( + diff --git a/backend/src/modules/aia/index.ts b/backend/src/modules/aia/index.ts index af3289cd..565c0c9d 100644 --- a/backend/src/modules/aia/index.ts +++ b/backend/src/modules/aia/index.ts @@ -26,3 +26,4 @@ export { aiaRoutes }; + diff --git a/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts b/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts index 683f83e1..af6a01ce 100644 --- a/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts +++ b/backend/src/modules/asl/fulltext-screening/__tests__/api-integration-test.ts @@ -368,5 +368,6 @@ runTests().catch((error) => { + diff --git a/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts b/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts index 7f9afac9..d58dd227 100644 --- a/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts +++ b/backend/src/modules/asl/fulltext-screening/__tests__/e2e-real-test-v2.ts @@ -309,5 +309,6 @@ runTest() + diff --git a/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http b/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http index 3023c8e7..220a1c35 100644 --- a/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http +++ b/backend/src/modules/asl/fulltext-screening/__tests__/fulltext-screening-api.http @@ -347,5 +347,6 @@ Content-Type: application/json + diff --git a/backend/src/modules/asl/services/screeningWorker.ts b/backend/src/modules/asl/services/screeningWorker.ts index d0de2cd6..cd5113ff 100644 --- a/backend/src/modules/asl/services/screeningWorker.ts +++ b/backend/src/modules/asl/services/screeningWorker.ts @@ -257,7 +257,7 @@ async function processScreeningBatchWithCheckpoint( literature.publicationYear ? Number(literature.publicationYear) : undefined ); - // 保存结果(使用 screeningService.ts 相同的映射方式) + // 保存结果(使用 upsert 保证幂等性,任务重试时覆盖而不是重复创建) const dbResult = { projectId, literatureId: literature.id, @@ -294,8 +294,16 @@ async function processScreeningBatchWithCheckpoint( finalDecision: screeningResult.finalDecision, }; - await prisma.aslScreeningResult.create({ - data: dbResult, + // 🛡️ 使用 upsert 实现幂等性(利用 unique_project_literature 约束) + await prisma.aslScreeningResult.upsert({ + where: { + projectId_literatureId: { + projectId, + literatureId: literature.id, + }, + }, + create: dbResult, + update: dbResult, }); successCount++; diff --git a/backend/src/modules/asl/workers/researchWorker.ts b/backend/src/modules/asl/workers/researchWorker.ts index 4fbf7924..07d77234 100644 --- a/backend/src/modules/asl/workers/researchWorker.ts +++ b/backend/src/modules/asl/workers/researchWorker.ts @@ -67,12 +67,8 @@ export function registerResearchWorker() { error: error.message, }); - // 更新任务状态为失败 - try { - await researchService.executeSearch(taskId, query); - } catch { - // 忽略 - } + // ❌ 已移除错误的 executeSearch 调用 + // 任务失败后 pg-boss 会自动重试(最多3次) return { success: false, diff --git a/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts b/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts index 805ad3ab..8ae9e674 100644 --- a/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts +++ b/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts @@ -283,5 +283,6 @@ export const conflictDetectionService = new ConflictDetectionService(); + diff --git a/backend/src/modules/dc/tool-c/README.md b/backend/src/modules/dc/tool-c/README.md index 59a799b9..3088408f 100644 --- a/backend/src/modules/dc/tool-c/README.md +++ b/backend/src/modules/dc/tool-c/README.md @@ -233,5 +233,6 @@ curl -X POST http://localhost:3000/api/v1/dc/tool-c/test/execute \ + diff --git a/backend/src/modules/dc/tool-c/controllers/StreamAIController.ts b/backend/src/modules/dc/tool-c/controllers/StreamAIController.ts index 2e49bb16..e34dd0f9 100644 --- a/backend/src/modules/dc/tool-c/controllers/StreamAIController.ts +++ b/backend/src/modules/dc/tool-c/controllers/StreamAIController.ts @@ -287,5 +287,6 @@ export const streamAIController = new StreamAIController(); + diff --git a/backend/src/modules/iit-manager/agents/SessionMemory.ts b/backend/src/modules/iit-manager/agents/SessionMemory.ts index b035e9fd..e1ea5852 100644 --- a/backend/src/modules/iit-manager/agents/SessionMemory.ts +++ b/backend/src/modules/iit-manager/agents/SessionMemory.ts @@ -196,5 +196,6 @@ logger.info('[SessionMemory] 会话记忆管理器已启动', { + diff --git a/backend/src/modules/iit-manager/check-iit-table-structure.ts b/backend/src/modules/iit-manager/check-iit-table-structure.ts index 6564d850..a40a8d4c 100644 --- a/backend/src/modules/iit-manager/check-iit-table-structure.ts +++ b/backend/src/modules/iit-manager/check-iit-table-structure.ts @@ -130,5 +130,6 @@ checkTableStructure(); + diff --git a/backend/src/modules/iit-manager/check-project-config.ts b/backend/src/modules/iit-manager/check-project-config.ts index 981dcfcf..d703026f 100644 --- a/backend/src/modules/iit-manager/check-project-config.ts +++ b/backend/src/modules/iit-manager/check-project-config.ts @@ -117,5 +117,6 @@ checkProjectConfig().catch(console.error); + diff --git a/backend/src/modules/iit-manager/check-test-project-in-db.ts b/backend/src/modules/iit-manager/check-test-project-in-db.ts index fc8abd1f..2ac39a0d 100644 --- a/backend/src/modules/iit-manager/check-test-project-in-db.ts +++ b/backend/src/modules/iit-manager/check-test-project-in-db.ts @@ -99,5 +99,6 @@ main(); + diff --git a/backend/src/modules/iit-manager/docs/微信服务号接入指南.md b/backend/src/modules/iit-manager/docs/微信服务号接入指南.md index 7f65ed4c..7e690c5f 100644 --- a/backend/src/modules/iit-manager/docs/微信服务号接入指南.md +++ b/backend/src/modules/iit-manager/docs/微信服务号接入指南.md @@ -556,5 +556,6 @@ URL: https://iit.xunzhengyixue.com/api/v1/iit/patient-wechat/callback + diff --git a/backend/src/modules/iit-manager/generate-wechat-tokens.ts b/backend/src/modules/iit-manager/generate-wechat-tokens.ts index dc32a9fb..5686d4ac 100644 --- a/backend/src/modules/iit-manager/generate-wechat-tokens.ts +++ b/backend/src/modules/iit-manager/generate-wechat-tokens.ts @@ -191,5 +191,6 @@ console.log(''); + diff --git a/backend/src/modules/iit-manager/services/PatientWechatService.ts b/backend/src/modules/iit-manager/services/PatientWechatService.ts index c4b8aa33..4a8bd509 100644 --- a/backend/src/modules/iit-manager/services/PatientWechatService.ts +++ b/backend/src/modules/iit-manager/services/PatientWechatService.ts @@ -508,5 +508,6 @@ export const patientWechatService = new PatientWechatService(); + diff --git a/backend/src/modules/iit-manager/test-chatservice-dify.ts b/backend/src/modules/iit-manager/test-chatservice-dify.ts index 26c3a3c8..a9c12259 100644 --- a/backend/src/modules/iit-manager/test-chatservice-dify.ts +++ b/backend/src/modules/iit-manager/test-chatservice-dify.ts @@ -153,5 +153,6 @@ testDifyIntegration().catch(error => { + diff --git a/backend/src/modules/iit-manager/test-iit-database.ts b/backend/src/modules/iit-manager/test-iit-database.ts index 8910877f..43291a75 100644 --- a/backend/src/modules/iit-manager/test-iit-database.ts +++ b/backend/src/modules/iit-manager/test-iit-database.ts @@ -182,5 +182,6 @@ testIitDatabase() + diff --git a/backend/src/modules/iit-manager/test-patient-wechat-config.ts b/backend/src/modules/iit-manager/test-patient-wechat-config.ts index 6131fe25..de548abe 100644 --- a/backend/src/modules/iit-manager/test-patient-wechat-config.ts +++ b/backend/src/modules/iit-manager/test-patient-wechat-config.ts @@ -168,5 +168,6 @@ if (hasError) { + diff --git a/backend/src/modules/iit-manager/test-patient-wechat-url-verify.ts b/backend/src/modules/iit-manager/test-patient-wechat-url-verify.ts index cae85043..81f6d17c 100644 --- a/backend/src/modules/iit-manager/test-patient-wechat-url-verify.ts +++ b/backend/src/modules/iit-manager/test-patient-wechat-url-verify.ts @@ -194,5 +194,6 @@ async function testUrlVerification() { + diff --git a/backend/src/modules/iit-manager/test-redcap-query-from-db.ts b/backend/src/modules/iit-manager/test-redcap-query-from-db.ts index d60c1d1f..b696405e 100644 --- a/backend/src/modules/iit-manager/test-redcap-query-from-db.ts +++ b/backend/src/modules/iit-manager/test-redcap-query-from-db.ts @@ -275,5 +275,6 @@ main().catch((error) => { + diff --git a/backend/src/modules/iit-manager/test-wechat-mp-local.ps1 b/backend/src/modules/iit-manager/test-wechat-mp-local.ps1 index 81510e9d..3f2d960f 100644 --- a/backend/src/modules/iit-manager/test-wechat-mp-local.ps1 +++ b/backend/src/modules/iit-manager/test-wechat-mp-local.ps1 @@ -159,5 +159,6 @@ Write-Host "" + diff --git a/backend/src/modules/iit-manager/types/index.ts b/backend/src/modules/iit-manager/types/index.ts index 7f9af3ce..b2c1c9b3 100644 --- a/backend/src/modules/iit-manager/types/index.ts +++ b/backend/src/modules/iit-manager/types/index.ts @@ -252,5 +252,6 @@ export interface CachedProtocolRules { + diff --git a/backend/src/modules/pkb/controllers/documentController.ts b/backend/src/modules/pkb/controllers/documentController.ts index 71785ee4..e84c1a61 100644 --- a/backend/src/modules/pkb/controllers/documentController.ts +++ b/backend/src/modules/pkb/controllers/documentController.ts @@ -1,8 +1,10 @@ import type { FastifyRequest, FastifyReply } from 'fastify'; import * as documentService from '../services/documentService.js'; import { storage } from '../../../common/storage/index.js'; +import { OSSAdapter } from '../../../common/storage/OSSAdapter.js'; import { randomUUID } from 'crypto'; import path from 'path'; +import { logger } from '../../../common/logging/index.js'; /** * 获取用户ID(从JWT Token中获取) @@ -374,4 +376,93 @@ export async function getDocumentFullText( } } +/** + * 获取文档签名URL(用于前端预览/下载) + * + * @description + * 生成一个带有过期时间的签名URL,前端可以直接使用该URL: + * - 在浏览器中预览 PDF + * - 下载文件(会恢复原始文件名) + */ +export async function getDocumentSignedUrl( + request: FastifyRequest<{ + Params: { + id: string; + }; + Querystring: { + /** 过期时间(秒),默认3600秒 */ + expires?: string; + /** 是否作为附件下载(添加 Content-Disposition),默认 false */ + download?: string; + }; + }>, + reply: FastifyReply +) { + try { + const { id } = request.params; + const expires = parseInt(request.query.expires || '3600', 10); + const download = request.query.download === 'true'; + + const userId = getUserId(request); + + // 获取文档信息 + const document = await documentService.getDocumentById(userId, id); + + // 检查是否有存储路径 + if (!document.storageKey) { + logger.warn('[PKB] 文档没有存储路径,可能是旧数据', { documentId: id }); + return reply.status(404).send({ + success: false, + message: '文档文件不可用,请重新上传', + }); + } + + // 生成签名URL + let signedUrl: string; + + // 检查存储适配器类型 + if (storage instanceof OSSAdapter) { + // OSS: 使用带原始文件名的签名URL + signedUrl = download + ? storage.getSignedUrl(document.storageKey, expires, document.filename) + : storage.getSignedUrl(document.storageKey, expires); + } else { + // 本地存储: 使用 getUrl + signedUrl = storage.getUrl(document.storageKey); + } + + logger.info('[PKB] 生成签名URL', { + documentId: id, + filename: document.filename, + expires, + download + }); + + return reply.send({ + success: true, + data: { + documentId: document.id, + filename: document.filename, + fileType: document.fileType, + url: signedUrl, + expiresIn: expires, + }, + }); + } catch (error: any) { + logger.error('[PKB] 获取签名URL失败', { error: error.message }); + + if (error.message.includes('not found') || error.message.includes('access denied')) { + return reply.status(404).send({ + success: false, + message: error.message, + }); + } + + return reply.status(500).send({ + success: false, + message: error.message || 'Failed to get signed URL', + }); + } +} + diff --git a/backend/src/modules/pkb/routes/health.ts b/backend/src/modules/pkb/routes/health.ts index b56f95e2..f32a4eb9 100644 --- a/backend/src/modules/pkb/routes/health.ts +++ b/backend/src/modules/pkb/routes/health.ts @@ -65,5 +65,6 @@ export default async function healthRoutes(fastify: FastifyInstance) { + diff --git a/backend/src/modules/pkb/routes/knowledgeBases.ts b/backend/src/modules/pkb/routes/knowledgeBases.ts index 2ed5216b..7177e271 100644 --- a/backend/src/modules/pkb/routes/knowledgeBases.ts +++ b/backend/src/modules/pkb/routes/knowledgeBases.ts @@ -44,6 +44,10 @@ export default async function knowledgeBaseRoutes(fastify: FastifyInstance) { // Phase 2: 获取文档全文 fastify.get('/documents/:id/full-text', { preHandler: [authenticate, requireModule('PKB')] }, documentController.getDocumentFullText); + // 获取文档签名URL(用于预览/下载) + // Query: ?expires=3600&download=true + fastify.get('/documents/:id/signed-url', { preHandler: [authenticate, requireModule('PKB')] }, documentController.getDocumentSignedUrl); + // 删除文档 fastify.delete('/documents/:id', { preHandler: [authenticate, requireModule('PKB')] }, documentController.deleteDocument); diff --git a/backend/src/modules/rvw/__tests__/api.http b/backend/src/modules/rvw/__tests__/api.http index b8138e81..137f03ec 100644 --- a/backend/src/modules/rvw/__tests__/api.http +++ b/backend/src/modules/rvw/__tests__/api.http @@ -143,5 +143,6 @@ Content-Type: application/json + diff --git a/backend/src/modules/rvw/__tests__/test-api.ps1 b/backend/src/modules/rvw/__tests__/test-api.ps1 index 772b5b39..2ae44ae3 100644 --- a/backend/src/modules/rvw/__tests__/test-api.ps1 +++ b/backend/src/modules/rvw/__tests__/test-api.ps1 @@ -128,5 +128,6 @@ Write-Host " - 删除任务: DELETE $BaseUrl/api/v1/rvw/tasks/{taskId}" -Foregr + diff --git a/backend/src/modules/rvw/index.ts b/backend/src/modules/rvw/index.ts index 2b715071..ac821f15 100644 --- a/backend/src/modules/rvw/index.ts +++ b/backend/src/modules/rvw/index.ts @@ -42,5 +42,6 @@ export * from './services/utils.js'; + diff --git a/backend/src/modules/rvw/services/utils.ts b/backend/src/modules/rvw/services/utils.ts index 2d8d71df..b2bd0616 100644 --- a/backend/src/modules/rvw/services/utils.ts +++ b/backend/src/modules/rvw/services/utils.ts @@ -133,5 +133,6 @@ export function validateAgentSelection(agents: string[]): void { + diff --git a/backend/src/tests/README.md b/backend/src/tests/README.md index eae948cb..aceaa45f 100644 --- a/backend/src/tests/README.md +++ b/backend/src/tests/README.md @@ -433,5 +433,6 @@ SET session_replication_role = 'origin'; + diff --git a/backend/src/tests/test-cross-language-search.ts b/backend/src/tests/test-cross-language-search.ts index 7a38ee57..1867a637 100644 --- a/backend/src/tests/test-cross-language-search.ts +++ b/backend/src/tests/test-cross-language-search.ts @@ -113,3 +113,4 @@ testCrossLanguageSearch(); + diff --git a/backend/src/tests/test-query-rewrite.ts b/backend/src/tests/test-query-rewrite.ts index 0028436d..aaf54a7a 100644 --- a/backend/src/tests/test-query-rewrite.ts +++ b/backend/src/tests/test-query-rewrite.ts @@ -175,3 +175,4 @@ testQueryRewrite(); + diff --git a/backend/src/tests/test-rerank.ts b/backend/src/tests/test-rerank.ts index 93ea3a71..41e87f48 100644 --- a/backend/src/tests/test-rerank.ts +++ b/backend/src/tests/test-rerank.ts @@ -121,3 +121,4 @@ testRerank(); + diff --git a/backend/src/tests/verify-test1-database.sql b/backend/src/tests/verify-test1-database.sql index 5203503f..3fd47718 100644 --- a/backend/src/tests/verify-test1-database.sql +++ b/backend/src/tests/verify-test1-database.sql @@ -135,5 +135,6 @@ WHERE key = 'verify_test'; + diff --git a/backend/src/tests/verify-test1-database.ts b/backend/src/tests/verify-test1-database.ts index ddd958fe..5bb64f5a 100644 --- a/backend/src/tests/verify-test1-database.ts +++ b/backend/src/tests/verify-test1-database.ts @@ -278,5 +278,6 @@ verifyDatabase() + diff --git a/backend/src/types/global.d.ts b/backend/src/types/global.d.ts index 2ee915bd..0cfe6924 100644 --- a/backend/src/types/global.d.ts +++ b/backend/src/types/global.d.ts @@ -68,5 +68,6 @@ export {} + diff --git a/backend/sync-dc-database.ps1 b/backend/sync-dc-database.ps1 index 21c9bb56..ff830387 100644 --- a/backend/sync-dc-database.ps1 +++ b/backend/sync-dc-database.ps1 @@ -91,5 +91,6 @@ Write-Host "✅ 完成!" -ForegroundColor Green + diff --git a/backend/temp_check.sql b/backend/temp_check.sql index 391e589a..8ce4f7d2 100644 --- a/backend/temp_check.sql +++ b/backend/temp_check.sql @@ -18,3 +18,4 @@ SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('p + diff --git a/backend/test-pkb-migration.http b/backend/test-pkb-migration.http index 123f0af5..e09f5525 100644 --- a/backend/test-pkb-migration.http +++ b/backend/test-pkb-migration.http @@ -179,5 +179,6 @@ DELETE {{baseUrl}}/api/v1/pkb/knowledge/knowledge-bases/{{testKbId}} + diff --git a/backend/test-tool-c-advanced-scenarios.mjs b/backend/test-tool-c-advanced-scenarios.mjs index 1e5ccf30..ac4f5f2a 100644 --- a/backend/test-tool-c-advanced-scenarios.mjs +++ b/backend/test-tool-c-advanced-scenarios.mjs @@ -378,5 +378,6 @@ runAdvancedTests().catch(error => { + diff --git a/backend/test-tool-c-day2.mjs b/backend/test-tool-c-day2.mjs index 5655344f..dcce41ed 100644 --- a/backend/test-tool-c-day2.mjs +++ b/backend/test-tool-c-day2.mjs @@ -444,5 +444,6 @@ runAllTests() + diff --git a/backend/test-tool-c-day3.mjs b/backend/test-tool-c-day3.mjs index 910ad244..328f37a9 100644 --- a/backend/test-tool-c-day3.mjs +++ b/backend/test-tool-c-day3.mjs @@ -402,5 +402,6 @@ runAllTests() + diff --git a/backend/verify_all_users.ts b/backend/verify_all_users.ts index 8dc9ed09..f5d44760 100644 --- a/backend/verify_all_users.ts +++ b/backend/verify_all_users.ts @@ -38,3 +38,4 @@ main() + diff --git a/backend/verify_functions.ts b/backend/verify_functions.ts index 640c9ced..fee43851 100644 --- a/backend/verify_functions.ts +++ b/backend/verify_functions.ts @@ -36,3 +36,4 @@ main() + diff --git a/backend/verify_job_common.ts b/backend/verify_job_common.ts index 1665063d..79b89a65 100644 --- a/backend/verify_job_common.ts +++ b/backend/verify_job_common.ts @@ -48,3 +48,4 @@ main() + diff --git a/backend/verify_mock_user.ts b/backend/verify_mock_user.ts index b184aabf..d7db66df 100644 --- a/backend/verify_mock_user.ts +++ b/backend/verify_mock_user.ts @@ -37,3 +37,4 @@ main() + diff --git a/backend/verify_system.ts b/backend/verify_system.ts index b3180522..d3486f86 100644 --- a/backend/verify_system.ts +++ b/backend/verify_system.ts @@ -177,3 +177,4 @@ main() + diff --git a/deploy-to-sae.ps1 b/deploy-to-sae.ps1 index 359fbc87..53607c98 100644 --- a/deploy-to-sae.ps1 +++ b/deploy-to-sae.ps1 @@ -186,5 +186,6 @@ Set-Location .. + diff --git a/docs/01-平台基础层/02-存储服务/OSS账号与配置信息.md b/docs/01-平台基础层/02-存储服务/OSS账号与配置信息.md index 7377a45c..3bc4a2bb 100644 --- a/docs/01-平台基础层/02-存储服务/OSS账号与配置信息.md +++ b/docs/01-平台基础层/02-存储服务/OSS账号与配置信息.md @@ -163,3 +163,4 @@ npm run dev *文档结束。如有问题请联系:gofeng117@163.com* + diff --git a/docs/01-平台基础层/02-存储服务/OSS集成开发记录-2026-01-22.md b/docs/01-平台基础层/02-存储服务/OSS集成开发记录-2026-01-22.md index dd0b8db5..6e3a9d27 100644 --- a/docs/01-平台基础层/02-存储服务/OSS集成开发记录-2026-01-22.md +++ b/docs/01-平台基础层/02-存储服务/OSS集成开发记录-2026-01-22.md @@ -190,3 +190,4 @@ OSS_INTERNAL=false # 本地开发用公网,生产用内网 - 审核:用户 + diff --git a/docs/02-通用能力层/03-RAG引擎/05-RAG引擎使用指南.md b/docs/02-通用能力层/03-RAG引擎/05-RAG引擎使用指南.md index 259e997d..be268e30 100644 --- a/docs/02-通用能力层/03-RAG引擎/05-RAG引擎使用指南.md +++ b/docs/02-通用能力层/03-RAG引擎/05-RAG引擎使用指南.md @@ -560,3 +560,4 @@ npx tsx src/tests/test-pdf-ingest.ts + diff --git a/docs/02-通用能力层/03-RAG引擎/06-pg_bigm安装指南.md b/docs/02-通用能力层/03-RAG引擎/06-pg_bigm安装指南.md new file mode 100644 index 00000000..475442ee --- /dev/null +++ b/docs/02-通用能力层/03-RAG引擎/06-pg_bigm安装指南.md @@ -0,0 +1,212 @@ +# pg_bigm 安装指南 + +> **版本:** v1.0 +> **日期:** 2026-01-23 +> **状态:** 待部署 +> **用途:** 优化中文关键词检索性能 + +--- + +## 📋 概述 + +pg_bigm 是 PostgreSQL 的全文搜索扩展,专门针对中日韩(CJK)字符优化。相比原生 LIKE/ILIKE,pg_bigm 提供: + +- **2-gram 索引**:将文本拆分为连续的 2 字符片段,支持任意子串匹配 +- **中文友好**:原生支持中文分词,无需额外配置 +- **性能提升**:10-100x 性能提升(取决于数据量) +- **模糊搜索**:支持相似度搜索 + +--- + +## 🚀 安装步骤 + +### 方案 1:Docker 镜像升级(推荐) + +**适用场景**:本地开发环境 + +```bash +cd AIclinicalresearch + +# 1. 备份现有数据 +docker exec ai-clinical-postgres pg_dump -U postgres -d ai_clinical_research > backup_$(date +%Y%m%d_%H%M%S).sql + +# 2. 构建新镜像(包含 pgvector + pg_bigm) +docker build -f Dockerfile.postgres-with-extensions -t ai-clinical-postgres:v1.1 . + +# 3. 停止现有容器 +docker compose down + +# 4. 修改 docker-compose.yml,替换镜像 +# image: pgvector/pgvector:pg15 → image: ai-clinical-postgres:v1.1 + +# 5. 启动新容器 +docker compose up -d + +# 6. 验证扩展安装 +docker exec ai-clinical-postgres psql -U postgres -d ai_clinical_research -c "SELECT extname, extversion FROM pg_extension;" +``` + +**预期输出**: +``` + extname | extversion +----------+------------ + plpgsql | 1.0 + vector | 0.8.0 + pg_bigm | 1.2 +``` + +### 方案 2:在现有容器中安装 + +**适用场景**:不想重建镜像 + +```bash +# 1. 进入容器 +docker exec -it ai-clinical-postgres bash + +# 2. 安装编译工具 +apt-get update && apt-get install -y build-essential postgresql-server-dev-15 wget + +# 3. 下载并编译 pg_bigm +cd /tmp +wget https://github.com/pgbigm/pg_bigm/archive/refs/tags/v1.2-20200228.tar.gz +tar -xzf v1.2-20200228.tar.gz +cd pg_bigm-1.2-20200228 +make USE_PGXS=1 +make USE_PGXS=1 install + +# 4. 清理 +rm -rf /tmp/pg_bigm* /tmp/v1.2-20200228.tar.gz +apt-get purge -y build-essential postgresql-server-dev-15 wget +apt-get autoremove -y + +# 5. 退出容器 +exit + +# 6. 创建扩展 +docker exec ai-clinical-postgres psql -U postgres -d ai_clinical_research -c "CREATE EXTENSION IF NOT EXISTS pg_bigm;" +``` + +### 方案 3:阿里云 RDS + +**适用场景**:生产环境(阿里云 RDS PostgreSQL) + +阿里云 RDS PostgreSQL 15 **已内置** pg_bigm,只需执行: + +```sql +-- 连接到 RDS 数据库 +CREATE EXTENSION IF NOT EXISTS pg_bigm; +``` + +--- + +## 🔧 使用方法 + +### 1. 创建 GIN 索引 + +```sql +-- 为 ekb_chunk 表的 content 列创建 pg_bigm 索引 +CREATE INDEX IF NOT EXISTS idx_ekb_chunk_content_bigm +ON ekb_schema.ekb_chunk +USING gin (content gin_bigm_ops); + +-- 验证索引创建 +SELECT indexname, indexdef FROM pg_indexes +WHERE tablename = 'ekb_chunk' AND indexname LIKE '%bigm%'; +``` + +### 2. 查询示例 + +```sql +-- 基本查询(使用索引) +SELECT * FROM ekb_schema.ekb_chunk +WHERE content LIKE '%银杏叶%'; + +-- 相似度查询 +SELECT *, bigm_similarity(content, '银杏叶副作用') AS similarity +FROM ekb_schema.ekb_chunk +WHERE content LIKE '%银杏叶%' +ORDER BY similarity DESC +LIMIT 10; +``` + +### 3. 在 VectorSearchService 中使用 + +```typescript +// keywordSearch 方法会自动检测 pg_bigm +// 如果扩展可用,使用 GIN 索引加速 +// 否则 fallback 到 ILIKE + +async keywordSearch(query: string, options: SearchOptions) { + // 自动使用最优方案 + // pg_bigm: SELECT * WHERE content LIKE '%query%' (使用索引) + // fallback: SELECT * WHERE content ILIKE '%query%' (全表扫描) +} +``` + +--- + +## 📊 性能对比 + +| 场景 | ILIKE(无索引) | pg_bigm(GIN索引) | 提升 | +|------|----------------|-------------------|------| +| 10万条记录 | 500ms | 5ms | 100x | +| 100万条记录 | 5s | 50ms | 100x | +| 中文2字符 | 支持 | 支持 | - | +| 中文1字符 | 支持 | 不支持* | - | + +> *pg_bigm 基于 2-gram,单字符查询需要至少2个字符 + +--- + +## ⚠️ 注意事项 + +### 1. 索引大小 + +pg_bigm 的 GIN 索引会占用额外存储空间: + +```sql +-- 查看索引大小 +SELECT pg_size_pretty(pg_relation_size('idx_ekb_chunk_content_bigm')); +``` + +预估:原始数据的 50%-100% + +### 2. 写入性能 + +GIN 索引会影响写入性能: + +- INSERT:约慢 20-30% +- UPDATE content 字段:约慢 30-50% + +**建议**:批量写入时可临时禁用索引 + +### 3. 最小查询长度 + +pg_bigm 基于 2-gram,单字符查询效果差: + +```sql +-- ❌ 效果差 +SELECT * WHERE content LIKE '%癌%'; + +-- ✅ 效果好 +SELECT * WHERE content LIKE '%肺癌%'; +``` + +--- + +## 🔗 相关文档 + +- [pg_bigm 官方文档](https://pgbigm.osdn.jp/pg_bigm_en-1-2.html) +- [RAG 引擎使用指南](./05-RAG引擎使用指南.md) +- [pgvector 替换 Dify 计划](./02-pgvector替换Dify计划.md) + +--- + +## 📅 更新计划 + +1. ✅ 创建 Dockerfile 和初始化脚本 +2. ⏳ 本地环境测试 +3. ⏳ 更新 VectorSearchService 使用 pg_bigm +4. ⏳ 生产环境部署(阿里云 RDS) +5. ⏳ 创建索引并验证性能 + diff --git a/docs/02-通用能力层/Postgres-Only异步任务处理指南.md b/docs/02-通用能力层/Postgres-Only异步任务处理指南.md index f5b3047f..c29e15e9 100644 --- a/docs/02-通用能力层/Postgres-Only异步任务处理指南.md +++ b/docs/02-通用能力层/Postgres-Only异步任务处理指南.md @@ -1,10 +1,13 @@ # Postgres-Only 异步任务处理指南 -> **文档版本:** v1.0 +> **文档版本:** v1.1(2026-01-23 安全规范更新) > **创建日期:** 2025-12-22 +> **最后更新:** 2026-01-23 > **维护者:** 平台架构团队 > **适用场景:** 长时间任务(>30秒)、大文件处理、后台Worker > **参考实现:** DC Tool C Excel解析、ASL文献筛选、DC Tool B数据提取 +> +> ⚠️ **重要更新 v1.1**:新增[🛡️ 安全规范](#-安全规范强制)章节,包含幂等性、错误处理等强制规范 --- @@ -537,6 +540,160 @@ async saveProcessedData(recordId, newData) { --- +## 🛡️ 安全规范(强制) + +> **更新日期**:2026-01-23 +> **来源**:内部逆向审查报告 + 生产问题修复 + +基于项目实际遇到的问题,以下规范 **必须遵守**: + +### 规范1:禁止 Worker 递归死循环 ❌ + +**错误示例**: +```typescript +// ❌ 禁止:在 catch 块中重试业务逻辑 +jobQueue.process('your_task', async (job) => { + try { + await doSomething(job.data); + } catch (error) { + // ❌ 错误!这会导致死循环或重复执行 + await doSomething(job.data); + throw error; + } +}); +``` + +**正确做法**: +```typescript +// ✅ 正确:直接 throw,让 pg-boss 接管重试(默认3次) +jobQueue.process('your_task', async (job) => { + try { + await doSomething(job.data); + } catch (error) { + logger.error('Job failed', { jobId: job.id, error: error.message }); + throw error; // ✅ pg-boss 会自动重试 + } +}); +``` + +--- + +### 规范2:禁止 Payload 膨胀 ❌ + +**错误示例**: +```typescript +// ❌ 禁止:在 job.data 中存大文件 +await jobQueue.push('parse_excel', { + fileContent: base64EncodedFile, // ❌ 会导致 job 表膨胀 + imageData: base64Image, // ❌ 拖慢数据库 +}); +``` + +**正确做法**: +```typescript +// ✅ 正确:只存 fileKey 或数据库 ID +await jobQueue.push('parse_excel', { + sessionId: session.id, // ✅ 只存 ID + fileKey: 'path/to/file', // ✅ 只存 OSS 路径 + userId: 'user-123', +}); +``` + +--- + +### 规范3:Worker 必须幂等 ⭐ + +**问题**:任务失败重试时,可能导致重复写入、重复扣费、重复发邮件。 + +**错误示例**: +```typescript +// ❌ 非幂等:重试会创建多条记录 +await prisma.screeningResult.create({ + data: { projectId, literatureId, result } +}); +``` + +**正确做法**: +```typescript +// ✅ 方案1:使用 upsert + 唯一约束 +await prisma.screeningResult.upsert({ + where: { + projectId_literatureId: { projectId, literatureId } + }, + create: { projectId, literatureId, result }, + update: { result }, // 重试时覆盖 +}); + +// ✅ 方案2:先检查状态再执行 +const existing = await prisma.task.findUnique({ where: { id: taskId } }); +if (existing?.status === 'completed') { + logger.info('Task already completed, skipping'); + return; +} +await doWork(); +``` + +**幂等性检查清单**: +| 操作类型 | 幂等方案 | +|---------|---------| +| 创建记录 | 使用 `upsert` + 唯一约束 | +| 更新记录 | `update` 天然幂等 | +| 发送邮件 | 先检查 `notificationSent` 标志 | +| 扣费 | 使用幂等 key(如订单号) | +| 调用外部API | 检查是否已成功 | + +--- + +### 规范4:合理设置任务过期时间 + +**默认配置**(当前): +```typescript +expireInSeconds: 6 * 60 * 60 // 6小时 +``` + +**推荐配置**(按业务类型): +| 任务类型 | 过期时间 | 理由 | +|---------|---------|------| +| `asl_screening_batch` | 30分钟 | 单条文献筛选 | +| `dc_extraction_batch` | 1小时 | 批量数据提取 | +| `dc_toolc_parse_excel` | 30分钟 | Excel解析 | +| `rvw_review_task` | 20分钟 | 审稿任务 | +| `asl_research_execute` | 30分钟 | DeepSearch检索 | + +--- + +### 规范5:优雅关闭 ✅ + +**已在 `index.ts` 实现**: +```typescript +// 进程退出时优雅关闭 +process.on('SIGTERM', async () => { + await fastify.close(); // 停止接收新请求 + await jobQueue.stop(); // 等待当前任务完成 + await prisma.$disconnect(); // 关闭数据库 + process.exit(0); +}); +``` + +--- + +### 规范6:全局错误监听 ✅ + +**已在 `PgBossQueue.ts` 实现**: +```typescript +// 防止未捕获错误导致进程崩溃 +this.boss.on('error', (err) => { + if (err.code === '23505' && err.constraint === 'queue_pkey') { + // 队列冲突,静默处理 + console.log('Queue concurrency conflict auto-resolved'); + } else { + console.error('PgBoss critical error:', err); + } +}); +``` + +--- + ## ⚠️ 常见问题 ### Q1: Worker 注册了但不工作? @@ -569,7 +726,7 @@ async saveProcessedData(recordId, newData) { ## ✅ 检查清单 -在实施异步任务前,请确认: +### 基础配置检查 - [ ] 业务表只存业务信息(不包含 status 等字段) - [ ] 队列名称使用下划线(不含冒号) @@ -579,11 +736,49 @@ async saveProcessedData(recordId, newData) { - [ ] Service 优先读取 clean data - [ ] saveProcessedData 同步更新 clean data +### 🛡️ 安全规范检查(强制) + +- [ ] **幂等性**:使用 `upsert` 或先检查状态,确保重试安全 +- [ ] **Payload**:`job.data` 只存 ID 和 fileKey,不存大文件 +- [ ] **错误处理**:catch 块中直接 `throw error`,不要重试业务逻辑 +- [ ] **唯一约束**:数据库表有合适的唯一索引防止重复写入 +- [ ] **过期时间**:根据业务类型设置合理的 `expireInSeconds` + +--- + +## 📊 故障排查 SQL + +```sql +-- 查看队列健康状况 +SELECT + name AS queue_name, + state, + COUNT(*) AS count +FROM platform_schema.job +WHERE created_on > NOW() - INTERVAL '24 hours' +GROUP BY name, state +ORDER BY name, state; + +-- 查看失败任务 +SELECT id, name, data, output, created_on +FROM platform_schema.job +WHERE state = 'failed' +ORDER BY created_on DESC +LIMIT 10; + +-- 查看卡住的任务(processing 超过1小时) +SELECT id, name, data, created_on, started_on +FROM platform_schema.job +WHERE state = 'active' + AND started_on < NOW() - INTERVAL '1 hour'; +``` + --- **维护者**: 平台架构团队 -**最后更新**: 2025-12-22 -**文档状态**: ✅ 已完成 +**最后更新**: 2026-01-23 +**文档状态**: ✅ 已完成(v1.1 安全规范更新) + diff --git a/docs/02-通用能力层/快速引用卡片.md b/docs/02-通用能力层/快速引用卡片.md index d31055c6..569b7a8f 100644 --- a/docs/02-通用能力层/快速引用卡片.md +++ b/docs/02-通用能力层/快速引用卡片.md @@ -238,3 +238,4 @@ const userId = 'test'; // ❌ 应该用 getUserId(request) + diff --git a/docs/02-通用能力层/技术方案文档_Postgres-Only队列架构优化方案 (1).md b/docs/02-通用能力层/技术方案文档_Postgres-Only队列架构优化方案 (1).md new file mode 100644 index 00000000..794f3a7e --- /dev/null +++ b/docs/02-通用能力层/技术方案文档_Postgres-Only队列架构优化方案 (1).md @@ -0,0 +1,229 @@ +# **Postgres-Only 队列架构治理与异步决策指南** + +**文档版本:** v1.2 (Review版) **面向对象:** 后端开发团队 (2人) **核心目标:** 解决并发冲突,规避异步陷阱,建立低成本运维标准 + +**适用架构:** Node.js \+ PostgreSQL \+ pg-boss (无 Redis) + +## **1\. 现状与痛点分析** + +### **1.1 当前架构背景** + +我们采用了极简的 **Postgres-Only** 架构,利用 pg-boss 实现异步任务队列。这对于我们 2 人团队非常有利,因为: + +* **运维成本低**:不需要维护 Redis 或 RabbitMQ。 +* **事务一致性**:任务数据与业务数据在同一个数据库,天然支持事务。 +* **部署简单**:一个 Docker 容器搞定所有状态存储。 + +### **1.2 遇到的技术问题** + +在开发环境(Nodemon 热重载)或生产环境(多实例部署)启动时,频发以下错误: + +error: duplicate key value violates unique constraint "queue\_pkey" +Key (name)=(asl\_research\_execute) already exists. + +**根本原因:** 典型的竞争条件 (Race Condition)。多个进程同时尝试初始化队列,触发数据库唯一约束。 + +## **2\. 核心技术方案:健壮的单例模式** + +为了解决报错并防止资源泄露,我们需要对 pg-boss 进行**防御性封装**。 + +### **2.1 标准代码实现 (backend/services/queueService.js)** + +**⚠️ 重大更新**:增加了连接池限制 (max: 2),防止搞挂 RDS。 + +import PgBoss from 'pg-boss'; +import { logger } from '@/common/logging'; + +class QueueService { + constructor() { + this.boss \= null; + this.isReady \= false; + this.isStarting \= false; + } + + /\*\* + \* 核心:初始化与错误监听 + \*/ + async init(connectionString) { + if (this.boss || this.isStarting) return; + this.isStarting \= true; + + try { + this.boss \= new PgBoss({ + connectionString, + application\_name: 'ai\_clinical\_queue', + retentionDays: 7, + maxTries: 3, + // 🛡️ \[逆向防御\]:限制连接池大小 + // pg-boss 默认至少需要 2-4 个连接。 + // 我们显式限制为 4,防止挤占 Prisma 的连接配额 (RDS通常限制 100\) + max: 4, + }); + + // 🛡️ \[逆向防御\]:监听全局错误,防止进程崩溃 + this.boss.on('error', (err) \=\> { + if (this.\_isDuplicateKeyError(err)) { + logger.warn(\`\[Queue\] Concurrency conflict auto-resolved: ${err.detail}\`); + } else { + logger.error('\[Queue\] PgBoss critical error:', err); + // TODO: 这里可以接入飞书/钉钉 Webhook 告警 + } + }); + + await this.boss.start(); + this.isReady \= true; + this.isStarting \= false; + logger.info('✅ Queue Service started successfully'); + + } catch (err) { + this.isStarting \= false; + logger.error('❌ Failed to start Queue Service:', err); + throw err; + } + } + + /\*\* + \* 封装:安全地发布任务 + \*/ + async publish(queueName, data, options \= {}) { + await this.\_ensureReady(); + await this.\_ensureQueueExists(queueName); + + try { + return await this.boss.send(queueName, data, options); + } catch (err) { + logger.error(\`❌ Failed to publish to ${queueName}:\`, err); + // 🛡️ \[逆向防御\]:这里是否需要抛出错误取决于业务? + // 建议抛出,让上层业务感知到任务提交失败 + throw err; + } + } + + /\*\* + \* 封装:Worker 注册 + \*/ + async subscribe(queueName, handler) { + await this.\_ensureReady(); + await this.\_ensureQueueExists(queueName); + + // 🛡️ \[逆向防御\]:包裹 handler,捕获未处理的异常,防止 Worker 僵死 + const safeHandler \= async (job) \=\> { + try { + logger.info(\`🔄 Processing job ${job.id} \[${queueName}\]\`); + return await handler(job); + } catch (err) { + logger.error(\`❌ Job ${job.id} failed:\`, err); + throw err; // 抛出给 pg-boss 进行重试 + } + }; + + await this.boss.work(queueName, safeHandler); + logger.info(\`👷 Worker registered: ${queueName}\`); + } + + async shutdown() { + if (this.boss) { + await this.boss.stop(); + this.boss \= null; + this.isReady \= false; + } + } + + // \--- 私有辅助方法 \--- + + async \_ensureQueueExists(queueName) { + try { + await this.boss.createQueue(queueName); + } catch (err) { + if (\!this.\_isDuplicateKeyError(err)) throw err; + } + } + + \_isDuplicateKeyError(err) { + return err.code \=== '23505' && err.constraint \=== 'queue\_pkey'; + } + + async \_ensureReady() { + if (\!this.isReady && \!this.isStarting) { + await this.init(process.env.DATABASE\_URL); + } + if (\!this.isReady) throw new Error('QueueService not initialized'); + } +} + +export const queueService \= new QueueService(); + +## **3\. 架构决策:什么时候该用异步?** + +作为 2 人团队,维护异步队列有显著的隐性成本。原则:**默认同步,按需异步。** + +### **3.1 坚决【不使用】异步的场景** + +* **短时间 AI 交互 (\< 20秒)**:用 SSE 流式响应。 +* **简单 CRUD**:直接 await。 +* **强实时反馈**:如 REDCap Webhook。 + +### **3.2 【必须】使用异步的场景** + +* **大文件解析 (DC 模块)**:防止 HTTP Timeout。 +* **长时外部 API (ASL 模块)**:DeepSearch 检索。 +* **高并发削峰**:批量导入。 + +## **4\. 最佳实践:智能混合模式 (Smart Hybrid Strategy)** + +### **4.1 ⚠️ 逆向风险:代码分裂 (Code Divergence)** + +**风险**:如果同步逻辑写一份,异步 Worker 里又复制粘贴一份。一旦业务修改,很容易“改了同步忘了异步”,导致 Bug。 **解法**:**业务逻辑必须原子化**。 + +### **4.2 正确的代码范例** + +// backend/src/modules/dc/services/coreLogic.ts +// 1\. 核心逻辑剥离:这是一个纯函数,不关心它是被 HTTP 调用的还是被 Worker 调用的 +export async function extractDataCore(fileBuffer: Buffer) { + // ...复杂的解析逻辑... + return result; +} + +// backend/src/modules/dc/services/extractionService.ts +import { extractDataCore } from './coreLogic'; + +async function processData(data: any\[\]) { + // 🟢 场景 A:同步处理 + if (data.length \< 50\) { + // 直接调用核心逻辑 + return await extractDataCore(data); + } + + // 🟠 场景 B:异步队列 + else { + // 仅仅是发布任务,任务载荷里只存必要参数 + const jobId \= await queueService.publish('dc\_process\_batch', data); + return { status: 'queued', jobId }; + } +} + +// backend/src/workers/dcWorker.ts +import { extractDataCore } from '../modules/dc/services/coreLogic'; + +// Worker 也调用同一个核心逻辑 +queueService.subscribe('dc\_process\_batch', async (job) \=\> { + return await extractDataCore(job.data); +}); + +## **5\. 开发规范** + +### **5.1 命名规范** + +* ✅ **推荐**:模块\_动作 (如 asl\_screening\_task) +* ❌ **禁止**:冒号 : 或点号 . + +### **5.2 Postgres-Only 特有技巧** + +利用 **事务一致性**。在 Postgres-Only 架构中,尽量让任务发布与业务数据写入在同一个事务中(如果 ORM 支持),确保不丢任务。 + +## **6\. 故障排查与监控 (SQL)** + +因为没有 Redis GUI,使用 SQL 监控: + +\-- 查看失败任务 +SELECT id, name, data, output, created\_on FROM platform\_schema.job WHERE state \= 'failed' LIMIT 10; diff --git a/docs/02-通用能力层/通用能力层技术债务清单.md b/docs/02-通用能力层/通用能力层技术债务清单.md index 45c88e23..04968f97 100644 --- a/docs/02-通用能力层/通用能力层技术债务清单.md +++ b/docs/02-通用能力层/通用能力层技术债务清单.md @@ -812,5 +812,6 @@ export const AsyncProgressBar: React.FC = ({ + diff --git a/docs/03-业务模块/ADMIN-运营管理端/00-Phase3.5完成总结.md b/docs/03-业务模块/ADMIN-运营管理端/00-Phase3.5完成总结.md index 093d8d19..04b7e8ae 100644 --- a/docs/03-业务模块/ADMIN-运营管理端/00-Phase3.5完成总结.md +++ b/docs/03-业务模块/ADMIN-运营管理端/00-Phase3.5完成总结.md @@ -307,3 +307,4 @@ Level 3: 兜底Prompt(缓存也失效) + diff --git a/docs/03-业务模块/ADMIN-运营管理端/06-开发记录/2026-01-16_用户管理功能与模块权限系统完成.md b/docs/03-业务模块/ADMIN-运营管理端/06-开发记录/2026-01-16_用户管理功能与模块权限系统完成.md index 5066136a..8862b20d 100644 --- a/docs/03-业务模块/ADMIN-运营管理端/06-开发记录/2026-01-16_用户管理功能与模块权限系统完成.md +++ b/docs/03-业务模块/ADMIN-运营管理端/06-开发记录/2026-01-16_用户管理功能与模块权限系统完成.md @@ -493,3 +493,4 @@ const pageSize = Number(query.pageSize) || 20; + diff --git a/docs/03-业务模块/ADMIN-运营管理端/README.md b/docs/03-业务模块/ADMIN-运营管理端/README.md index 7a1cd0a2..1e0837f5 100644 --- a/docs/03-业务模块/ADMIN-运营管理端/README.md +++ b/docs/03-业务模块/ADMIN-运营管理端/README.md @@ -227,3 +227,4 @@ ADMIN-运营管理端/ + diff --git a/docs/03-业务模块/ADMIN运营与INST机构管理端-文档体系建立完成.md b/docs/03-业务模块/ADMIN运营与INST机构管理端-文档体系建立完成.md index d0c3bc39..d239c22b 100644 --- a/docs/03-业务模块/ADMIN运营与INST机构管理端-文档体系建立完成.md +++ b/docs/03-业务模块/ADMIN运营与INST机构管理端-文档体系建立完成.md @@ -326,3 +326,4 @@ INST-机构管理端/ + diff --git a/docs/03-业务模块/AIA-AI智能问答/04-开发计划/03-前端组件设计.md b/docs/03-业务模块/AIA-AI智能问答/04-开发计划/03-前端组件设计.md index 9a7e9ab3..332b6923 100644 --- a/docs/03-业务模块/AIA-AI智能问答/04-开发计划/03-前端组件设计.md +++ b/docs/03-业务模块/AIA-AI智能问答/04-开发计划/03-前端组件设计.md @@ -893,3 +893,4 @@ export interface SlashCommand { + diff --git a/docs/03-业务模块/AIA-AI智能问答/06-开发记录/2026-01-18-Prompt管理系统集成.md b/docs/03-业务模块/AIA-AI智能问答/06-开发记录/2026-01-18-Prompt管理系统集成.md index 5863fd70..16f28cbb 100644 --- a/docs/03-业务模块/AIA-AI智能问答/06-开发记录/2026-01-18-Prompt管理系统集成.md +++ b/docs/03-业务模块/AIA-AI智能问答/06-开发记录/2026-01-18-Prompt管理系统集成.md @@ -198,3 +198,4 @@ export type AgentStage = 'topic' | 'design' | 'review' | 'data' | 'writing'; + diff --git a/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md b/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md index ca5b5c69..6fcd365d 100644 --- a/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md +++ b/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md @@ -1305,5 +1305,6 @@ interface FulltextScreeningResult { + diff --git a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md index 08cd9f22..4c9dad2d 100644 --- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md +++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md @@ -419,5 +419,6 @@ GET /api/v1/asl/fulltext-screening/tasks/:taskId/export + diff --git a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md index ce641d50..81ff31c0 100644 --- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md +++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md @@ -362,5 +362,6 @@ Linter错误:0个 + diff --git a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md index da0715b2..bab872e2 100644 --- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md +++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-23_Day5_全文复筛API开发.md @@ -521,5 +521,6 @@ Failed to open file '\\tmp\\extraction_service\\temp_10000_test.pdf' + diff --git a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2026-01-18_智能文献检索DeepSearch集成.md b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2026-01-18_智能文献检索DeepSearch集成.md index fead4e64..8b62a989 100644 --- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2026-01-18_智能文献检索DeepSearch集成.md +++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2026-01-18_智能文献检索DeepSearch集成.md @@ -179,3 +179,4 @@ UNIFUNCS_API_KEY=sk-xxxx + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md index 3cdb6869..d7e4e2dd 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md @@ -587,5 +587,6 @@ df['creatinine'] = pd.to_numeric(df['creatinine'], errors='coerce') + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Bug修复总结_2025-12-08.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Bug修复总结_2025-12-08.md index 30833726..f68752ba 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Bug修复总结_2025-12-08.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Bug修复总结_2025-12-08.md @@ -425,5 +425,6 @@ npm run dev + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md index 4e4d53ff..1345718e 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md @@ -1002,5 +1002,6 @@ export const aiController = new AIController(); + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day4-5前端开发计划.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day4-5前端开发计划.md index 0154eb47..9a98acc7 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day4-5前端开发计划.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day4-5前端开发计划.md @@ -1336,5 +1336,6 @@ npm install react-markdown + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md index 7123b5a8..9281527e 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md @@ -244,5 +244,6 @@ FMA___基线 | FMA___1个月 | FMA___2个月 + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_方案B实施总结_2025-12-09.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_方案B实施总结_2025-12-09.md index 0dc46d91..68a20353 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_方案B实施总结_2025-12-09.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_方案B实施总结_2025-12-09.md @@ -402,5 +402,6 @@ formula = "FMA总分(0-100) / 100" + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md index f9b10b7e..828924c8 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md @@ -236,5 +236,6 @@ async handleFillnaMice(request, reply) { + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md index 8d2ccced..59044c27 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md @@ -208,5 +208,6 @@ method: 'mean' | 'median' | 'mode' | 'constant' | 'ffill' | 'bfill' + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md index 1bb416f6..c5c04b89 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md @@ -358,5 +358,6 @@ Changes: + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day1开发完成总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day1开发完成总结.md index 9688b721..7f631dc1 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day1开发完成总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day1开发完成总结.md @@ -430,5 +430,6 @@ cd path; command + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day2开发完成总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day2开发完成总结.md index c2084441..73228f47 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day2开发完成总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day2开发完成总结.md @@ -659,5 +659,6 @@ import { logger } from '../../../../common/logging/index.js'; + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_AI对话核心功能增强总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_AI对话核心功能增强总结.md index 1425db6c..e5c0717f 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_AI对话核心功能增强总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_AI对话核心功能增强总结.md @@ -663,5 +663,6 @@ Content-Length: 45234 + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md index 5362d645..b9903b40 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md @@ -315,5 +315,6 @@ Response: + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5_Ant-Design-X重构完成.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5_Ant-Design-X重构完成.md index 03bd852c..7b09f404 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5_Ant-Design-X重构完成.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5_Ant-Design-X重构完成.md @@ -468,5 +468,6 @@ Response: + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md index b5405fc3..9868fe93 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md @@ -462,5 +462,6 @@ import { ChatContainer } from '@/shared/components/Chat'; + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_UI优化与Bug修复.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_UI优化与Bug修复.md index 6a98c902..688ddec4 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_UI优化与Bug修复.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_UI优化与Bug修复.md @@ -372,5 +372,6 @@ const initialMessages = defaultMessages.length > 0 ? defaultMessages : [{ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_后端API完整对接完成.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_后端API完整对接完成.md index c05b6e0b..d3b4078b 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_后端API完整对接完成.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_后端API完整对接完成.md @@ -412,5 +412,6 @@ python main.py + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_完整UI优化与功能增强.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_完整UI优化与功能增强.md index 99c49818..f9be9baf 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_完整UI优化与功能增强.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_完整UI优化与功能增强.md @@ -660,5 +660,6 @@ http://localhost:5173/data-cleaning/tool-c + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_工具C_Day4前端基础完成.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_工具C_Day4前端基础完成.md index 3227fd02..b183eafa 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_工具C_Day4前端基础完成.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_工具C_Day4前端基础完成.md @@ -270,5 +270,6 @@ Day 5 (6-8小时): + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md index 78b1f01b..242a7159 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md @@ -448,5 +448,6 @@ Docs: docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建 + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md index bb85c37a..962b23ce 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md @@ -423,5 +423,6 @@ const mockAssets: Asset[] = [ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md index 63917139..847edf48 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md @@ -407,5 +407,6 @@ frontend-v2/src/modules/dc/ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md index 63c9bec3..66617076 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md @@ -367,5 +367,6 @@ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md index c29cc71e..6199fd55 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Tool-B-MVP完成总结-2025-12-03.md @@ -321,5 +321,6 @@ ConflictDetectionService // 冲突检测(字段级对比) + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md index adb6e249..25b36b97 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md @@ -370,5 +370,6 @@ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md index 8a16e6c6..e08227ca 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-Round2-2025-12-03.md @@ -333,5 +333,6 @@ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md index 95bec4a0..cb663fe9 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md @@ -397,5 +397,6 @@ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md index 7ed23bf0..a625165c 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md @@ -485,5 +485,6 @@ Tool B后端代码**100%复用**了平台通用能力层,无任何重复开发 + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md index 889f6ea8..00e16a71 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md @@ -331,5 +331,6 @@ + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md index cfde6bac..992bb1c8 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md @@ -262,5 +262,6 @@ $ node scripts/check-dc-tables.mjs + diff --git a/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md b/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md index dfc6c34b..848229fd 100644 --- a/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md +++ b/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md @@ -495,5 +495,6 @@ ${fields.map((f, i) => `${i + 1}. ${f.name}:${f.desc}`).join('\n')} + diff --git a/docs/03-业务模块/IIT Manager Agent/02-技术设计/IIT Manager Agent 技术路径与架构设计.md b/docs/03-业务模块/IIT Manager Agent/02-技术设计/IIT Manager Agent 技术路径与架构设计.md index c60e8678..88a78bec 100644 --- a/docs/03-业务模块/IIT Manager Agent/02-技术设计/IIT Manager Agent 技术路径与架构设计.md +++ b/docs/03-业务模块/IIT Manager Agent/02-技术设计/IIT Manager Agent 技术路径与架构设计.md @@ -700,5 +700,6 @@ private async processMessageAsync(xmlData: any) { + diff --git a/docs/03-业务模块/IIT Manager Agent/04-开发计划/REDCap对接技术方案与实施指南.md b/docs/03-业务模块/IIT Manager Agent/04-开发计划/REDCap对接技术方案与实施指南.md index 57646798..5af5871b 100644 --- a/docs/03-业务模块/IIT Manager Agent/04-开发计划/REDCap对接技术方案与实施指南.md +++ b/docs/03-业务模块/IIT Manager Agent/04-开发计划/REDCap对接技术方案与实施指南.md @@ -1094,5 +1094,6 @@ async function testIntegration() { + diff --git a/docs/03-业务模块/IIT Manager Agent/04-开发计划/企业微信注册指南.md b/docs/03-业务模块/IIT Manager Agent/04-开发计划/企业微信注册指南.md index 30c9feec..15aa8896 100644 --- a/docs/03-业务模块/IIT Manager Agent/04-开发计划/企业微信注册指南.md +++ b/docs/03-业务模块/IIT Manager Agent/04-开发计划/企业微信注册指南.md @@ -235,5 +235,6 @@ Content-Type: application/json + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/2026-01-04-Dify知识库集成开发记录.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/2026-01-04-Dify知识库集成开发记录.md index 47e2f19c..9465c8a3 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/2026-01-04-Dify知识库集成开发记录.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/2026-01-04-Dify知识库集成开发记录.md @@ -655,5 +655,6 @@ REDCap API: exportRecords success { recordCount: 1 } + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day2-REDCap实时集成开发完成记录.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day2-REDCap实时集成开发完成记录.md index 1a8701e5..e2bb0443 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day2-REDCap实时集成开发完成记录.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day2-REDCap实时集成开发完成记录.md @@ -661,5 +661,6 @@ backend/src/modules/iit-manager/ + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成与端到端测试完成记录.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成与端到端测试完成记录.md index 2b686857..383b1ffd 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成与端到端测试完成记录.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成与端到端测试完成记录.md @@ -811,5 +811,6 @@ CREATE TABLE iit_schema.wechat_tokens ( + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成开发完成记录.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成开发完成记录.md index 62001551..3072b7f1 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成开发完成记录.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成开发完成记录.md @@ -568,5 +568,6 @@ Day 3 的开发工作虽然遇到了多个技术问题,但最终成功完成 + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Phase1.5-AI对话集成REDCap完成记录.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Phase1.5-AI对话集成REDCap完成记录.md index a0edc9be..99657868 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/Phase1.5-AI对话集成REDCap完成记录.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/Phase1.5-AI对话集成REDCap完成记录.md @@ -335,5 +335,6 @@ AI: "出生日期:2017-01-04 + diff --git a/docs/03-业务模块/IIT Manager Agent/06-开发记录/V1.1更新完成报告.md b/docs/03-业务模块/IIT Manager Agent/06-开发记录/V1.1更新完成报告.md index c95a534e..50ae5e2b 100644 --- a/docs/03-业务模块/IIT Manager Agent/06-开发记录/V1.1更新完成报告.md +++ b/docs/03-业务模块/IIT Manager Agent/06-开发记录/V1.1更新完成报告.md @@ -279,5 +279,6 @@ Day 4: REDCap EM(Webhook推送)← 作为增强,而非核心 + diff --git a/docs/03-业务模块/IIT Manager Agent/07-技术债务/IIT Manager Agent 技术债务清单.md b/docs/03-业务模块/IIT Manager Agent/07-技术债务/IIT Manager Agent 技术债务清单.md index 593bda34..eefca42b 100644 --- a/docs/03-业务模块/IIT Manager Agent/07-技术债务/IIT Manager Agent 技术债务清单.md +++ b/docs/03-业务模块/IIT Manager Agent/07-技术债务/IIT Manager Agent 技术债务清单.md @@ -693,5 +693,6 @@ const answer = `根据研究方案[1]和CRF表格[2],纳入标准包括: + diff --git a/docs/03-业务模块/INST-机构管理端/00-模块当前状态与开发指南.md b/docs/03-业务模块/INST-机构管理端/00-模块当前状态与开发指南.md index d9bc47bf..29a1385b 100644 --- a/docs/03-业务模块/INST-机构管理端/00-模块当前状态与开发指南.md +++ b/docs/03-业务模块/INST-机构管理端/00-模块当前状态与开发指南.md @@ -452,3 +452,4 @@ export const calculateAvailableQuota = async (tenantId: string) => { + diff --git a/docs/03-业务模块/INST-机构管理端/README.md b/docs/03-业务模块/INST-机构管理端/README.md index a5c445cb..a8ced8d7 100644 --- a/docs/03-业务模块/INST-机构管理端/README.md +++ b/docs/03-业务模块/INST-机构管理端/README.md @@ -325,3 +325,4 @@ https://platform.example.com/t/pharma-abc/login + diff --git a/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07-前端迁移与批处理功能完善.md b/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07-前端迁移与批处理功能完善.md index efc6c93c..044ab2fd 100644 --- a/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07-前端迁移与批处理功能完善.md +++ b/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07-前端迁移与批处理功能完善.md @@ -374,4 +374,5 @@ const newResults = resultsData.map((docResult: any) => ({ + diff --git a/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07_PKB模块前端V3设计实现.md b/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07_PKB模块前端V3设计实现.md index ab7511c5..41f85a33 100644 --- a/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07_PKB模块前端V3设计实现.md +++ b/docs/03-业务模块/PKB-个人知识库/06-开发记录/2026-01-07_PKB模块前端V3设计实现.md @@ -246,5 +246,6 @@ const chatApi = axios.create({ + diff --git a/docs/03-业务模块/Redcap/01-部署与配置/10-REDCap_Docker部署操作手册.md b/docs/03-业务模块/Redcap/01-部署与配置/10-REDCap_Docker部署操作手册.md index fe324625..1ac3b21e 100644 --- a/docs/03-业务模块/Redcap/01-部署与配置/10-REDCap_Docker部署操作手册.md +++ b/docs/03-业务模块/Redcap/01-部署与配置/10-REDCap_Docker部署操作手册.md @@ -783,5 +783,6 @@ docker exec redcap-apache php /tmp/create-redcap-password.php + diff --git a/docs/03-业务模块/Redcap/README.md b/docs/03-业务模块/Redcap/README.md index c1e3007a..a1489ac2 100644 --- a/docs/03-业务模块/Redcap/README.md +++ b/docs/03-业务模块/Redcap/README.md @@ -165,5 +165,6 @@ AIclinicalresearch/redcap-docker-dev/ + diff --git a/docs/04-开发规范/09-数据库开发规范.md b/docs/04-开发规范/09-数据库开发规范.md index bd31e79d..644e5a71 100644 --- a/docs/04-开发规范/09-数据库开发规范.md +++ b/docs/04-开发规范/09-数据库开发规范.md @@ -333,3 +333,4 @@ npx tsx check_iit_asl_data.ts + diff --git a/docs/04-开发规范/10-模块认证规范.md b/docs/04-开发规范/10-模块认证规范.md index d56db9ca..d10ad53c 100644 --- a/docs/04-开发规范/10-模块认证规范.md +++ b/docs/04-开发规范/10-模块认证规范.md @@ -201,3 +201,4 @@ interface DecodedToken { + diff --git a/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md b/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md index 3a7732e0..b2872b0a 100644 --- a/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md +++ b/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md @@ -902,5 +902,6 @@ ACR镜像仓库: + diff --git a/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md b/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md index 306d4d2c..bf83277d 100644 --- a/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md +++ b/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md @@ -1389,5 +1389,6 @@ SAE应用配置: + diff --git a/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md b/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md index 41e6f50e..588a92b1 100644 --- a/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md +++ b/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md @@ -1205,5 +1205,6 @@ docker exec -e PGPASSWORD="密码" ai-clinical-postgres psql -h RDS地址 -U air + diff --git a/docs/05-部署文档/10-Node.js后端-Docker镜像构建手册.md b/docs/05-部署文档/10-Node.js后端-Docker镜像构建手册.md index a1fc7bb6..83880b2a 100644 --- a/docs/05-部署文档/10-Node.js后端-Docker镜像构建手册.md +++ b/docs/05-部署文档/10-Node.js后端-Docker镜像构建手册.md @@ -616,5 +616,6 @@ scripts/*.ts + diff --git a/docs/05-部署文档/11-Node.js后端-SAE部署配置清单.md b/docs/05-部署文档/11-Node.js后端-SAE部署配置清单.md index e7d72758..1c02d603 100644 --- a/docs/05-部署文档/11-Node.js后端-SAE部署配置清单.md +++ b/docs/05-部署文档/11-Node.js后端-SAE部署配置清单.md @@ -304,5 +304,6 @@ Node.js后端部署成功后: + diff --git a/docs/05-部署文档/12-Node.js后端-SAE部署操作手册.md b/docs/05-部署文档/12-Node.js后端-SAE部署操作手册.md index 7417a653..9a62d489 100644 --- a/docs/05-部署文档/12-Node.js后端-SAE部署操作手册.md +++ b/docs/05-部署文档/12-Node.js后端-SAE部署操作手册.md @@ -527,5 +527,6 @@ Node.js后端 (SAE) ← http://172.17.173.88:3001 + diff --git a/docs/05-部署文档/13-Node.js后端-镜像修复记录.md b/docs/05-部署文档/13-Node.js后端-镜像修复记录.md index 9a894f79..3f350d7a 100644 --- a/docs/05-部署文档/13-Node.js后端-镜像修复记录.md +++ b/docs/05-部署文档/13-Node.js后端-镜像修复记录.md @@ -242,5 +242,6 @@ curl http://localhost:3001/health + diff --git a/docs/05-部署文档/14-Node.js后端-pino-pretty问题修复.md b/docs/05-部署文档/14-Node.js后端-pino-pretty问题修复.md index 192171c4..1ad87cbc 100644 --- a/docs/05-部署文档/14-Node.js后端-pino-pretty问题修复.md +++ b/docs/05-部署文档/14-Node.js后端-pino-pretty问题修复.md @@ -280,5 +280,6 @@ npm run dev + diff --git a/docs/05-部署文档/16-前端Nginx-部署成功总结.md b/docs/05-部署文档/16-前端Nginx-部署成功总结.md index 8e806966..91fc51db 100644 --- a/docs/05-部署文档/16-前端Nginx-部署成功总结.md +++ b/docs/05-部署文档/16-前端Nginx-部署成功总结.md @@ -504,5 +504,6 @@ pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432 + diff --git a/docs/05-部署文档/17-完整部署实战手册-2025版.md b/docs/05-部署文档/17-完整部署实战手册-2025版.md index 6c67e4e7..c8198e8e 100644 --- a/docs/05-部署文档/17-完整部署实战手册-2025版.md +++ b/docs/05-部署文档/17-完整部署实战手册-2025版.md @@ -1832,5 +1832,6 @@ curl http://8.140.53.236/ + diff --git a/docs/05-部署文档/18-部署文档使用指南.md b/docs/05-部署文档/18-部署文档使用指南.md index c0cc9ffc..90af5330 100644 --- a/docs/05-部署文档/18-部署文档使用指南.md +++ b/docs/05-部署文档/18-部署文档使用指南.md @@ -380,5 +380,6 @@ crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/backend-se + diff --git a/docs/05-部署文档/19-日常更新快速操作手册.md b/docs/05-部署文档/19-日常更新快速操作手册.md index 76c423e0..2a07bf4f 100644 --- a/docs/05-部署文档/19-日常更新快速操作手册.md +++ b/docs/05-部署文档/19-日常更新快速操作手册.md @@ -702,5 +702,6 @@ docker login --username=gofeng117@163.com \ + diff --git a/docs/05-部署文档/文档修正报告-20251214.md b/docs/05-部署文档/文档修正报告-20251214.md index 215f5cf2..da7ee0cd 100644 --- a/docs/05-部署文档/文档修正报告-20251214.md +++ b/docs/05-部署文档/文档修正报告-20251214.md @@ -513,5 +513,6 @@ NAT网关成本¥100/月,对初创团队是一笔开销 + diff --git a/docs/07-运维文档/03-SAE环境变量配置指南.md b/docs/07-运维文档/03-SAE环境变量配置指南.md index 8531828a..a0d03a97 100644 --- a/docs/07-运维文档/03-SAE环境变量配置指南.md +++ b/docs/07-运维文档/03-SAE环境变量配置指南.md @@ -418,5 +418,6 @@ curl http://你的SAE地址:3001/health + diff --git a/docs/07-运维文档/05-Redis缓存与队列的区别说明.md b/docs/07-运维文档/05-Redis缓存与队列的区别说明.md index b1f7a480..d6bc6c42 100644 --- a/docs/07-运维文档/05-Redis缓存与队列的区别说明.md +++ b/docs/07-运维文档/05-Redis缓存与队列的区别说明.md @@ -750,5 +750,6 @@ const job = await queue.getJob(jobId); + diff --git a/docs/07-运维文档/06-长时间任务可靠性分析.md b/docs/07-运维文档/06-长时间任务可靠性分析.md index 34c7a49d..76e217ce 100644 --- a/docs/07-运维文档/06-长时间任务可靠性分析.md +++ b/docs/07-运维文档/06-长时间任务可靠性分析.md @@ -517,5 +517,6 @@ processLiteraturesInBackground(task.id, projectId, testLiteratures); + diff --git a/docs/07-运维文档/07-Redis使用需求分析(按模块).md b/docs/07-运维文档/07-Redis使用需求分析(按模块).md index 200e0f5a..048206bb 100644 --- a/docs/07-运维文档/07-Redis使用需求分析(按模块).md +++ b/docs/07-运维文档/07-Redis使用需求分析(按模块).md @@ -994,5 +994,6 @@ ROI = (¥22,556 - ¥144) / ¥144 × 100% = 15,564% + diff --git a/docs/08-项目管理/03-每周计划/2025-12-13-Postgres-Only架构改造完成.md b/docs/08-项目管理/03-每周计划/2025-12-13-Postgres-Only架构改造完成.md index 05d9ab50..7300cec2 100644 --- a/docs/08-项目管理/03-每周计划/2025-12-13-Postgres-Only架构改造完成.md +++ b/docs/08-项目管理/03-每周计划/2025-12-13-Postgres-Only架构改造完成.md @@ -1051,5 +1051,6 @@ Redis 实例:¥500/月 + diff --git a/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md b/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md index acb839d0..6f293509 100644 --- a/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md +++ b/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md @@ -509,5 +509,6 @@ import { ChatContainer } from '@/shared/components/Chat'; + diff --git a/docs/08-项目管理/2026-01-11-数据库事故总结.md b/docs/08-项目管理/2026-01-11-数据库事故总结.md index 1dca2e32..1b1a178d 100644 --- a/docs/08-项目管理/2026-01-11-数据库事故总结.md +++ b/docs/08-项目管理/2026-01-11-数据库事故总结.md @@ -217,3 +217,4 @@ VALUES ('user-mock-001', '13800000000', ..., 'tenant-mock-001', ...); + diff --git a/docs/08-项目管理/PKB前端问题修复报告.md b/docs/08-项目管理/PKB前端问题修复报告.md index 9fcc8275..0e17ec5f 100644 --- a/docs/08-项目管理/PKB前端问题修复报告.md +++ b/docs/08-项目管理/PKB前端问题修复报告.md @@ -427,5 +427,6 @@ frontend-v2/src/modules/pkb/ + diff --git a/docs/08-项目管理/PKB前端验证指南.md b/docs/08-项目管理/PKB前端验证指南.md index 0103c05f..ca3def69 100644 --- a/docs/08-项目管理/PKB前端验证指南.md +++ b/docs/08-项目管理/PKB前端验证指南.md @@ -289,5 +289,6 @@ npm run dev + diff --git a/docs/08-项目管理/PKB功能审查报告-阶段0.md b/docs/08-项目管理/PKB功能审查报告-阶段0.md index 01fd07f4..093bf51f 100644 --- a/docs/08-项目管理/PKB功能审查报告-阶段0.md +++ b/docs/08-项目管理/PKB功能审查报告-阶段0.md @@ -804,5 +804,6 @@ AIA智能问答模块 + diff --git a/docs/08-项目管理/PKB和RVW功能迁移计划.md b/docs/08-项目管理/PKB和RVW功能迁移计划.md index 64601546..38ecfccb 100644 --- a/docs/08-项目管理/PKB和RVW功能迁移计划.md +++ b/docs/08-项目管理/PKB和RVW功能迁移计划.md @@ -949,5 +949,6 @@ CREATE INDEX idx_rvw_tasks_created_at ON rvw_schema.review_tasks(created_at); + diff --git a/docs/08-项目管理/PKB精细化优化报告.md b/docs/08-项目管理/PKB精细化优化报告.md index 8e6298aa..75555cef 100644 --- a/docs/08-项目管理/PKB精细化优化报告.md +++ b/docs/08-项目管理/PKB精细化优化报告.md @@ -602,5 +602,6 @@ const typography = { + diff --git a/docs/08-项目管理/PKB迁移-超级安全执行计划.md b/docs/08-项目管理/PKB迁移-超级安全执行计划.md index 51108f8f..bb5f6f07 100644 --- a/docs/08-项目管理/PKB迁移-超级安全执行计划.md +++ b/docs/08-项目管理/PKB迁移-超级安全执行计划.md @@ -914,5 +914,6 @@ app.use('/api/v1/knowledge', (req, res) => { + diff --git a/docs/08-项目管理/PKB迁移-阶段1完成报告.md b/docs/08-项目管理/PKB迁移-阶段1完成报告.md index 268df9ea..001f5ecd 100644 --- a/docs/08-项目管理/PKB迁移-阶段1完成报告.md +++ b/docs/08-项目管理/PKB迁移-阶段1完成报告.md @@ -228,5 +228,6 @@ rm -rf src/modules/pkb + diff --git a/docs/08-项目管理/PKB迁移-阶段2完成报告.md b/docs/08-项目管理/PKB迁移-阶段2完成报告.md index a5effdb8..9e38f90a 100644 --- a/docs/08-项目管理/PKB迁移-阶段2完成报告.md +++ b/docs/08-项目管理/PKB迁移-阶段2完成报告.md @@ -403,5 +403,6 @@ GET /api/v2/pkb/batch-tasks/batch/templates + diff --git a/docs/08-项目管理/PKB迁移-阶段2进行中.md b/docs/08-项目管理/PKB迁移-阶段2进行中.md index 8ec31c5c..6c88d011 100644 --- a/docs/08-项目管理/PKB迁移-阶段2进行中.md +++ b/docs/08-项目管理/PKB迁移-阶段2进行中.md @@ -47,5 +47,6 @@ import pkbRoutes from './modules/pkb/routes/index.js'; + diff --git a/docs/08-项目管理/PKB迁移-阶段3完成报告.md b/docs/08-项目管理/PKB迁移-阶段3完成报告.md index 17344aa1..e73a2b34 100644 --- a/docs/08-项目管理/PKB迁移-阶段3完成报告.md +++ b/docs/08-项目管理/PKB迁移-阶段3完成报告.md @@ -316,5 +316,6 @@ backend/ + diff --git a/docs/08-项目管理/PKB迁移-阶段4完成报告.md b/docs/08-项目管理/PKB迁移-阶段4完成报告.md index f24f0cc6..b446b5d8 100644 --- a/docs/08-项目管理/PKB迁移-阶段4完成报告.md +++ b/docs/08-项目管理/PKB迁移-阶段4完成报告.md @@ -527,5 +527,6 @@ const response = await fetch('/api/v2/pkb/batch-tasks/batch/execute', { + diff --git a/extraction_service/.dockerignore b/extraction_service/.dockerignore index f666890c..1b545132 100644 --- a/extraction_service/.dockerignore +++ b/extraction_service/.dockerignore @@ -87,5 +87,6 @@ models/ + diff --git a/extraction_service/operations/__init__.py b/extraction_service/operations/__init__.py index b27ecf14..e3b70fe7 100644 --- a/extraction_service/operations/__init__.py +++ b/extraction_service/operations/__init__.py @@ -75,5 +75,6 @@ __version__ = '1.0.0' + diff --git a/extraction_service/operations/dropna.py b/extraction_service/operations/dropna.py index e921c1de..342ace97 100644 --- a/extraction_service/operations/dropna.py +++ b/extraction_service/operations/dropna.py @@ -208,5 +208,6 @@ def get_missing_summary(df: pd.DataFrame) -> dict: + diff --git a/extraction_service/operations/filter.py b/extraction_service/operations/filter.py index 7b854933..65b951c0 100644 --- a/extraction_service/operations/filter.py +++ b/extraction_service/operations/filter.py @@ -168,5 +168,6 @@ def apply_filter( + diff --git a/extraction_service/operations/unpivot.py b/extraction_service/operations/unpivot.py index 9a764127..ef67d18a 100644 --- a/extraction_service/operations/unpivot.py +++ b/extraction_service/operations/unpivot.py @@ -332,5 +332,6 @@ def get_unpivot_preview( + diff --git a/extraction_service/services/pdf_markdown_processor.py b/extraction_service/services/pdf_markdown_processor.py index 5b1770dd..a04adfbd 100644 --- a/extraction_service/services/pdf_markdown_processor.py +++ b/extraction_service/services/pdf_markdown_processor.py @@ -147,3 +147,4 @@ def extract_pdf_to_markdown(pdf_path: str) -> Dict[str, Any]: + diff --git a/extraction_service/test_dc_api.py b/extraction_service/test_dc_api.py index 5d4bb53d..ca33d13f 100644 --- a/extraction_service/test_dc_api.py +++ b/extraction_service/test_dc_api.py @@ -342,5 +342,6 @@ if __name__ == "__main__": + diff --git a/extraction_service/test_execute_simple.py b/extraction_service/test_execute_simple.py index 3c9112ba..34f3c72c 100644 --- a/extraction_service/test_execute_simple.py +++ b/extraction_service/test_execute_simple.py @@ -108,5 +108,6 @@ except Exception as e: + diff --git a/extraction_service/test_module.py b/extraction_service/test_module.py index 9409f823..8d22aa89 100644 --- a/extraction_service/test_module.py +++ b/extraction_service/test_module.py @@ -88,5 +88,6 @@ except Exception as e: + diff --git a/frontend-v2/.dockerignore b/frontend-v2/.dockerignore index ec551a26..24f8fc3b 100644 --- a/frontend-v2/.dockerignore +++ b/frontend-v2/.dockerignore @@ -107,5 +107,6 @@ vite.config.*.timestamp-* + diff --git a/frontend-v2/docker-entrypoint.sh b/frontend-v2/docker-entrypoint.sh index 777bc4af..14b5d5b3 100644 --- a/frontend-v2/docker-entrypoint.sh +++ b/frontend-v2/docker-entrypoint.sh @@ -74,5 +74,6 @@ exec nginx -g 'daemon off;' + diff --git a/frontend-v2/nginx.conf b/frontend-v2/nginx.conf index ed08aa60..1a037b27 100644 --- a/frontend-v2/nginx.conf +++ b/frontend-v2/nginx.conf @@ -230,5 +230,6 @@ http { + diff --git a/frontend-v2/src/common/api/axios.ts b/frontend-v2/src/common/api/axios.ts index cfe4e15a..78111006 100644 --- a/frontend-v2/src/common/api/axios.ts +++ b/frontend-v2/src/common/api/axios.ts @@ -59,3 +59,4 @@ export default apiClient; + diff --git a/frontend-v2/src/framework/auth/api.ts b/frontend-v2/src/framework/auth/api.ts index a89a4a31..a0904f45 100644 --- a/frontend-v2/src/framework/auth/api.ts +++ b/frontend-v2/src/framework/auth/api.ts @@ -258,3 +258,4 @@ export async function logout(): Promise { + diff --git a/frontend-v2/src/framework/auth/index.ts b/frontend-v2/src/framework/auth/index.ts index 7f711c7a..16157f09 100644 --- a/frontend-v2/src/framework/auth/index.ts +++ b/frontend-v2/src/framework/auth/index.ts @@ -24,3 +24,4 @@ export * from './api'; + diff --git a/frontend-v2/src/framework/auth/moduleApi.ts b/frontend-v2/src/framework/auth/moduleApi.ts index f602bc8b..748db9fb 100644 --- a/frontend-v2/src/framework/auth/moduleApi.ts +++ b/frontend-v2/src/framework/auth/moduleApi.ts @@ -48,3 +48,4 @@ export async function fetchUserModules(): Promise { + diff --git a/frontend-v2/src/modules/admin/components/ModulePermissionModal.tsx b/frontend-v2/src/modules/admin/components/ModulePermissionModal.tsx index a7b4bea1..1060668d 100644 --- a/frontend-v2/src/modules/admin/components/ModulePermissionModal.tsx +++ b/frontend-v2/src/modules/admin/components/ModulePermissionModal.tsx @@ -128,3 +128,4 @@ export default ModulePermissionModal; + diff --git a/frontend-v2/src/modules/admin/index.tsx b/frontend-v2/src/modules/admin/index.tsx index 1bbd1294..18372994 100644 --- a/frontend-v2/src/modules/admin/index.tsx +++ b/frontend-v2/src/modules/admin/index.tsx @@ -39,3 +39,4 @@ export default AdminModule; + diff --git a/frontend-v2/src/modules/admin/types/user.ts b/frontend-v2/src/modules/admin/types/user.ts index 401046c9..a0647f66 100644 --- a/frontend-v2/src/modules/admin/types/user.ts +++ b/frontend-v2/src/modules/admin/types/user.ts @@ -204,3 +204,4 @@ export const TENANT_TYPE_NAMES: Record = { + diff --git a/frontend-v2/src/modules/aia/components/AgentCard.tsx b/frontend-v2/src/modules/aia/components/AgentCard.tsx index da653462..d556cc8f 100644 --- a/frontend-v2/src/modules/aia/components/AgentCard.tsx +++ b/frontend-v2/src/modules/aia/components/AgentCard.tsx @@ -88,3 +88,4 @@ export default AgentCard; + diff --git a/frontend-v2/src/modules/aia/components/index.ts b/frontend-v2/src/modules/aia/components/index.ts index 712ab8de..02ddccb2 100644 --- a/frontend-v2/src/modules/aia/components/index.ts +++ b/frontend-v2/src/modules/aia/components/index.ts @@ -18,3 +18,4 @@ export { ChatWorkspace } from './ChatWorkspace'; + diff --git a/frontend-v2/src/modules/aia/constants.ts b/frontend-v2/src/modules/aia/constants.ts index 41185fbd..a1506286 100644 --- a/frontend-v2/src/modules/aia/constants.ts +++ b/frontend-v2/src/modules/aia/constants.ts @@ -182,3 +182,4 @@ export const BRAND_COLORS = { + diff --git a/frontend-v2/src/modules/aia/styles/agent-card.css b/frontend-v2/src/modules/aia/styles/agent-card.css index 2a061e66..1c06d40c 100644 --- a/frontend-v2/src/modules/aia/styles/agent-card.css +++ b/frontend-v2/src/modules/aia/styles/agent-card.css @@ -220,3 +220,4 @@ + diff --git a/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx b/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx index 8e326822..c597f74e 100644 --- a/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx +++ b/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx @@ -577,5 +577,6 @@ export default FulltextDetailDrawer; + diff --git a/frontend-v2/src/modules/dc/hooks/useAssets.ts b/frontend-v2/src/modules/dc/hooks/useAssets.ts index 829f5e95..60afe7da 100644 --- a/frontend-v2/src/modules/dc/hooks/useAssets.ts +++ b/frontend-v2/src/modules/dc/hooks/useAssets.ts @@ -170,5 +170,6 @@ export const useAssets = (activeTab: AssetTabType) => { + diff --git a/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts b/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts index 2d344c41..5ccbefd2 100644 --- a/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts +++ b/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts @@ -160,5 +160,6 @@ export const useRecentTasks = () => { + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/hooks/useSessionStatus.ts b/frontend-v2/src/modules/dc/pages/tool-c/hooks/useSessionStatus.ts index 4ac6b89d..792d3af2 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/hooks/useSessionStatus.ts +++ b/frontend-v2/src/modules/dc/pages/tool-c/hooks/useSessionStatus.ts @@ -130,5 +130,6 @@ export function useSessionStatus({ + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/types/index.ts b/frontend-v2/src/modules/dc/pages/tool-c/types/index.ts index a014daab..6455910b 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/types/index.ts +++ b/frontend-v2/src/modules/dc/pages/tool-c/types/index.ts @@ -122,5 +122,6 @@ export interface DataStats { + diff --git a/frontend-v2/src/modules/dc/types/portal.ts b/frontend-v2/src/modules/dc/types/portal.ts index 8e42a88e..f755b0c9 100644 --- a/frontend-v2/src/modules/dc/types/portal.ts +++ b/frontend-v2/src/modules/dc/types/portal.ts @@ -118,5 +118,6 @@ export type AssetTabType = 'all' | 'processed' | 'raw'; + diff --git a/frontend-v2/src/modules/pkb/pages/KnowledgePage.tsx b/frontend-v2/src/modules/pkb/pages/KnowledgePage.tsx index 0c33d24c..f1ca97f3 100644 --- a/frontend-v2/src/modules/pkb/pages/KnowledgePage.tsx +++ b/frontend-v2/src/modules/pkb/pages/KnowledgePage.tsx @@ -305,5 +305,6 @@ export default KnowledgePage; + diff --git a/frontend-v2/src/modules/pkb/types/workspace.ts b/frontend-v2/src/modules/pkb/types/workspace.ts index 3a235e76..0ced2dea 100644 --- a/frontend-v2/src/modules/pkb/types/workspace.ts +++ b/frontend-v2/src/modules/pkb/types/workspace.ts @@ -60,5 +60,6 @@ export interface BatchTemplate { + diff --git a/frontend-v2/src/modules/rvw/components/AgentModal.tsx b/frontend-v2/src/modules/rvw/components/AgentModal.tsx index 01d69a3b..648af4c6 100644 --- a/frontend-v2/src/modules/rvw/components/AgentModal.tsx +++ b/frontend-v2/src/modules/rvw/components/AgentModal.tsx @@ -139,4 +139,5 @@ export default function AgentModal({ visible, taskCount, onClose, onConfirm }: A + diff --git a/frontend-v2/src/modules/rvw/components/BatchToolbar.tsx b/frontend-v2/src/modules/rvw/components/BatchToolbar.tsx index e5d81dcf..f78e508b 100644 --- a/frontend-v2/src/modules/rvw/components/BatchToolbar.tsx +++ b/frontend-v2/src/modules/rvw/components/BatchToolbar.tsx @@ -59,4 +59,5 @@ export default function BatchToolbar({ selectedCount, onRunBatch, onClearSelecti + diff --git a/frontend-v2/src/modules/rvw/components/FilterChips.tsx b/frontend-v2/src/modules/rvw/components/FilterChips.tsx index 30fe9197..08802069 100644 --- a/frontend-v2/src/modules/rvw/components/FilterChips.tsx +++ b/frontend-v2/src/modules/rvw/components/FilterChips.tsx @@ -82,4 +82,5 @@ export default function FilterChips({ filters, counts, onFilterChange }: FilterC + diff --git a/frontend-v2/src/modules/rvw/components/Header.tsx b/frontend-v2/src/modules/rvw/components/Header.tsx index 13c3d862..73f6e071 100644 --- a/frontend-v2/src/modules/rvw/components/Header.tsx +++ b/frontend-v2/src/modules/rvw/components/Header.tsx @@ -72,4 +72,5 @@ export default function Header({ onUpload }: HeaderProps) { + diff --git a/frontend-v2/src/modules/rvw/components/ReportDetail.tsx b/frontend-v2/src/modules/rvw/components/ReportDetail.tsx index 5fd3dcf7..4eacb5a8 100644 --- a/frontend-v2/src/modules/rvw/components/ReportDetail.tsx +++ b/frontend-v2/src/modules/rvw/components/ReportDetail.tsx @@ -126,4 +126,5 @@ export default function ReportDetail({ report, onBack }: ReportDetailProps) { + diff --git a/frontend-v2/src/modules/rvw/components/ScoreRing.tsx b/frontend-v2/src/modules/rvw/components/ScoreRing.tsx index 17a8f5b7..b8da1dc9 100644 --- a/frontend-v2/src/modules/rvw/components/ScoreRing.tsx +++ b/frontend-v2/src/modules/rvw/components/ScoreRing.tsx @@ -54,4 +54,5 @@ export default function ScoreRing({ score, size = 'medium', showLabel = true }: + diff --git a/frontend-v2/src/modules/rvw/components/Sidebar.tsx b/frontend-v2/src/modules/rvw/components/Sidebar.tsx index 540ed4f1..40928e75 100644 --- a/frontend-v2/src/modules/rvw/components/Sidebar.tsx +++ b/frontend-v2/src/modules/rvw/components/Sidebar.tsx @@ -89,4 +89,5 @@ export default function Sidebar({ currentView, onViewChange, onSettingsClick }: + diff --git a/frontend-v2/src/modules/rvw/components/index.ts b/frontend-v2/src/modules/rvw/components/index.ts index 8665feec..76ca5c6f 100644 --- a/frontend-v2/src/modules/rvw/components/index.ts +++ b/frontend-v2/src/modules/rvw/components/index.ts @@ -31,4 +31,5 @@ export { default as TaskDetail } from './TaskDetail'; + diff --git a/frontend-v2/src/modules/rvw/pages/Dashboard.tsx b/frontend-v2/src/modules/rvw/pages/Dashboard.tsx index e59feae4..6257572e 100644 --- a/frontend-v2/src/modules/rvw/pages/Dashboard.tsx +++ b/frontend-v2/src/modules/rvw/pages/Dashboard.tsx @@ -300,4 +300,5 @@ export default function Dashboard() { + diff --git a/frontend-v2/src/modules/rvw/styles/index.css b/frontend-v2/src/modules/rvw/styles/index.css index 5ae713dc..92a58039 100644 --- a/frontend-v2/src/modules/rvw/styles/index.css +++ b/frontend-v2/src/modules/rvw/styles/index.css @@ -249,4 +249,5 @@ + diff --git a/frontend-v2/src/pages/admin/tenants/TenantListPage.tsx b/frontend-v2/src/pages/admin/tenants/TenantListPage.tsx index d9db4b0e..b5f280ae 100644 --- a/frontend-v2/src/pages/admin/tenants/TenantListPage.tsx +++ b/frontend-v2/src/pages/admin/tenants/TenantListPage.tsx @@ -351,3 +351,4 @@ export default TenantListPage; + diff --git a/frontend-v2/src/pages/admin/tenants/api/tenantApi.ts b/frontend-v2/src/pages/admin/tenants/api/tenantApi.ts index 9befd93c..1f10fb88 100644 --- a/frontend-v2/src/pages/admin/tenants/api/tenantApi.ts +++ b/frontend-v2/src/pages/admin/tenants/api/tenantApi.ts @@ -260,3 +260,4 @@ export async function fetchModuleList(): Promise { + diff --git a/frontend-v2/src/shared/components/Chat/AIStreamChat.tsx b/frontend-v2/src/shared/components/Chat/AIStreamChat.tsx index 8819846d..4a3c8201 100644 --- a/frontend-v2/src/shared/components/Chat/AIStreamChat.tsx +++ b/frontend-v2/src/shared/components/Chat/AIStreamChat.tsx @@ -479,3 +479,4 @@ export default AIStreamChat; + diff --git a/frontend-v2/src/shared/components/Chat/ConversationList.tsx b/frontend-v2/src/shared/components/Chat/ConversationList.tsx index 962ee0b2..02a9d13b 100644 --- a/frontend-v2/src/shared/components/Chat/ConversationList.tsx +++ b/frontend-v2/src/shared/components/Chat/ConversationList.tsx @@ -179,3 +179,4 @@ export default ConversationList; + diff --git a/frontend-v2/src/shared/components/Chat/hooks/index.ts b/frontend-v2/src/shared/components/Chat/hooks/index.ts index b3f17ef4..575a0ab6 100644 --- a/frontend-v2/src/shared/components/Chat/hooks/index.ts +++ b/frontend-v2/src/shared/components/Chat/hooks/index.ts @@ -31,3 +31,4 @@ export type { + diff --git a/frontend-v2/src/shared/components/Chat/hooks/useAIStream.ts b/frontend-v2/src/shared/components/Chat/hooks/useAIStream.ts index 26ae8d7b..6be2d64d 100644 --- a/frontend-v2/src/shared/components/Chat/hooks/useAIStream.ts +++ b/frontend-v2/src/shared/components/Chat/hooks/useAIStream.ts @@ -323,3 +323,4 @@ export default useAIStream; + diff --git a/frontend-v2/src/shared/components/Chat/hooks/useConversations.ts b/frontend-v2/src/shared/components/Chat/hooks/useConversations.ts index 23c1350b..f0536a46 100644 --- a/frontend-v2/src/shared/components/Chat/hooks/useConversations.ts +++ b/frontend-v2/src/shared/components/Chat/hooks/useConversations.ts @@ -252,3 +252,4 @@ export default useConversations; + diff --git a/frontend-v2/src/shared/components/Chat/styles/ai-stream-chat.css b/frontend-v2/src/shared/components/Chat/styles/ai-stream-chat.css index 935c8887..57f7688b 100644 --- a/frontend-v2/src/shared/components/Chat/styles/ai-stream-chat.css +++ b/frontend-v2/src/shared/components/Chat/styles/ai-stream-chat.css @@ -287,3 +287,4 @@ + diff --git a/frontend-v2/src/shared/components/Chat/styles/conversation-list.css b/frontend-v2/src/shared/components/Chat/styles/conversation-list.css index ced09cac..72c41f97 100644 --- a/frontend-v2/src/shared/components/Chat/styles/conversation-list.css +++ b/frontend-v2/src/shared/components/Chat/styles/conversation-list.css @@ -223,3 +223,4 @@ + diff --git a/frontend-v2/src/shared/components/Chat/styles/thinking.css b/frontend-v2/src/shared/components/Chat/styles/thinking.css index 33324dd1..f51402cf 100644 --- a/frontend-v2/src/shared/components/Chat/styles/thinking.css +++ b/frontend-v2/src/shared/components/Chat/styles/thinking.css @@ -160,3 +160,4 @@ + diff --git a/frontend-v2/src/shared/components/index.ts b/frontend-v2/src/shared/components/index.ts index e643f8db..275b1cc3 100644 --- a/frontend-v2/src/shared/components/index.ts +++ b/frontend-v2/src/shared/components/index.ts @@ -73,5 +73,6 @@ export { default as Placeholder } from './Placeholder'; + diff --git a/frontend-v2/src/vite-env.d.ts b/frontend-v2/src/vite-env.d.ts index 00de34b4..984bb2b5 100644 --- a/frontend-v2/src/vite-env.d.ts +++ b/frontend-v2/src/vite-env.d.ts @@ -53,5 +53,6 @@ interface ImportMeta { + diff --git a/frontend/src/pages/rvw/components/BatchToolbar.tsx b/frontend/src/pages/rvw/components/BatchToolbar.tsx index 1dcf30a3..98a91d0e 100644 --- a/frontend/src/pages/rvw/components/BatchToolbar.tsx +++ b/frontend/src/pages/rvw/components/BatchToolbar.tsx @@ -60,5 +60,6 @@ export default function BatchToolbar({ selectedCount, onRunBatch, onClearSelecti + diff --git a/frontend/src/pages/rvw/components/EditorialReport.tsx b/frontend/src/pages/rvw/components/EditorialReport.tsx index d0909d3b..5040689b 100644 --- a/frontend/src/pages/rvw/components/EditorialReport.tsx +++ b/frontend/src/pages/rvw/components/EditorialReport.tsx @@ -125,5 +125,6 @@ export default function EditorialReport({ data }: EditorialReportProps) { + diff --git a/frontend/src/pages/rvw/components/FilterChips.tsx b/frontend/src/pages/rvw/components/FilterChips.tsx index c9e3bd6e..f026733e 100644 --- a/frontend/src/pages/rvw/components/FilterChips.tsx +++ b/frontend/src/pages/rvw/components/FilterChips.tsx @@ -83,5 +83,6 @@ export default function FilterChips({ filters, counts, onFilterChange }: FilterC + diff --git a/frontend/src/pages/rvw/components/Header.tsx b/frontend/src/pages/rvw/components/Header.tsx index 885b661e..36607a81 100644 --- a/frontend/src/pages/rvw/components/Header.tsx +++ b/frontend/src/pages/rvw/components/Header.tsx @@ -73,5 +73,6 @@ export default function Header({ onUpload }: HeaderProps) { + diff --git a/frontend/src/pages/rvw/components/ReportDetail.tsx b/frontend/src/pages/rvw/components/ReportDetail.tsx index bb68e806..c8435e3c 100644 --- a/frontend/src/pages/rvw/components/ReportDetail.tsx +++ b/frontend/src/pages/rvw/components/ReportDetail.tsx @@ -127,5 +127,6 @@ export default function ReportDetail({ report, onBack }: ReportDetailProps) { + diff --git a/frontend/src/pages/rvw/components/ScoreRing.tsx b/frontend/src/pages/rvw/components/ScoreRing.tsx index a74fa2cc..0cfafaa0 100644 --- a/frontend/src/pages/rvw/components/ScoreRing.tsx +++ b/frontend/src/pages/rvw/components/ScoreRing.tsx @@ -55,5 +55,6 @@ export default function ScoreRing({ score, size = 'medium', showLabel = true }: + diff --git a/frontend/src/pages/rvw/components/Sidebar.tsx b/frontend/src/pages/rvw/components/Sidebar.tsx index f5a79d36..cb678cb3 100644 --- a/frontend/src/pages/rvw/components/Sidebar.tsx +++ b/frontend/src/pages/rvw/components/Sidebar.tsx @@ -90,5 +90,6 @@ export default function Sidebar({ currentView, onViewChange, onSettingsClick }: + diff --git a/frontend/src/pages/rvw/index.ts b/frontend/src/pages/rvw/index.ts index 1b12fcf5..46445093 100644 --- a/frontend/src/pages/rvw/index.ts +++ b/frontend/src/pages/rvw/index.ts @@ -24,5 +24,6 @@ export * from './api'; + diff --git a/frontend/src/pages/rvw/styles.css b/frontend/src/pages/rvw/styles.css index 7e839492..f4c13dc5 100644 --- a/frontend/src/pages/rvw/styles.css +++ b/frontend/src/pages/rvw/styles.css @@ -250,5 +250,6 @@ + diff --git a/git-cleanup-redcap.ps1 b/git-cleanup-redcap.ps1 index ea3a6139..c817a9a2 100644 --- a/git-cleanup-redcap.ps1 +++ b/git-cleanup-redcap.ps1 @@ -46,5 +46,6 @@ Write-Host "Next step: Run the commit command" -ForegroundColor Cyan + diff --git a/git-commit-day1.ps1 b/git-commit-day1.ps1 index b6b708f4..4d111d06 100644 --- a/git-commit-day1.ps1 +++ b/git-commit-day1.ps1 @@ -102,5 +102,6 @@ Write-Host "Git commit and push completed!" -ForegroundColor Green + diff --git a/git-fix-lock.ps1 b/git-fix-lock.ps1 index d30f4597..e90b2d95 100644 --- a/git-fix-lock.ps1 +++ b/git-fix-lock.ps1 @@ -50,5 +50,6 @@ Write-Host "Now you can run git commands again." -ForegroundColor Cyan + diff --git a/python-microservice/operations/__init__.py b/python-microservice/operations/__init__.py index b27ecf14..e3b70fe7 100644 --- a/python-microservice/operations/__init__.py +++ b/python-microservice/operations/__init__.py @@ -75,5 +75,6 @@ __version__ = '1.0.0' + diff --git a/python-microservice/operations/binning.py b/python-microservice/operations/binning.py index 3115f50f..c405019a 100644 --- a/python-microservice/operations/binning.py +++ b/python-microservice/operations/binning.py @@ -182,5 +182,6 @@ def apply_binning( + diff --git a/python-microservice/operations/filter.py b/python-microservice/operations/filter.py index 7b854933..65b951c0 100644 --- a/python-microservice/operations/filter.py +++ b/python-microservice/operations/filter.py @@ -168,5 +168,6 @@ def apply_filter( + diff --git a/python-microservice/operations/recode.py b/python-microservice/operations/recode.py index 73bf277b..7aaad178 100644 --- a/python-microservice/operations/recode.py +++ b/python-microservice/operations/recode.py @@ -138,5 +138,6 @@ def apply_recode( + diff --git a/recover_dc_code.py b/recover_dc_code.py index 4f3fb605..bd03be32 100644 --- a/recover_dc_code.py +++ b/recover_dc_code.py @@ -282,5 +282,6 @@ if __name__ == "__main__": + diff --git a/redcap-docker-dev/.gitattributes b/redcap-docker-dev/.gitattributes index 2b1a2cad..35c2dacf 100644 --- a/redcap-docker-dev/.gitattributes +++ b/redcap-docker-dev/.gitattributes @@ -62,5 +62,6 @@ + diff --git a/redcap-docker-dev/.gitignore b/redcap-docker-dev/.gitignore index 39d46feb..7c0fed03 100644 --- a/redcap-docker-dev/.gitignore +++ b/redcap-docker-dev/.gitignore @@ -93,5 +93,6 @@ Desktop.ini + diff --git a/redcap-docker-dev/README.md b/redcap-docker-dev/README.md index af32da66..a6add25b 100644 --- a/redcap-docker-dev/README.md +++ b/redcap-docker-dev/README.md @@ -394,5 +394,6 @@ docker-compose -f docker-compose.prod.yml up -d + diff --git a/redcap-docker-dev/docker-compose.prod.yml b/redcap-docker-dev/docker-compose.prod.yml index 63848947..424f0e36 100644 --- a/redcap-docker-dev/docker-compose.prod.yml +++ b/redcap-docker-dev/docker-compose.prod.yml @@ -155,5 +155,6 @@ volumes: + diff --git a/redcap-docker-dev/docker-compose.yml b/redcap-docker-dev/docker-compose.yml index 892c11a5..e98060d5 100644 --- a/redcap-docker-dev/docker-compose.yml +++ b/redcap-docker-dev/docker-compose.yml @@ -153,5 +153,6 @@ volumes: + diff --git a/redcap-docker-dev/env.template b/redcap-docker-dev/env.template index c5126737..47d6c154 100644 --- a/redcap-docker-dev/env.template +++ b/redcap-docker-dev/env.template @@ -89,5 +89,6 @@ PMA_UPLOAD_LIMIT=50M + diff --git a/redcap-docker-dev/scripts/clean-redcap.ps1 b/redcap-docker-dev/scripts/clean-redcap.ps1 index c2898496..8c899eb7 100644 --- a/redcap-docker-dev/scripts/clean-redcap.ps1 +++ b/redcap-docker-dev/scripts/clean-redcap.ps1 @@ -97,5 +97,6 @@ Write-Host "" + diff --git a/redcap-docker-dev/scripts/create-redcap-password.php b/redcap-docker-dev/scripts/create-redcap-password.php index 351c8ccb..d8f464cc 100644 --- a/redcap-docker-dev/scripts/create-redcap-password.php +++ b/redcap-docker-dev/scripts/create-redcap-password.php @@ -75,5 +75,6 @@ try { + diff --git a/redcap-docker-dev/scripts/logs-redcap.ps1 b/redcap-docker-dev/scripts/logs-redcap.ps1 index 919cb2fc..6d206fb5 100644 --- a/redcap-docker-dev/scripts/logs-redcap.ps1 +++ b/redcap-docker-dev/scripts/logs-redcap.ps1 @@ -88,5 +88,6 @@ Write-Host "" + diff --git a/redcap-docker-dev/scripts/reset-admin-password.php b/redcap-docker-dev/scripts/reset-admin-password.php index 2f976009..d0aaddea 100644 --- a/redcap-docker-dev/scripts/reset-admin-password.php +++ b/redcap-docker-dev/scripts/reset-admin-password.php @@ -51,5 +51,6 @@ if ($result) { + diff --git a/redcap-docker-dev/scripts/start-redcap.ps1 b/redcap-docker-dev/scripts/start-redcap.ps1 index 768d05c5..528487e1 100644 --- a/redcap-docker-dev/scripts/start-redcap.ps1 +++ b/redcap-docker-dev/scripts/start-redcap.ps1 @@ -73,5 +73,6 @@ if ($LASTEXITCODE -eq 0) { + diff --git a/redcap-docker-dev/scripts/stop-redcap.ps1 b/redcap-docker-dev/scripts/stop-redcap.ps1 index 3770c349..cdd30b92 100644 --- a/redcap-docker-dev/scripts/stop-redcap.ps1 +++ b/redcap-docker-dev/scripts/stop-redcap.ps1 @@ -59,5 +59,6 @@ if ($LASTEXITCODE -eq 0) { + diff --git a/run_recovery.ps1 b/run_recovery.ps1 index 969dd68f..46066ef8 100644 --- a/run_recovery.ps1 +++ b/run_recovery.ps1 @@ -106,5 +106,6 @@ Write-Host "==================================================================== + diff --git a/tests/QUICKSTART_快速开始.md b/tests/QUICKSTART_快速开始.md index deb67445..049ecea1 100644 --- a/tests/QUICKSTART_快速开始.md +++ b/tests/QUICKSTART_快速开始.md @@ -153,5 +153,6 @@ INFO: Uvicorn running on http://0.0.0.0:8001 + diff --git a/tests/README_测试说明.md b/tests/README_测试说明.md index f792849d..6ed90668 100644 --- a/tests/README_测试说明.md +++ b/tests/README_测试说明.md @@ -309,5 +309,6 @@ df_numeric.to_excel('test_data/numeric_test.xlsx', index=False) + diff --git a/tests/run_tests.bat b/tests/run_tests.bat index 3a9e476f..ac11b586 100644 --- a/tests/run_tests.bat +++ b/tests/run_tests.bat @@ -104,5 +104,6 @@ pause + diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 99d446f3..a2534cd6 100644 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -100,5 +100,6 @@ echo "========================================" + diff --git a/快速部署到SAE.md b/快速部署到SAE.md index f9dab9e9..a03c4cc5 100644 --- a/快速部署到SAE.md +++ b/快速部署到SAE.md @@ -365,5 +365,6 @@ OSS AccessKeySecret:_______________ + diff --git a/部署检查清单.md b/部署检查清单.md index 9ed28e50..b99fd3aa 100644 --- a/部署检查清单.md +++ b/部署检查清单.md @@ -401,5 +401,6 @@ OSS配置: +