diff --git a/DC模块代码恢复指南.md b/DC模块代码恢复指南.md index 6794e7dd..f2e9b0c0 100644 --- a/DC模块代码恢复指南.md +++ b/DC模块代码恢复指南.md @@ -242,6 +242,8 @@ + + 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 90658767..db1ffd1f 100644 --- a/backend/migrations/add_data_stats_to_tool_c_session.sql +++ b/backend/migrations/add_data_stats_to_tool_c_session.sql @@ -38,5 +38,7 @@ 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 ce2eb1f3..1ecc2467 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 @@ -78,3 +78,5 @@ 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 757a3380..dedbb9f6 100644 --- a/backend/prisma/manual-migrations/run-migration-002.ts +++ b/backend/prisma/manual-migrations/run-migration-002.ts @@ -91,3 +91,5 @@ runMigration() + + diff --git a/backend/prisma/migrations/20251208_add_column_mapping/migration.sql b/backend/prisma/migrations/20251208_add_column_mapping/migration.sql index da8e4b06..782ca058 100644 --- a/backend/prisma/migrations/20251208_add_column_mapping/migration.sql +++ b/backend/prisma/migrations/20251208_add_column_mapping/migration.sql @@ -25,3 +25,5 @@ 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 97646c0b..74a11703 100644 --- a/backend/prisma/migrations/create_tool_c_session.sql +++ b/backend/prisma/migrations/create_tool_c_session.sql @@ -49,6 +49,8 @@ COMMENT ON COLUMN dc_schema.dc_tool_c_sessions.expires_at IS '过期时间(创 + + diff --git a/backend/recover-code-from-cursor-db.js b/backend/recover-code-from-cursor-db.js index 4bca69d4..c97c2214 100644 --- a/backend/recover-code-from-cursor-db.js +++ b/backend/recover-code-from-cursor-db.js @@ -199,6 +199,8 @@ function extractCodeBlocks(obj, blocks = []) { + + diff --git a/backend/scripts/check-dc-tables.mjs b/backend/scripts/check-dc-tables.mjs index e5119bc6..3c20dcd5 100644 --- a/backend/scripts/check-dc-tables.mjs +++ b/backend/scripts/check-dc-tables.mjs @@ -218,6 +218,8 @@ checkDCTables(); + + diff --git a/backend/scripts/create-tool-c-ai-history-table.mjs b/backend/scripts/create-tool-c-ai-history-table.mjs index 7a879f2a..27014875 100644 --- a/backend/scripts/create-tool-c-ai-history-table.mjs +++ b/backend/scripts/create-tool-c-ai-history-table.mjs @@ -170,6 +170,8 @@ createAiHistoryTable() + + diff --git a/backend/scripts/create-tool-c-table.js b/backend/scripts/create-tool-c-table.js index e58baf80..f555d6d9 100644 --- a/backend/scripts/create-tool-c-table.js +++ b/backend/scripts/create-tool-c-table.js @@ -157,6 +157,8 @@ createToolCTable() + + diff --git a/backend/scripts/create-tool-c-table.mjs b/backend/scripts/create-tool-c-table.mjs index 794fbef9..7ed42f4b 100644 --- a/backend/scripts/create-tool-c-table.mjs +++ b/backend/scripts/create-tool-c-table.mjs @@ -154,6 +154,8 @@ createToolCTable() + + diff --git a/backend/src/common/jobs/utils.ts b/backend/src/common/jobs/utils.ts index dff61419..ecc68c0d 100644 --- a/backend/src/common/jobs/utils.ts +++ b/backend/src/common/jobs/utils.ts @@ -289,3 +289,5 @@ export function getBatchItems( + + 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 5ef7a76c..8dc36227 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 @@ -322,6 +322,8 @@ 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 ba00c712..14ac8ef6 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 @@ -263,6 +263,8 @@ 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 92bf2f3d..8566cc0c 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 @@ -301,6 +301,8 @@ Content-Type: application/json + + diff --git a/backend/src/modules/asl/fulltext-screening/services/ExcelExporter.ts b/backend/src/modules/asl/fulltext-screening/services/ExcelExporter.ts index ab7dc272..462d2b2c 100644 --- a/backend/src/modules/asl/fulltext-screening/services/ExcelExporter.ts +++ b/backend/src/modules/asl/fulltext-screening/services/ExcelExporter.ts @@ -380,6 +380,8 @@ export class ExcelExporter { + + diff --git a/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts b/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts index 88e9f76f..66a262dd 100644 --- a/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts +++ b/backend/src/modules/dc/tool-b/services/ConflictDetectionService.ts @@ -237,6 +237,8 @@ export const conflictDetectionService = new ConflictDetectionService(); + + diff --git a/backend/src/modules/dc/tool-b/services/TemplateService.ts b/backend/src/modules/dc/tool-b/services/TemplateService.ts index 3b15b9b5..5ef4c2c3 100644 --- a/backend/src/modules/dc/tool-b/services/TemplateService.ts +++ b/backend/src/modules/dc/tool-b/services/TemplateService.ts @@ -265,6 +265,8 @@ export const templateService = new TemplateService(); + + diff --git a/backend/src/modules/dc/tool-c/README.md b/backend/src/modules/dc/tool-c/README.md index 86baa05c..f6b27207 100644 --- a/backend/src/modules/dc/tool-c/README.md +++ b/backend/src/modules/dc/tool-c/README.md @@ -187,6 +187,8 @@ 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 4287eef0..c4c898fc 100644 --- a/backend/src/modules/dc/tool-c/controllers/StreamAIController.ts +++ b/backend/src/modules/dc/tool-c/controllers/StreamAIController.ts @@ -242,5 +242,7 @@ export const streamAIController = new StreamAIController(); + + diff --git a/backend/src/tests/README.md b/backend/src/tests/README.md index 3a37cbd6..ae497951 100644 --- a/backend/src/tests/README.md +++ b/backend/src/tests/README.md @@ -390,3 +390,5 @@ SET session_replication_role = 'origin'; + + diff --git a/backend/src/tests/verify-test1-database.sql b/backend/src/tests/verify-test1-database.sql index f066feb2..567ec691 100644 --- a/backend/src/tests/verify-test1-database.sql +++ b/backend/src/tests/verify-test1-database.sql @@ -92,3 +92,5 @@ WHERE key = 'verify_test'; + + diff --git a/backend/src/tests/verify-test1-database.ts b/backend/src/tests/verify-test1-database.ts index 252ce00b..69868faf 100644 --- a/backend/src/tests/verify-test1-database.ts +++ b/backend/src/tests/verify-test1-database.ts @@ -235,3 +235,5 @@ verifyDatabase() + + diff --git a/backend/src/types/global.d.ts b/backend/src/types/global.d.ts index 659c1062..99473f4b 100644 --- a/backend/src/types/global.d.ts +++ b/backend/src/types/global.d.ts @@ -25,3 +25,5 @@ export {} + + diff --git a/backend/sync-dc-database.ps1 b/backend/sync-dc-database.ps1 index a83d055c..4572322d 100644 --- a/backend/sync-dc-database.ps1 +++ b/backend/sync-dc-database.ps1 @@ -45,6 +45,8 @@ Write-Host "✅ 完成!" -ForegroundColor Green + + diff --git a/backend/test-tool-c-advanced-scenarios.mjs b/backend/test-tool-c-advanced-scenarios.mjs index 41fe53a4..5b22fd55 100644 --- a/backend/test-tool-c-advanced-scenarios.mjs +++ b/backend/test-tool-c-advanced-scenarios.mjs @@ -333,5 +333,7 @@ runAdvancedTests().catch(error => { + + diff --git a/backend/test-tool-c-day2.mjs b/backend/test-tool-c-day2.mjs index 8524bcac..94df91d2 100644 --- a/backend/test-tool-c-day2.mjs +++ b/backend/test-tool-c-day2.mjs @@ -398,6 +398,8 @@ runAllTests() + + diff --git a/backend/test-tool-c-day3.mjs b/backend/test-tool-c-day3.mjs index 0850bb43..0f43cd87 100644 --- a/backend/test-tool-c-day3.mjs +++ b/backend/test-tool-c-day3.mjs @@ -356,6 +356,8 @@ runAllTests() + + diff --git a/deploy-to-sae.ps1 b/deploy-to-sae.ps1 index 5db24e1a..45dc25ac 100644 --- a/deploy-to-sae.ps1 +++ b/deploy-to-sae.ps1 @@ -143,3 +143,5 @@ Set-Location .. + + diff --git a/docs/00-系统总体设计/00-系统当前状态与开发指南.md b/docs/00-系统总体设计/00-系统当前状态与开发指南.md index 81a6bada..b1db4cbd 100644 --- a/docs/00-系统总体设计/00-系统当前状态与开发指南.md +++ b/docs/00-系统总体设计/00-系统当前状态与开发指南.md @@ -1,10 +1,10 @@ # AIclinicalresearch 系统当前状态与开发指南 -> **文档版本:** v2.0 +> **文档版本:** v2.1 > **创建日期:** 2025-11-28 > **维护者:** 开发团队 -> **最后更新:** 2025-12-22 -> **重大进展:** 🏆 **DC Tool C Postgres-Only异步架构改造完成** - 性能提升99%,异步任务处理标准建立 +> **最后更新:** 2024-12-24 +> **重大进展:** 🚀 **阿里云生产环境部署启动** - PostgreSQL数据迁移完成、前端Nginx与Python微服务镜像已推送ACR > **文档目的:** 快速了解系统当前状态,为新AI助手提供上下文 --- @@ -98,11 +98,13 @@ **云原生部署**: - 阿里云 SAE (Serverless 应用引擎) -- RDS PostgreSQL 15 + OSS (对象存储) + Redis (可选,Dify需要) +- RDS PostgreSQL 15 + OSS (对象存储) + NAT网关 +- ACR (容器镜像服务 - 个人版免费) +- **部署状态**:🚀 **进行中**(PostgreSQL✅、前端镜像✅、Python镜像✅) --- -## 🚀 当前开发状态(2025-12-10) +## 🚀 当前开发状态(2024-12-24) ### ✅ 已完成模块 @@ -254,6 +256,137 @@ --- +## 🚀 阿里云生产环境部署状态(2024-12-24) + +### ✅ 已完成部署 + +#### 1. 基础设施层 +- ✅ **VPC网络**:`vpc-2ze055cptkew9c38w4r06`(172.17.0.0/16) +- ✅ **NAT网关**:`ngw-2zeec9ulzgw7ywvx1pst6`(公网IP: 182.92.176.14) +- ✅ **安全组**:`sg-2zedk6fi8sgmmcwdu7tu` +- ✅ **交换机**:2个(可用区F + 可用区A) +- ✅ **SAE命名空间**:`cn-beijing:test-airesearch` + +#### 2. 数据存储层 +- ✅ **RDS PostgreSQL 15** + - 实例ID: `pgm-2zex1m2y3r23hdn5` + - 规格: 2核4GB + - 内网地址: `pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432` + - 数据库: `ai_clinical_research` + - **数据迁移**: ✅ 完成(90MB SQL文件,约12秒导入) + - **Schema验证**: ✅ 11个Schema全部迁移成功 + - **数据验证**: ✅ 用户3条、项目2条、文献1204条 + - **部署时间**: 2024-12-24 + +- ✅ **OSS对象存储** + - Bucket: `ai-clinical-research` + - 存储类型: 标准存储(同城冗余) + - 内网域名: `ai-clinical-research.oss-cn-beijing-internal.aliyuncs.com` + - RAM用户: `oss-bucket-put-object@1991407246109125.onaliyun.com` + - AccessKey: 已配置(不公开) + +#### 3. 容器镜像服务(ACR) +- ✅ **命名空间**: `ai-clinical` +- ✅ **Registry**: `crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com` +- ✅ **已推送镜像**: + - **前端Nginx**: `ai-clinical_frontend-nginx:v1.0`(约50MB) + - 构建时间: 2024-12-24 + - 基础镜像: `nginx:alpine` + - 功能: React SPA + Nginx反向代理 + 动态环境变量 + - 配置文件: `frontend-v2/Dockerfile`, `nginx.conf`, `.dockerignore` + + - **Python微服务**: `python-extraction:v1.0`(1.12GB) + - 构建时间: 2024-12-24 + - 基础镜像: `python:3-slim` + - 功能: PDF提取(PyMuPDF)+ 数据清洗(pandas/numpy/polars) + - 特性: 移除Nougat(减小1.5GB)、使用阿里云Debian源 + - 配置文件: `extraction_service/Dockerfile`, `requirements-prod.txt`, `.dockerignore` + +### 🚧 进行中 + +#### 4. SAE应用部署 +- ⏳ **Python微服务**: 镜像已推送,待部署到SAE + - 目标规格: 1核2GB + - 端口: 8000 + - 健康检查: `/api/health` + +- ⏳ **Node.js后端**: Docker镜像待构建 + - 目标规格: 2核4GB + - 端口: 3001 + - 依赖: RDS PostgreSQL + +- ⏳ **前端Nginx**: 镜像已推送,待部署到SAE + - 目标规格: 1核2GB + - 端口: 80 + - 需配置: 后端API内网地址 + +### 📋 待完成 + +- [ ] Python微服务部署到SAE +- [ ] Node.js后端Docker镜像构建 +- [ ] Node.js后端部署到SAE +- [ ] 前端Nginx部署到SAE +- [ ] 配置服务间内网通信 +- [ ] 全链路验证测试 +- [ ] Dify AI服务部署(可选) + +### 📊 部署文档 + +**部署进度总览**: +- [00-部署进度总览.md](../05-部署文档/00-部署进度总览.md) - 🎯 **一站式部署状态查看** + +**操作手册**: +- [07-前端Nginx-SAE部署操作手册.md](../05-部署文档/07-前端Nginx-SAE部署操作手册.md) +- [08-PostgreSQL数据库部署操作手册.md](../05-部署文档/08-PostgreSQL数据库部署操作手册.md) +- Python微服务SAE部署操作手册(待创建) + +**技术指南**: +- [01-快速部署SOP-零基础版.md](../05-部署文档/01-快速部署SOP-零基础版.md) - 完整部署流程 +- [04-Python微服务-SAE容器部署指南.md](../05-部署文档/04-Python微服务-SAE容器部署指南.md) +- [06-前端Nginx-SAE容器部署指南.md](../05-部署文档/06-前端Nginx-SAE容器部署指南.md) + +### 🎯 部署关键成就 + +1. **PostgreSQL数据迁移** ✅ + - 采用`pg_dump`全量导出/导入方案 + - 11个Schema完整迁移 + - 数据一致性验证通过 + - 安全加固(外网访问已关闭) + +2. **前端Nginx镜像优化** ✅ + - 解决Docker Hub网络问题(使用通用标签) + - 修复30个TypeScript编译错误 + - 多阶段构建优化 + - 健康检查通过 + +3. **Python微服务镜像优化** ✅ + - 移除Nougat OCR(减小1.5GB) + - 使用阿里云Debian镜像源(解决apt-get网络问题) + - 保留数据清洗功能(pandas/numpy/polars) + - 运行时依赖优化(libgl1、libglib2.0) + +4. **镜像配置文件Git管理** ✅ + - Dockerfile: ✅ 已提交Git(构建蓝图) + - .dockerignore: ✅ 已提交Git(优化构建) + - 依赖文件: ✅ 已提交Git(可复现) + - 敏感信息: ❌ 禁止提交(.env等) + +### 💰 当前运行成本估算 + +| 服务 | 规格 | 月成本 | 状态 | +|------|------|-------|------| +| RDS PostgreSQL | 2核4GB | ¥260 | ✅ 运行中 | +| OSS存储 | 10GB | ¥2 | ✅ 运行中 | +| NAT网关 | 小型 | ¥60 | ✅ 运行中 | +| EIP流量 | 5Mbps | ¥40 | ✅ 运行中 | +| ACR镜像仓库 | 个人版 | ¥0(免费) | ✅ 运行中 | +| SAE - Python | 1核2GB×1 | ¥60 | ⏳ 待部署 | +| SAE - Node.js | 2核4GB×1 | ¥120 | ⏳ 待部署 | +| SAE - Frontend | 1核2GB×1 | ¥60 | ⏳ 待部署 | +| **总计** | - | **¥602/月** | 部署中 | + +--- + ## 📁 项目结构概览 ``` @@ -336,33 +469,68 @@ AIclinicalresearch/ | **2025-11-18~21** | Week 3~4 | ✅ ASL标题摘要初筛MVP | | **2025-11-22~23** | ASL Day 2-5 | ✅ ASL全文复筛后端完成 | | **2025-11-26~27** | DC Day 2-3 | ✅ DC工具B健康检查+模板管理 | -| **2025-11-28** | 当前 | 🚧 ASL全文复筛前端 + DC工具B开发 | +| **2025-11-28** | DC Day 4-8 | ✅ DC Tool C MVP + UX重大改进完成 | +| **2025-12-13** | 架构优化 | ✅ Postgres-Only架构改造完成 | +| **2024-12-24** | **部署启动** 🚀 | ✅ PostgreSQL数据迁移 + 前端/Python镜像推送ACR | +| **当前** | 部署进行中 | 🚧 SAE应用部署 + Node.js后端构建 | --- ## 🎯 下一步计划 -### 短期(1-2周) -1. **ASL全文复筛前端**(Day 6-8) +### 🔥 最高优先级(1-2天)- 部署到生产环境 +1. **Python微服务部署到SAE** + - 创建SAE应用 + - 配置环境变量 + - 健康检查验证 + - 获取内网地址 + +2. **Node.js后端Docker镜像构建** + - 创建Dockerfile + - 配置数据库连接(RDS内网地址) + - 构建并推送到ACR + +3. **Node.js后端部署到SAE** + - 创建SAE应用(2核4GB) + - 配置环境变量(DATABASE_URL、OSS等) + - 配置Python微服务内网地址 + - 健康检查验证 + +4. **前端Nginx部署到SAE** + - 创建SAE应用(1核2GB) + - 配置后端API内网地址 + - 公网域名绑定 + - SSL证书配置 + +5. **全链路验证测试** + - 前端→Node.js后端→Python微服务→RDS + - ASL文献筛选完整流程 + - DC数据清洗完整流程 + - 性能和稳定性测试 + +### 短期(1-2周)- 功能完善 +6. **ASL全文复筛前端**(Day 6-8) - 4个核心页面:设置、进度、工作台、结果 - PDF上传和预览功能 - 双模型判断对比UI - 实时进度监控 -2. **DC工具B完成**(Day 4-7) - - ExtractionService实现 - - 批量提取API - - 前端集成和测试 +7. **DC工具B前端开发** + - 健康检查界面 + - 模板管理界面 + - 批量提取界面 + - 冲突解决界面 -### 中期(1-2月) -3. DC模块完整实现(工具A、工具C、Portal) -4. ASL模块优化(Prompt优化、并发处理) -5. LLM网关统一抽取 +### 中期(1-2月)- 模块完善 +8. DC模块完整实现(工具A、Portal优化) +9. ASL模块优化(Prompt优化、并发处理) +10. 监控和告警系统配置 +11. CI/CD流程建立 -### 长期(3月+) -6. SSA模块(智能统计分析) -7. ST模块(统计分析工具) -8. RVW模块(稿件审查系统) +### 长期(3月+)- 新模块开发 +12. SSA模块(智能统计分析) +13. ST模块(统计分析工具) +14. RVW模块(稿件审查系统) --- @@ -380,6 +548,12 @@ AIclinicalresearch/ - [DC模块README](../03-业务模块/DC-数据清洗整理/README.md) - [DC Day3完成总结](../03-业务模块/DC-数据清洗整理/06-开发记录/Day3完成总结.md) +### 🚀 部署文档(新增) +- ⭐ [00-部署进度总览.md](../05-部署文档/00-部署进度总览.md) - **一站式部署状态查看** +- [01-快速部署SOP-零基础版.md](../05-部署文档/01-快速部署SOP-零基础版.md) - 完整部署流程 +- [07-前端Nginx-SAE部署操作手册.md](../05-部署文档/07-前端Nginx-SAE部署操作手册.md) +- [08-PostgreSQL数据库部署操作手册.md](../05-部署文档/08-PostgreSQL数据库部署操作手册.md) + ### 🏗️ 架构设计 - [平台基础设施规划](../09-架构实施/04-平台基础设施规划.md) - [云原生部署架构指南](../09-架构实施/03-云原生部署架构指南.md) @@ -447,6 +621,13 @@ npm run dev # http://localhost:3000 - 🚧 **开发中**:ASL(80%)、DC(Tool C 98%,Tool B后端100%,Tool B前端0%) - 📋 **未开始**:SSA、ST、RVW +### 部署完成度 +- ✅ **基础设施**:VPC(100%)、NAT网关(100%)、安全组(100%) +- ✅ **数据存储**:RDS PostgreSQL(100%)、OSS(100%) +- ✅ **容器镜像**:前端Nginx(100%)、Python微服务(100%) +- 🚧 **SAE应用**:Python微服务(待部署)、Node.js后端(镜像待构建)、前端Nginx(待部署) +- 📋 **验证测试**:全链路测试(待进行) + ### 测试覆盖率 - **平台基础层**:100%(8/8模块全部通过) - **AIA模块**:手动测试通过 @@ -574,9 +755,9 @@ if (items.length >= 50) { --- -**文档版本**:v1.8 -**最后更新**:2025-12-13 -**下次更新**:Phase 8 全面测试完成 或 Phase 9 SAE 部署完成 +**文档版本**:v2.1 +**最后更新**:2024-12-24 +**下次更新**:SAE应用部署完成 或 全链路验证测试完成 --- diff --git a/docs/02-通用能力层/Postgres-Only异步任务处理指南.md b/docs/02-通用能力层/Postgres-Only异步任务处理指南.md index 5c2863d5..19bf068f 100644 --- a/docs/02-通用能力层/Postgres-Only异步任务处理指南.md +++ b/docs/02-通用能力层/Postgres-Only异步任务处理指南.md @@ -585,3 +585,5 @@ async saveProcessedData(recordId, newData) { **最后更新**: 2025-12-22 **文档状态**: ✅ 已完成 + + diff --git a/docs/02-通用能力层/通用能力层技术债务清单.md b/docs/02-通用能力层/通用能力层技术债务清单.md index b2597aea..4b819cf4 100644 --- a/docs/02-通用能力层/通用能力层技术债务清单.md +++ b/docs/02-通用能力层/通用能力层技术债务清单.md @@ -772,3 +772,5 @@ export const AsyncProgressBar: React.FC = ({ **最后更新**: 2025-12-22 **文档状态**: ✅ 初始版本 + + diff --git a/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md b/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md index 0d515e46..681558e5 100644 --- a/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md +++ b/docs/03-业务模块/ASL-AI智能文献/04-开发计划/05-全文复筛前端开发计划.md @@ -1262,6 +1262,8 @@ 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 90d89c2e..8b985f86 100644 --- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md +++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端开发完成.md @@ -376,6 +376,8 @@ 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 565e8451..7f35e2ac 100644 --- a/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md +++ b/docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-01-23_全文复筛前端逻辑调整.md @@ -319,6 +319,8 @@ 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 e4816b2b..b50e2e66 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 @@ -478,6 +478,8 @@ Failed to open file '\\tmp\\extraction_service\\temp_10000_test.pdf' + + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md index 1feb8352..fa9fbd34 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_AI_Few-shot示例库.md @@ -544,6 +544,8 @@ 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 079a446e..5bbbf8cb 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Bug修复总结_2025-12-08.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Bug修复总结_2025-12-08.md @@ -385,3 +385,5 @@ npm run dev + + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md index 4e0af9d1..b3b830e1 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md @@ -959,6 +959,8 @@ 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 4e4c7945..5514b5b6 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day4-5前端开发计划.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Day4-5前端开发计划.md @@ -1293,6 +1293,8 @@ npm install react-markdown + + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md index 1b3f4f77..b3756f44 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_Pivot列顺序优化总结.md @@ -204,3 +204,5 @@ 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 ef817b76..1eca3dc0 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_方案B实施总结_2025-12-09.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_方案B实施总结_2025-12-09.md @@ -362,3 +362,5 @@ 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 8c8e366b..ea82d0cd 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md @@ -196,3 +196,5 @@ async handleFillnaMice(request, reply) { + + diff --git a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md index 0e950efe..51db0c05 100644 --- a/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md +++ b/docs/03-业务模块/DC-数据清洗整理/04-开发计划/工具C_缺失值处理功能_更新说明.md @@ -168,3 +168,5 @@ 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 efa63634..6e085a91 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md @@ -315,6 +315,8 @@ 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 8f99f4f4..f76c54b6 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day1开发完成总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day1开发完成总结.md @@ -387,6 +387,8 @@ 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 7e16e37c..21a1fca1 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day2开发完成总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-06_工具C_Day2开发完成总结.md @@ -616,6 +616,8 @@ 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 a7a0583e..5ab65caf 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_AI对话核心功能增强总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_AI对话核心功能增强总结.md @@ -621,5 +621,7 @@ 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 48e4bd95..d449e646 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md @@ -272,6 +272,8 @@ 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 b261519a..92caffd2 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 @@ -425,6 +425,8 @@ Response: + + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md index 98df63a5..02a0b8c2 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_Day5最终总结.md @@ -419,6 +419,8 @@ 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 645e0671..2ecc1617 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_UI优化与Bug修复.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_UI优化与Bug修复.md @@ -329,6 +329,8 @@ 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 8cf218ef..505926f2 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_后端API完整对接完成.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_后端API完整对接完成.md @@ -369,6 +369,8 @@ 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 97cf8847..4eb997e9 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_完整UI优化与功能增强.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_完整UI优化与功能增强.md @@ -617,6 +617,8 @@ 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 59004169..b5495e32 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_工具C_Day4前端基础完成.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/2025-12-07_工具C_Day4前端基础完成.md @@ -227,6 +227,8 @@ Day 5 (6-8小时): + + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md index ac942b70..33dc48c7 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/DC模块重建完成总结-Day1.md @@ -405,6 +405,8 @@ 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 b0ce7ff9..82ccc55f 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md @@ -380,6 +380,8 @@ 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 0b128fef..0334853f 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 @@ -364,6 +364,8 @@ 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 d4c5b0b5..b9fa6ebf 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/Portal页面UI优化-2025-12-02.md @@ -324,6 +324,8 @@ + + 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 781ee328..b434065d 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 @@ -278,6 +278,8 @@ 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 0bd2849d..7340f9af 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB-UI优化-2025-12-03.md @@ -327,6 +327,8 @@ + + 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 66727b5e..7f845d2b 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 @@ -290,6 +290,8 @@ + + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md index d0a57650..39054992 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/ToolB浏览器测试计划-2025-12-03.md @@ -354,6 +354,8 @@ + + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md index e34f7538..28cfac9a 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/后端API测试报告-2025-12-02.md @@ -442,6 +442,8 @@ Tool B后端代码**100%复用**了平台通用能力层,无任何重复开发 + + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md index 26f9c425..f4c73f7a 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md @@ -288,6 +288,8 @@ + + diff --git a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md index 49a7c58b..7020ce4e 100644 --- a/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md +++ b/docs/03-业务模块/DC-数据清洗整理/06-开发记录/数据库验证报告-2025-12-02.md @@ -219,6 +219,8 @@ $ 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 0932c943..cbd3deb9 100644 --- a/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md +++ b/docs/03-业务模块/DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md @@ -452,6 +452,8 @@ ${fields.map((f, i) => `${i + 1}. ${f.name}:${f.desc}`).join('\n')} + + diff --git a/docs/05-部署文档/00-部署进度总览.md b/docs/05-部署文档/00-部署进度总览.md new file mode 100644 index 00000000..28e88a8a --- /dev/null +++ b/docs/05-部署文档/00-部署进度总览.md @@ -0,0 +1,699 @@ +# 🚀 AI临床研究平台 - 部署进度总览 + +> **文档用途**:统一展示项目部署状态、资源信息、操作手册索引 +> **更新时间**:2024-12-24 +> **维护人员**:开发团队 + +--- + +## 📊 一、部署进度一览表 + +| 服务名称 | 部署状态 | 镜像版本 | 部署位置 | 完成时间 | 操作文档 | +|---------|---------|---------|---------|---------|---------| +| **PostgreSQL数据库** | ✅ 已完成 | PostgreSQL 15 | RDS | 2024-12-24 | [08-PostgreSQL数据库部署操作手册.md](./08-PostgreSQL数据库部署操作手册.md) | +| **前端Nginx服务** | ✅ 已完成 | v1.0 | SAE(待部署) | 2024-12-24 | [07-前端Nginx-SAE部署操作手册.md](./07-前端Nginx-SAE部署操作手册.md) | +| **Python微服务** | ✅ 镜像已推送 | v1.0 | SAE(待部署) | 2024-12-24 | 待创建 | +| **Node.js后端** | ⏳ 待开始 | - | - | - | - | +| **Dify AI服务** | ⏳ 待开始 | - | - | - | - | + +**图例说明**: +- ✅ 已完成:服务已成功部署并验证 +- 🔄 进行中:正在部署或配置 +- ⏳ 待开始:尚未开始 + +--- + +## 🔑 二、阿里云资源速查表 + +### 2.1 ACR容器镜像仓库 + +**基本信息**: +- **命名空间**:`ai-clinical` +- **Registry地址(公网)**:`crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com` +- **Registry地址(VPC)**:`crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com` +- **用户名**:`gofeng117@163.com` +- **密码**:`fengzhibo117` + +**镜像仓库列表**: + +| 仓库名称 | 最新版本 | 镜像大小 | 公网地址 | VPC地址 | +|---------|---------|---------|---------|---------| +| **python-extraction** | v1.0 | 1.12GB | `crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0` | `crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0` | +| **ai-clinical_frontend-nginx** | v1.0 | ~50MB | `crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0` | `crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0` | +| **nodejs-backend** | - | - | `crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/nodejs-backend` | `crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/nodejs-backend` | + +--- + +### 2.2 VPC网络与NAT网关 + +**VPC信息**: +- **VPC ID**:`vpc-2ze055cptkew9c38w4r06` +- **VPC名称**:`ai-clinical-vpc` +- **网段**:`172.17.0.0/16` +- **地域**:华北2(北京) +- **交换机1**:`vsw-2zevacop039bxrmj6yc0c`(可用区F) +- **交换机2**:`vsw-2zehoeyw9ldncymcyvfwq`(可用区A) +- **安全组ID**:`sg-2zedk6fi8sgmmcwdu7tu` + +**NAT网关信息**: +- **NAT网关名称**:`NAT_airesearch` +- **NAT网关ID**:`ngw-2zeec9ulzgw7ywvx1pst6` +- **公网IP(EIP)**:`182.92.176.14` +- **SNAT表ID**:`stb-2zesszmzx1qpwf1cb2bry` +- **SNAT条目**:覆盖所有交换机,允许VPC内资源访问公网 + +--- + +### 2.3 RDS PostgreSQL数据库 + +**实例信息**: +- **实例ID**:`pgm-2zex1m2y3r23hdn5` +- **规格**:2核4GB(pg.n2.2c.1m) +- **存储空间**:100GB(SSD云盘) +- **PostgreSQL版本**:15.0 +- **内网地址**:`pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432` +- **外网地址**:`pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com`(⚠️ 已关闭) +- **最大连接数**:400 +- **时区**:Asia/Shanghai +- **白名单**:172.17.0.0/16(VPC网段) + +**数据库配置**: +- **数据库名**:`ai_clinical_research` +- **用户名**:`airesearch` +- **密码**:`Xibahe@fengzhibo117` +- **字符集**:UTF8 +- **排序规则**:en_US.utf8 + +**Schema架构**(11个业务Schema): +| Schema名称 | 功能模块 | 表数量 | 说明 | +|-----------|---------|-------|------| +| `platform_schema` | 平台核心 | 8 | 用户、权限、任务队列(pg-boss) | +| `asl_schema` | 系统文献筛查 | 6 | 项目、文献、筛查记录 | +| `aia_schema` | AI智能摘要 | 5 | AI项目、摘要任务 | +| `dc_schema` | 数据清洗 | 6 | 工具A/B/C数据处理 | +| `pkb_schema` | 个人知识库 | 5 | 文献管理、笔记 | +| `admin_schema` | 系统管理 | 0 | 预留 | +| `rvw_schema` | 文献回顾 | 0 | 预留 | +| `ssa_schema` | 智能统计分析 | 0 | 预留 | +| `st_schema` | 统计工具 | 0 | 预留 | +| `common_schema` | 公共模块 | 0 | 预留 | +| `information_schema` | 系统元数据 | - | PostgreSQL标准 | + +**关键数据量**(截至2024-12-24): +- 用户:3条 +- AI项目:2条 +- 文献:1204条 +- 筛查记录:783条 +- pg-boss任务:350条 + +**连接字符串格式**: +``` +postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research +``` +⚠️ 注意:密码中的 `@` 需要URL编码为 `%40` + +--- + +### 2.4 SAE Serverless应用 + +**命名空间**: +- **命名空间ID**:`cn-beijing:test-airesearch` +- **地域**:华北2(北京) + +**已部署/待部署应用列表**: + +| 应用名称 | 状态 | 规格 | 实例数 | 端口 | 内网地址 | 公网地址 | +|---------|------|------|-------|------|---------|---------| +| **python-extraction** | 镜像已推送 | 1核2GB | 1 | 8000 | 待部署后填写 | 待部署后填写 | +| **nodejs-backend** | 待构建 | 2核4GB | 1 | 3001 | 待部署后填写 | 待部署后填写 | +| **frontend-nginx** | 镜像已推送 | 1核2GB | 1 | 80 | 待部署后填写 | 待部署后填写 | + +--- + +### 2.5 OSS对象存储 + +**Bucket信息**: +- **Bucket名称**:`ai-clinical-research` +- **地域**:华北2(北京) +- **存储类型**:标准存储 +- **访问控制**:私有 +- **存储冗余类型**:同城冗余存储 +- **内网Endpoint**:`oss-cn-beijing-internal.aliyuncs.com` +- **公网Endpoint**:`oss-cn-beijing.aliyuncs.com` +- **Bucket域名(内网)**:`ai-clinical-research.oss-cn-beijing-internal.aliyuncs.com` +- **创建时间**:2025-12-16 20:22 + +**RAM用户访问凭证**(用于OSS写入): +- **RAM用户名**:`oss-bucket-put-object@1991407246109125.onaliyun.com` +- **AccessKeyId**:`LTAI5tB2Dt3NdvBL3G7nYGv7` +- **AccessKeySecret**:`1iSN9k39RkApP93QjUhC1DcPIeMG4V` +- **UID**:`203256565888301026` +- **创建时间**:2025-12-16 20:31:41 + +⚠️ **安全警告**:AccessKey是敏感信息,请勿提交到公开Git仓库! + +**存储用途**: +- `/uploads/pdfs/` - PDF文件上传 +- `/uploads/docx/` - Word文档上传 +- `/uploads/txt/` - 文本文件上传 +- `/exports/` - 导出文件临时存储 + +--- + +--- + +### 2.6 镜像配置文件存储位置 + +**前端Nginx服务**: +``` +AIclinicalresearch/frontend-v2/ +├── Dockerfile ✅ 已提交Git(多阶段构建) +├── .dockerignore ✅ 已提交Git(优化构建上下文) +├── nginx.conf ✅ 已提交Git(Nginx配置) +└── docker-entrypoint.sh ✅ 已提交Git(启动脚本) + +镜像存储位置: +公网:crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0 +VPC:crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0 +``` + +**Python微服务**: +``` +AIclinicalresearch/extraction_service/ +├── Dockerfile ✅ 已提交Git(多阶段构建 + 阿里云源) +├── .dockerignore ✅ 已提交Git(优化构建上下文) +└── requirements-prod.txt ✅ 已提交Git(精简依赖列表) + +镜像存储位置: +公网:crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0 +VPC:crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0 +``` + +**Node.js后端**(待构建): +``` +AIclinicalresearch/backend/ +├── Dockerfile ⏳ 待创建 +├── .dockerignore ⏳ 待创建 +└── (配置文件) ⏳ 待确认 + +镜像存储位置(预留): +公网:crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/nodejs-backend:v1.0 +VPC:crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/nodejs-backend:v1.0 +``` + +**Git提交规范**: +| 文件类型 | 是否提交Git | 说明 | +|---------|------------|------| +| ✅ Dockerfile | 必须提交 | 镜像构建蓝图,团队协作必需 | +| ✅ .dockerignore | 必须提交 | 优化构建性能,避免传输无用文件 | +| ✅ requirements*.txt / package.json | 必须提交 | 依赖清单,可复现构建 | +| ✅ nginx.conf / 配置文件 | 必须提交 | 服务配置 | +| ❌ .env | 禁止提交 | 敏感信息(密码、API密钥) | +| ❌ Docker镜像文件(.tar) | 禁止提交 | 镜像文件很大,存储在ACR云端 | + +--- + +## 📦 三、已部署服务详情 + +### 3.1 PostgreSQL数据库 + +**部署概要**: +- **部署时间**:2024-12-24 +- **部署方式**:`pg_dump` 全量导出 → RDS导入 +- **数据迁移时长**:约12秒(90MB SQL文件) +- **验证状态**:✅ Schema完整、数据一致、关系正确 + +**关键配置**: +```bash +# 本地PostgreSQL Docker容器 +docker run --name ai-clinical-postgres \ + -e POSTGRES_PASSWORD=postgres \ + -e POSTGRES_DB=ai_clinical_research \ + -p 5432:5432 \ + -d postgres:15-alpine +``` + +**备份信息**: +- **本地备份文件**:`AIclinicalresearch/rds_init_20251224_154529.sql`(90MB) +- **备份内容**:完整Schema + 全量数据 +- **RDS自动备份**:每日凌晨2点(保留7天) + +**操作文档**: +- [08-PostgreSQL数据库部署操作手册.md](./08-PostgreSQL数据库部署操作手册.md) - 完整部署流程 +- [PostgreSQL部署策略-摸底报告.md](./PostgreSQL部署策略-摸底报告.md) - 数据库分析报告 + +**重要提示**: +- ⚠️ **安全**:外网访问已关闭,生产环境禁止长期开启 +- ⚠️ **连接**:需通过VPC内网或SSH隧道连接 +- ⚠️ **密码**:环境变量中的 `@` 需转义为 `%40` + +--- + +### 3.2 前端Nginx服务 + +**镜像信息**: +- **仓库名称**:`ai-clinical_frontend-nginx` +- **镜像版本**:`v1.0` +- **镜像大小**:约50MB +- **基础镜像**:`nginx:alpine` +- **构建时间**:2024-12-24 + +**镜像功能**: +- ✅ 托管React单页应用(SPA) +- ✅ Nginx反向代理API请求 +- ✅ 支持动态环境变量注入 +- ✅ Gzip压缩优化 +- ✅ 健康检查端点 + +**构建产物**: +- **Dockerfile**:`AIclinicalresearch/frontend-v2/Dockerfile` +- **Nginx配置**:`AIclinicalresearch/frontend-v2/nginx.conf` +- **.dockerignore**:`AIclinicalresearch/frontend-v2/.dockerignore` + +**SAE配置建议**: +- **CPU/内存**:1核 / 2GB +- **实例数**:1 +- **端口**:80 +- **健康检查**:`GET /` 返回200 +- **环境变量**: + ```bash + VITE_API_BASE_URL=http://nodejs-backend-service.cn-beijing:test-airesearch.svc.cluster.local:3001 + ``` + ⚠️ 注意:内网地址需在SAE部署后获取 + +**操作文档**: +- [07-前端Nginx-SAE部署操作手册.md](./07-前端Nginx-SAE部署操作手册.md) - 完整SAE部署步骤 +- [06-前端Nginx-SAE容器部署指南.md](./06-前端Nginx-SAE容器部署指南.md) - 技术架构详解 + +**部署状态**: +- ✅ Docker镜像构建成功 +- ✅ 镜像已推送至ACR +- ⏳ 待部署到SAE + +--- + +### 3.3 Python微服务 + +**镜像信息**: +- **仓库名称**:`python-extraction` +- **镜像版本**:`v1.0` +- **镜像大小**:1.12GB +- **基础镜像**:`python:3-slim` +- **构建时间**:2024-12-24 + +**功能模块**: +- ✅ **PDF文本提取**:PyMuPDF 1.26.7 +- ✅ **Docx文档提取**:Mammoth + python-docx +- ✅ **数据清洗(DC工具)**:pandas 2.0+ / numpy 1.24+ / polars 0.19+ +- ✅ **语言检测**:langdetect +- ❌ **Nougat OCR**:已移除(减小镜像1.5GB) + +**依赖优化**: +```txt +# 精简版依赖(requirements-prod.txt) +- 移除:nougat-ocr (1.5GB) +- 移除:albumentations (Nougat依赖) +- 保留:pandas、numpy、polars(DC工具必需) +- 保留:PyMuPDF、pdfplumber(PDF提取) +``` + +**健康检查**: +- **端点**:`GET /api/health` +- **响应示例**: + ```json + { + "status": "healthy", + "checks": { + "pymupdf": {"available": true, "version": "1.26.7"}, + "nougat": {"available": false, "error": "Nougat未安装"}, + "temp_dir": {"path": "/tmp/extraction_service", "writable": true} + } + } + ``` + +**SAE配置建议**: +- **CPU/内存**:1核 / 2GB +- **实例数**:1 +- **端口**:8000 +- **启动命令**:默认(Dockerfile中的CMD) +- **健康检查**:`GET /api/health` 返回200 +- **环境变量**: + ```bash + LOG_LEVEL=INFO + TEMP_DIR=/tmp/extraction_service + ``` + ⚠️ 生产环境建议根据实际负载调整实例数 + +**构建产物**: +- **Dockerfile**:`AIclinicalresearch/extraction_service/Dockerfile` +- **依赖文件**:`AIclinicalresearch/extraction_service/requirements-prod.txt` +- **.dockerignore**:`AIclinicalresearch/extraction_service/.dockerignore` + +**关键技术方案**: +- ✅ 使用阿里云Debian镜像源(解决apt-get网络问题) +- ✅ 多阶段构建(优化镜像大小) +- ✅ 运行时依赖安装(libgl1、libglib2.0) + +**操作文档**: +- [04-Python微服务-SAE容器部署指南.md](./04-Python微服务-SAE容器部署指南.md) - 技术架构详解 +- 待创建:Python微服务SAE部署操作手册 + +**部署状态**: +- ✅ Docker镜像构建成功(本地测试通过) +- ✅ 镜像已推送至ACR +- ⏳ 待部署到SAE + +--- + +## ⚡ 四、快速命令参考 + +### 4.1 Docker镜像管理 + +**登录ACR**: +```bash +# 使用公网地址登录 +docker login --username=gofeng117@163.com \ + --password=fengzhibo117 \ + crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com +``` + +**拉取镜像**: +```bash +# 前端Nginx +docker pull crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0 + +# Python微服务 +docker pull crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0 +``` + +**本地测试**: +```bash +# 前端Nginx(端口3000) +docker run -d -p 3000:80 \ + -e VITE_API_BASE_URL=http://localhost:3001 \ + --name frontend-test \ + ai-clinical_frontend-nginx:v1.0 + +# Python微服务(端口8000) +docker run -d -p 8000:8000 \ + --name python-test \ + python-extraction:v1.0 + +# 查看日志 +docker logs -f frontend-test +docker logs -f python-test + +# 健康检查 +curl http://localhost:3000 # 前端 +curl http://localhost:8000/api/health # Python微服务 +``` + +**构建新版本**: +```bash +# 前端Nginx +cd AIclinicalresearch/frontend-v2 +docker build -t ai-clinical_frontend-nginx:v1.1 . +docker tag ai-clinical_frontend-nginx:v1.1 \ + crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.1 +docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.1 + +# Python微服务 +cd AIclinicalresearch/extraction_service +docker build -t python-extraction:v1.1 -f Dockerfile . +docker tag python-extraction:v1.1 \ + crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.1 +docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.1 +``` + +--- + +### 4.2 数据库连接与管理 + +**通过本地Docker容器连接RDS**: +```bash +# 启动本地PostgreSQL容器(用于psql客户端) +docker run --name ai-clinical-postgres \ + -e POSTGRES_PASSWORD=postgres \ + -p 5432:5432 \ + -d postgres:15-alpine + +# 连接到RDS(需临时开启外网或使用VPC) +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" \ + ai-clinical-postgres psql \ + -h pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com \ + -p 5432 \ + -U airesearch \ + -d ai_clinical_research + +# 查看Schema列表 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" \ + ai-clinical-postgres psql \ + -h pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com \ + -p 5432 -U airesearch -d ai_clinical_research \ + -c "SELECT nspname FROM pg_namespace WHERE nspname LIKE '%_schema' ORDER BY nspname;" + +# 查看表数量统计 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" \ + ai-clinical-postgres psql \ + -h pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com \ + -p 5432 -U airesearch -d ai_clinical_research \ + -c "SELECT schemaname, COUNT(*) FROM pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema') GROUP BY schemaname;" +``` + +**数据库备份**: +```bash +# 导出完整数据库 +docker exec ai-clinical-postgres pg_dump \ + -U postgres \ + -d ai_clinical_research \ + --format=plain \ + --no-owner \ + --no-acl \ + --encoding=UTF8 \ + > "backup_$(date +%Y%m%d_%H%M%S).sql" + +# 导入到RDS(需临时开启外网) +cat backup_20241224_154529.sql | \ + docker exec -i -e PGPASSWORD="Xibahe@fengzhibo117" \ + ai-clinical-postgres psql \ + -h pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com \ + -p 5432 -U airesearch -d ai_clinical_research +``` + +**Node.js应用连接字符串**: +```bash +# .env 文件配置 +DATABASE_URL="postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research" + +# 注意:@ 符号需要URL编码为 %40 +``` + +--- + +### 4.3 SAE常用操作 + +**通过阿里云CLI部署**(可选): +```bash +# 安装阿里云CLI +# https://help.aliyun.com/document_detail/121541.html + +# 配置访问凭证 +aliyun configure + +# 部署应用(示例) +aliyun sae DeployApplication \ + --AppId xxx \ + --ImageUrl crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0 \ + --Namespace cn-beijing:xxx +``` + +**通过Web控制台部署**(推荐): +1. 登录阿里云SAE控制台 +2. 选择应用 → 部署应用 +3. 选择镜像版本 +4. 配置环境变量 +5. 确认部署 + +--- + +## ⚠️ 五、注意事项与最佳实践 + +### 5.1 安全规范 🔒 + +**数据库安全**: +- ❌ **禁止**:RDS外网地址长期开启 +- ✅ **推荐**:使用VPC内网或SSH隧道连接 +- ✅ **白名单**:仅允许必要的IP访问 +- ✅ **密码强度**:使用复杂密码(大小写+数字+特殊字符) + +**镜像仓库安全**: +- ❌ **禁止**:在代码中硬编码ACR密码 +- ✅ **推荐**:定期轮换Registry密码(每季度) +- ✅ **访问控制**:仅团队成员拥有推送权限 + +**环境变量管理**: +- ❌ **禁止**:在Git中提交 `.env` 文件 +- ✅ **推荐**:使用SAE的环境变量配置功能 +- ✅ **敏感信息**:数据库密码、API密钥等使用环境变量 + +**SSL/TLS**: +- ✅ 生产环境必须启用HTTPS +- ✅ 使用阿里云免费SSL证书或Let's Encrypt + +--- + +### 5.2 部署顺序 📋 + +**推荐的部署顺序**: +1. ✅ **基础设施**:VPC、NAT网关、安全组 +2. ✅ **数据库**:RDS PostgreSQL(数据迁移+验证) +3. ✅ **对象存储**:OSS Bucket创建+权限配置 +4. 🔄 **后端服务**: + - Python微服务(文档提取+数据清洗) + - Node.js后端(API服务器) +5. 🔄 **前端服务**:Nginx静态资源托管 +6. 🔄 **AI服务**:Dify部署 +7. 🔄 **验证测试**:全链路功能验证 + +**依赖关系**: +``` +RDS PostgreSQL (必需) + ↓ +Node.js 后端 (依赖数据库) + ↓ +Python 微服务 (可独立,但后端会调用) + ↓ +前端 Nginx (依赖后端API) + ↓ +Dify AI (可独立) +``` + +--- + +### 5.3 回滚策略 🔄 + +**镜像版本管理**: +- ACR保留所有历史版本(v1.0, v1.1, v1.2...) +- 使用语义化版本号:`major.minor.patch` +- 生产环境使用固定版本号,禁止使用 `:latest` + +**SAE应用回滚**: +- SAE支持一键回滚到上一版本 +- 回滚时长:约1-2分钟 +- 建议:部署前先在测试环境验证 + +**数据库回滚**: +- RDS自动备份:每日凌晨2点(保留7天) +- 手动备份:重大变更前务必手动备份 +- 回滚时长:取决于数据量(约10分钟/10GB) + +--- + +### 5.4 监控与日志 📊 + +**应用监控**(建议配置): +- **健康检查**:每个服务配置健康检查端点 +- **日志收集**:SAE自动收集stdout/stderr日志 +- **告警规则**:CPU>80%、内存>80%、健康检查失败 + +**日志查看**: +```bash +# SAE控制台 → 应用详情 → 日志查询 +# 或使用阿里云CLI +aliyun sae DescribeApplicationInstances --AppId xxx +``` + +**性能指标**: +- **响应时间**:API平均响应<500ms +- **错误率**:<1% +- **可用性**:>99.9% + +--- + +### 5.5 成本优化 💰 + +**SAE资源配置**: +- **开发环境**:0.5核 / 1GB(约¥30/月) +- **生产环境**:1核 / 2GB(约¥60/月) +- **弹性伸缩**:根据流量自动扩缩容 + +**RDS成本**: +- **按量付费**:测试阶段使用 +- **包年包月**:生产环境更优惠(约¥800/月) + +**OSS成本**: +- **存储费用**:约¥0.12/GB/月 +- **流量费用**:内网流量免费,外网流量¥0.5/GB + +--- + +## 📝 六、待办事项清单 + +### 高优先级 🔴 +- [ ] **Python微服务**:部署到SAE并验证 +- [ ] **Python微服务**:创建SAE部署操作手册 +- [ ] **Node.js后端**:Docker镜像构建 +- [ ] **Node.js后端**:部署到SAE + +### 中优先级 🟡 +- [ ] **前端Nginx**:部署到SAE并配置域名 +- [ ] **内网通信**:配置前端→后端→Python微服务的内网调用 +- [ ] **SSL证书**:申请并配置HTTPS +- [ ] **监控告警**:配置SAE健康检查和告警规则 + +### 低优先级 🟢 +- [ ] **Dify AI**:评估部署方案 +- [ ] **负载测试**:压力测试各服务性能 +- [ ] **文档完善**:补充故障排查手册 +- [ ] **CI/CD**:配置自动化部署流程 + +--- + +## 📚 七、相关文档索引 + +### 部署指南 +- [01-快速部署SOP-零基础版.md](./01-快速部署SOP-零基础版.md) - **完整部署流程总纲** +- [02-SAE部署完全指南(产品经理版).md](./02-SAE部署完全指南(产品经理版).md) - SAE基础知识 + +### 服务部署手册 +- [07-前端Nginx-SAE部署操作手册.md](./07-前端Nginx-SAE部署操作手册.md) - 前端Nginx部署步骤 +- [08-PostgreSQL数据库部署操作手册.md](./08-PostgreSQL数据库部署操作手册.md) - PostgreSQL部署步骤 +- 待创建:Python微服务SAE部署操作手册 +- 待创建:Node.js后端SAE部署操作手册 + +### 技术架构文档 +- [00-部署架构总览.md](./00-部署架构总览.md) - 架构设计与技术选型 +- [04-Python微服务-SAE容器部署指南.md](./04-Python微服务-SAE容器部署指南.md) - Python服务技术详解 +- [06-前端Nginx-SAE容器部署指南.md](./06-前端Nginx-SAE容器部署指南.md) - 前端Nginx技术详解 + +### 分析报告 +- [PostgreSQL部署策略-摸底报告.md](./PostgreSQL部署策略-摸底报告.md) - 数据库结构分析 + +--- + +## 🔄 八、更新日志 + +### 2024-12-24 +- ✅ PostgreSQL数据库部署完成 +- ✅ 前端Nginx Docker镜像构建并推送至ACR +- ✅ Python微服务Docker镜像构建并推送至ACR +- ✅ 创建部署进度总览文档 + +--- + +## 📞 九、联系与支持 + +**技术支持**: +- 开发团队内部文档 +- 阿里云工单:https://workorder.console.aliyun.com/ + +**紧急联系**: +- 数据库问题:先检查 [08-PostgreSQL数据库部署操作手册.md] +- SAE部署问题:先检查 [01-快速部署SOP-零基础版.md] +- 镜像构建问题:查看本文档"快速命令参考"章节 + +--- + +> **提示**:本文档会随着部署进度持续更新,请定期查看最新版本! +> **最后更新**:2024-12-24 + diff --git a/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md b/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md index 0d9a9ba0..a85a3870 100644 --- a/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md +++ b/docs/05-部署文档/02-SAE部署完全指南(产品经理版).md @@ -862,3 +862,5 @@ ACR镜像仓库: + + diff --git a/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md b/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md new file mode 100644 index 00000000..be6919f6 --- /dev/null +++ b/docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md @@ -0,0 +1,1353 @@ +# 前端 Nginx - SAE 部署操作手册 + +**文档版本**: v1.0 +**创建时间**: 2025-12-23 +**适用范围**: AIclinicalresearch 平台前端服务 +**部署目标**: 阿里云 SAE(Serverless 应用引擎) +**镜像仓库**: 阿里云 ACR 个人版 + +--- + +## 📋 目录 + +1. [前置条件检查](#1-前置条件检查) +2. [镜像信息确认](#2-镜像信息确认) +3. [创建SAE应用](#3-创建sae应用) +4. [配置环境变量](#4-配置环境变量) +5. [配置健康检查](#5-配置健康检查) +6. [配置公网访问](#6-配置公网访问) +7. [部署应用](#7-部署应用) +8. [验证部署](#8-验证部署) +9. [常见问题排查](#9-常见问题排查) +10. [日常运维](#10-日常运维) + +--- + +## 1. 前置条件检查 + +### ✅ **部署前必须完成的准备** + +| 检查项 | 状态 | 说明 | +|--------|------|------| +| **ACR镜像已推送** | ☑️ | 镜像地址:`crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0.0` | +| **后端服务已部署** | ⬜ | 需要获取后端VPC内网地址(格式:`172.17.x.x:3001`) | +| **VPC网络已创建** | ☑️ | VPC ID: `vpc-2ze055cptkew9c38w4r06` | +| **交换机已创建** | ☑️ | 交换机 ID: `vsw-2zevacop039bxrmj6yc0c` (可用区F) | +| **安全组已创建** | ☑️ | 安全组 ID: `sg-2zedk6fi8sgmmcwdu7tu` | + +### 🔑 **必需的配置信息** + +准备以下信息(在部署过程中需要): + +```yaml +# ACR 镜像信息 +ACR域名(专有网络): crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com +命名空间: ai-clinical +镜像名称: ai-clinical_frontend-nginx +镜像版本: v1.0.0 + +# VPC网络信息 +VPC ID: vpc-2ze055cptkew9c38w4r06 +交换机ID: vsw-2zevacop039bxrmj6yc0c +安全组ID: sg-2zedk6fi8sgmmcwdu7tu + +# 后端服务信息(从后端SAE应用获取) +后端内网地址: 待获取(格式:172.17.x.x) +后端端口: 3001 +``` + +--- + +## 2. 镜像信息确认 + +### 📦 **ACR 镜像详情** + +```yaml +服务类型: 个人版(免费) +命名空间: ai-clinical +仓库名称: ai-clinical_frontend-nginx + +镜像完整地址(专有网络): + crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0.0 + +镜像标签: + - v1.0.0 (生产版本,digest: 68e97e28...) + - latest (指向最新版本) + +镜像大小: 91.9 MB +构建时间: 2025-12-23 +``` + +### 🔍 **验证镜像存在** + +登录ACR控制台验证:https://cr.console.aliyun.com/ + +1. 进入【个人版】→【镜像仓库】 +2. 找到 `ai-clinical_frontend-nginx` +3. 确认存在 `v1.0.0` 标签 + +--- + +## 3. 创建SAE应用 + +### 📍 **登录SAE控制台** + +访问:https://sae.console.aliyun.com/ + +选择地域:**华北2(北京)** + +### 🆕 **创建新应用** + +点击【创建应用】,按以下步骤填写: + +#### **步骤1:应用基本信息** + +```yaml +应用名称: frontend-nginx-service +应用描述: AI临床研究平台 - 前端静态资源服务(React SPA + Nginx) +命名空间: 默认命名空间(或与后端同一命名空间) +``` + +#### **步骤2:应用部署方式** + +```yaml +部署方式: 镜像 +技术栈语言: 不限 +``` + +#### **步骤3:应用实例规格** + +```yaml +实例规格: 0.5核 1GB + + 说明: + - 前端Nginx占用资源极少 + - 0.5核1GB完全够用 + - 对比:后端需要2核4GB,Python需要2核4GB + +实例数量: 2 + + 说明: + - 最小2个实例保证高可用 + - 1个实例故障时,另1个继续服务 + - 前端很少需要扩容 +``` + +**为什么前端只需要0.5核1GB?** + +| 服务类型 | 推荐规格 | 原因 | +|---------|---------|------| +| Node.js 后端 | 2核4GB | 处理AI对话、数据库查询、业务逻辑 | +| Python 微服务 | 2核4GB | PDF提取是CPU密集型操作 | +| **Nginx 前端** | **0.5核1GB** | **仅提供静态文件,消耗极少** | + +#### **步骤4:VPC网络配置** + +```yaml +VPC: vpc-2ze055cptkew9c38w4r06 (172.17.0.0/16) + +交换机: vsw-2zevacop039bxrmj6yc0c + 可用区: 华北2可用区F + 网段: 172.17.0.0/24 + +安全组: sg-2zedk6fi8sgmmcwdu7tu + + ⚠️ 重要:必须与后端服务在同一VPC,否则无法通信 +``` + +#### **步骤5:镜像配置** + +```yaml +镜像类型: 容器镜像服务个人版 + +镜像地址: crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0.0 + + ⚠️ 注意事项: + - 使用专有网络域名(带-vpc后缀),不使用公网域名 + - 完整输入镜像地址(包括命名空间和标签) + - 不要遗漏版本号 :v1.0.0 + +镜像版本: v1.0.0 + +镜像拉取策略: 总是拉取镜像(Always) + + 说明: + - 每次部署都拉取最新镜像 + - 确保使用最新代码 + - 避免使用缓存的旧镜像 +``` + +#### **步骤6:应用容器配置** + +```yaml +容器端口: 80 + + 说明: + - Nginx默认监听80端口 + - 与Dockerfile中的EXPOSE 80一致 + +协议: TCP + +启动命令: + - 不填(使用Dockerfile中的ENTRYPOINT) + +工作目录: + - 不填(使用Dockerfile中的WORKDIR) +``` + +--- + +## 4. 配置环境变量 + +### ⚠️ **极其重要:后端服务地址配置** + +环境变量配置错误是最常见的部署失败原因! + +### 📍 **获取后端内网地址** + +**在配置前端之前,必须先获取后端的VPC内网地址:** + +1. 登录 SAE 控制台 +2. 进入应用列表 +3. 找到 `nodejs-backend-service`(你的后端应用名称) +4. 点击进入应用详情 +5. 查看【应用访问配置】→【VPC内网访问地址】 + +示例格式: +``` +172.17.0.15:3001 +``` + +将IP地址和端口分别记录下来。 + +### 🔧 **配置环境变量** + +在SAE应用配置页面,找到【环境变量】配置项: + +```yaml +# 必需配置(必填) +BACKEND_SERVICE_HOST: 172.17.0.15 + + 说明: + - 这是后端服务的VPC内网IP地址(从上一步获取) + - 不要加http://前缀 + - 不要包含端口号 + - 如果不配置,容器启动会失败并报错 + +# 可选配置(有默认值) +BACKEND_SERVICE_PORT: 3001 + + 说明: + - 后端服务的端口号 + - 默认值是3001 + - 如果你的后端使用其他端口,需要修改 +``` + +### ❌ **常见错误** + +| 错误配置 | 正确配置 | 说明 | +|---------|---------|------| +| `http://172.17.0.15` | `172.17.0.15` | 不要加协议前缀 | +| `172.17.0.15:3001` | `172.17.0.15` | 不要包含端口(端口单独配置) | +| `backend-service` | `172.17.0.15` | 必须使用IP,不要用主机名 | +| `localhost` | `172.17.0.15` | 不能用localhost | +| 不配置 | `172.17.0.15` | 必须配置,否则启动失败 | + +### ✅ **配置验证** + +配置完成后,点击【验证】,确保: +- ✅ 变量名称拼写正确(区分大小写) +- ✅ 变量值格式正确(纯IP地址) +- ✅ 没有多余的空格 + +--- + +## 5. 配置健康检查 + +### 🏥 **健康检查配置** + +```yaml +检查方式: HTTP 请求 + +检查路径: /health + + 说明: + - Nginx配置中专门提供的健康检查端点 + - 返回纯文本 "healthy" + - 不依赖后端服务 + +检查端口: 80 + 说明:与容器端口一致 + +检查协议: HTTP + 说明:不是HTTPS + +超时时间: 3秒 + 说明:静态端点,3秒足够 + +检查间隔: 10秒 + 说明:每10秒检查一次 + +不健康阈值: 3次 + 说明:连续失败3次后标记为不健康 + +健康阈值: 2次 + 说明:连续成功2次后标记为健康 + +初始延迟: 30秒 + 说明: + - Nginx启动很快(5-10秒) + - 30秒足够镜像拉取和容器启动 +``` + +### 🔍 **健康检查原理** + +``` +SAE健康检查器 + ↓ (每10秒) +curl http://容器IP:80/health + ↓ +Nginx处理 /health 请求 + ↓ +返回: HTTP 200 + "healthy" + ↓ +SAE标记实例为健康 ✅ +``` + +**如果健康检查失败,SAE会:** +1. 标记实例为不健康 +2. 停止向该实例转发流量 +3. 连续失败3次后,重启容器 + +--- + +## 6. 配置公网访问 + +### 🌐 **访问方式选择** + +#### **方案A:使用SAE提供的公网地址(推荐用于测试)** + +```yaml +配置方式: + 1. 在应用配置页面找到【应用访问配置】 + 2. 开启【公网访问】 + 3. SAE自动分配域名 + +获得的访问地址: + 格式: frontend-nginx-service-xxxxx.cn-beijing.sae.aliyuncs.com + 协议: HTTPS(SAE自动配置证书) + +优点: + - ✅ 免费 + - ✅ 自动HTTPS + - ✅ 立即可用 + +缺点: + - ❌ 域名难记 + - ❌ 无法自定义域名 + - ❌ 证书是SAE的,不是你的域名 +``` + +#### **方案B:绑定自定义域名(推荐用于生产)** + +```yaml +前置条件: + - 已有自己的域名(如 app.yizheng.ai) + - 域名已备案(如果服务器在中国大陆) + - 有SSL证书(可以使用免费的Let's Encrypt) + +配置步骤: + 1. 在域名服务商添加CNAME解析 + app.yizheng.ai → frontend-nginx-service-xxxxx.cn-beijing.sae.aliyuncs.com + + 2. 在SAE控制台绑定域名 + 【应用访问配置】→【自定义域名】→【添加域名】 + + 3. 上传SSL证书 + 【应用访问配置】→【HTTPS设置】→【上传证书】 + + 4. 启用强制HTTPS + 开启【强制HTTPS跳转】 + +获得的访问地址: + https://app.yizheng.ai + +优点: + - ✅ 品牌域名 + - ✅ 用户信任度高 + - ✅ SEO友好 + +缺点: + - ⚠️ 需要域名和证书 + - ⚠️ 需要ICP备案(如果在中国) +``` + +### 🔒 **HTTPS配置(生产环境必须)** + +如果使用方案B(自定义域名),强烈建议配置HTTPS: + +```yaml +证书来源选择: + + 方案1: 使用免费的Let's Encrypt证书 + - 阿里云SSL证书服务可以申请免费证书 + - 有效期3个月,需要定期更新 + + 方案2: 购买商业证书 + - 有效期1年 + - 品牌信任度更高 + - 支持更多特性 + +证书配置: + 1. 准备证书文件 + - 证书文件:domain.crt 或 domain.pem + - 私钥文件:domain.key + + 2. 在SAE上传证书 + 【应用访问配置】→【HTTPS设置】→【上传证书】 + + 3. 启用强制HTTPS + 开启【HTTP自动跳转HTTPS】 +``` + +--- + +## 7. 部署应用 + +### 🚀 **执行部署** + +确认所有配置无误后: + +1. 回到应用配置页面顶部 +2. 点击【部署】按钮 +3. 确认部署信息 +4. 点击【确定】 + +### ⏱️ **部署过程(约2-3分钟)** + +``` +1. 镜像拉取阶段 (30-60秒) + ├─ SAE连接到ACR + ├─ 验证镜像存在 + ├─ 下载镜像层(91.9MB) + └─ 解压镜像 + +2. 容器启动阶段 (10-20秒) + ├─ 创建容器 + ├─ 注入环境变量 + ├─ 执行docker-entrypoint.sh + ├─ envsubst替换nginx.conf + ├─ 验证Nginx配置 + └─ 启动Nginx进程 + +3. 健康检查阶段 (30-60秒) + ├─ 等待30秒(初始延迟) + ├─ 第1次检查 /health + ├─ 第2次检查 /health(10秒后) + └─ 标记为健康 ✅ + +4. 流量切换阶段 (5-10秒) + ├─ 将新实例加入负载均衡 + ├─ 从负载均衡移除旧实例 + └─ 部署完成 ✅ +``` + +### 📊 **部署状态监控** + +部署过程中可以实时查看: + +```yaml +查看方式: + 【应用详情】→【实例列表】→【查看实例状态】 + +状态说明: + - 创建中: 正在拉取镜像 + - 启动中: 正在启动容器 + - 运行中: 容器已启动,等待健康检查 + - 健康: 健康检查通过,可以接收流量 ✅ + - 不健康: 健康检查失败 ❌ + - 停止: 实例已停止 +``` + +### ❌ **部署失败常见原因** + +| 失败阶段 | 错误信息 | 解决方法 | +|---------|---------|---------| +| 镜像拉取 | `image not found` | 检查镜像地址是否正确,确认使用-vpc域名 | +| 镜像拉取 | `unauthorized` | 检查ACR访问权限,确认SAE有拉取权限 | +| 容器启动 | `BACKEND_SERVICE_HOST required` | 检查环境变量是否配置 | +| 健康检查 | `connection refused` | 检查容器端口配置(应该是80) | +| 健康检查 | `404 not found` | 检查健康检查路径(应该是/health) | + +--- + +## 8. 验证部署 + +### ✅ **验证清单** + +部署成功后,按以下步骤验证: + +#### **步骤1:查看实例状态** + +```bash +位置: 【应用详情】→【实例列表】 + +检查项: + ☑️ 实例数量: 2个实例 + ☑️ 实例状态: 全部显示"健康" + ☑️ 健康检查: 全部通过 +``` + +#### **步骤2:查看启动日志** + +```bash +位置: 【应用详情】→【日志】→【实时日志】 + +应该看到: +============================================ +Starting Frontend Nginx Service +Backend Service: 172.17.0.15:3001 +Container Timezone: Asia/Shanghai +Current Time: Tue Dec 23 21:07:35 CST 2025 +============================================ +nginx: configuration file /etc/nginx/nginx.conf test is successful + +✅ 如果看到以上日志,说明配置正确 +❌ 如果看到 "BACKEND_SERVICE_HOST required",说明环境变量未配置 +``` + +#### **步骤3:测试健康检查端点** + +```bash +# 获取公网访问地址 +公网地址: https://frontend-nginx-service-xxxxx.cn-beijing.sae.aliyuncs.com + +# 测试健康检查(使用浏览器或curl) +访问: https://frontend-nginx-service-xxxxx.cn-beijing.sae.aliyuncs.com/health + +预期返回: + Status: 200 OK + Content: healthy + +✅ 如果返回 "healthy",说明前端服务正常 +``` + +#### **步骤4:测试主页访问** + +```bash +# 访问主页 +访问: https://frontend-nginx-service-xxxxx.cn-beijing.sae.aliyuncs.com/ + +检查项: + ☑️ 页面能正常加载(不是空白页) + ☑️ 看到React应用界面 + ☑️ CSS样式正确显示 + ☑️ JavaScript正常执行 +``` + +#### **步骤5:测试SPA路由** + +```bash +# 访问一个不存在的路径(测试React Router) +访问: https://frontend-nginx-service-xxxxx.cn-beijing.sae.aliyuncs.com/dashboard + +预期行为: + ✅ 不报404错误 + ✅ 返回index.html + ✅ React Router接管路由 + ✅ 显示对应的页面组件 + +❌ 如果看到Nginx 404页面,说明nginx.conf配置有问题 +``` + +#### **步骤6:测试API代理(关键)** + +```bash +# 打开浏览器开发者工具(F12)→ Console标签 + +# 执行以下代码测试API代理 +fetch('/api/v1/health') + .then(res => res.json()) + .then(data => console.log(data)) + +预期结果: + ✅ 请求成功(Status 200) + ✅ 返回后端的响应数据 + ✅ 没有CORS错误 + +❌ 如果看到CORS错误,说明反向代理配置有问题 +❌ 如果看到连接失败,说明后端地址配置错误 +``` + +#### **步骤7:测试静态资源缓存** + +```bash +# 在浏览器开发者工具 → Network标签 + +# 第一次访问 + ✅ index.html: 状态200,Cache-Control: no-cache + ✅ index-xxxxx.js: 状态200,Cache-Control: 1年 + +# 刷新页面(第二次访问) + ✅ index.html: 状态200(每次都重新获取) + ✅ index-xxxxx.js: 状态200 (from disk cache)(使用缓存) +``` + +#### **步骤8:测试Gzip压缩** + +```bash +# 在浏览器开发者工具 → Network标签 +# 点击任意JS文件 + +检查Response Headers: + ✅ Content-Encoding: gzip + ✅ 文件大小减少60-70% + +示例: + 原始大小: 1.2 MB + 传输大小: 350 KB (gzip压缩后) +``` + +### 🎉 **部署成功标志** + +如果以上8个步骤全部通过,恭喜!前端服务部署成功! + +--- + +## 9. 常见问题排查 + +### ❌ **问题1:实例健康检查失败** + +**症状:** +``` +实例状态显示"不健康" +健康检查失败 +``` + +**排查步骤:** + +```bash +1. 查看实例日志 + 【应用详情】→【日志】→【实时日志】→【选择实例】 + + 如果看到: + - "BACKEND_SERVICE_HOST required" → 环境变量未配置 + - "nginx: configuration file test failed" → nginx.conf语法错误 + - 没有日志 → 容器没有启动 + +2. 检查健康检查配置 + 【应用配置】→【健康检查】 + + 确认: + - 检查路径: /health(不是 /) + - 检查端口: 80(不是3000或其他) + - 检查协议: HTTP(不是HTTPS) + +3. 手动测试健康检查 + 在SAE Webshell中执行: + curl http://localhost/health + + 预期返回: healthy +``` + +**解决方法:** +- 配置缺失的环境变量 +- 修正健康检查路径 +- 检查容器端口配置 + +--- + +### ❌ **问题2:页面能访问,但API请求失败** + +**症状:** +``` +前端页面正常显示 +调用API时报错: Network Error 或 504 Gateway Timeout +``` + +**排查步骤:** + +```bash +1. 检查浏览器Console + 看到的错误: + - "ERR_CONNECTION_REFUSED" → 后端服务未启动 + - "504 Gateway Timeout" → 后端响应超时 + - "502 Bad Gateway" → 后端地址错误 + +2. 检查环境变量配置 + 【应用配置】→【环境变量】 + + 验证: + - BACKEND_SERVICE_HOST 是否配置 + - IP地址是否正确(从后端SAE应用获取) + - 不要有http://前缀 + - 不要包含端口号 + +3. 测试后端服务可达性 + 在前端容器的Webshell中: + curl http://172.17.0.15:3001/api/v1/health + + 如果失败: + - 检查后端服务是否运行 + - 检查VPC网络是否相同 + - 检查安全组规则 + +4. 查看Nginx错误日志 + docker logs 2>&1 | grep error + + 常见错误: + - "upstream: "http://172.17.0.15:3001/..." → 后端地址正确 + - "connect() failed" → 后端不可达 +``` + +**解决方法:** +- 修正环境变量BACKEND_SERVICE_HOST +- 确保前后端在同一VPC +- 检查安全组规则允许VPC内网访问 +- 重启前端应用使配置生效 + +--- + +### ❌ **问题3:刷新页面报404** + +**症状:** +``` +访问主页正常 +点击链接跳转正常 +刷新页面(F5)→ 404 Not Found +``` + +**原因:** + +React Router使用浏览器路由(BrowserRouter),刷新时Nginx需要将所有路由回退到index.html。 + +**排查步骤:** + +```bash +1. 访问一个React路由 + 例如: https://your-domain.com/dashboard + +2. 按F5刷新页面 + + ❌ 错误现象: 看到Nginx 404页面 + ✅ 正确现象: 页面正常显示 + +3. 检查nginx.conf配置 + 登录容器Webshell: + cat /etc/nginx/nginx.conf | grep "try_files" + + 应该看到: + try_files $uri $uri/ /index.html; +``` + +**解决方法:** + +如果nginx.conf中没有`try_files`配置,需要重新构建镜像: + +```nginx +# 在nginx.conf中确保有以下配置 +location / { + try_files $uri $uri/ /index.html; +} +``` + +--- + +### ❌ **问题4:静态资源404** + +**症状:** +``` +HTML能加载 +JS/CSS文件404 Not Found +页面显示为纯文本(无样式) +``` + +**排查步骤:** + +```bash +1. 检查浏览器Network标签 + 看到: + GET https://your-domain.com/assets/index-xxxxx.js 404 + +2. 检查index.html中的资源路径 + curl https://your-domain.com/ | grep assets + + 正确示例: + + + 错误示例: + # 相对路径 + # 错误base + +3. 检查Vite配置 + 查看frontend-v2/vite.config.ts: + + 正确配置: + export default defineConfig({ + base: '/', // ✅ 默认值 + }) + + 错误配置: + export default defineConfig({ + base: '/app/', // ❌ 除非确实需要 + }) +``` + +**解决方法:** + +1. 修改 `vite.config.ts`,确保 `base: '/'` +2. 重新构建前端:`npm run build` +3. 重新构建Docker镜像 +4. 推送到ACR +5. SAE重新部署 + +--- + +### ❌ **问题5:环境变量未生效** + +**症状:** +``` +配置了环境变量 +但容器启动日志显示变量为空 +``` + +**排查步骤:** + +```bash +1. 查看容器启动日志 + 【应用详情】→【日志】→【实时日志】 + + 看到: + Backend Service: ${BACKEND_SERVICE_HOST}:${BACKEND_SERVICE_PORT} + + ❌ 这说明envsubst没有替换变量 + +2. 进入容器Webshell检查 + echo $BACKEND_SERVICE_HOST + + 如果为空 → SAE环境变量未传入 + 如果有值 → envsubst执行失败 + +3. 检查docker-entrypoint.sh + cat /docker-entrypoint.sh + + 确认有: + envsubst '${BACKEND_SERVICE_HOST} ${BACKEND_SERVICE_PORT}' \ + < /etc/nginx/templates/nginx.conf.template \ + > /etc/nginx/nginx.conf +``` + +**解决方法:** + +1. 在SAE控制台重新配置环境变量 +2. 确保变量名拼写正确(区分大小写) +3. 重启应用使配置生效 + +--- + +## 10. 日常运维 + +### 📊 **监控指标** + +#### **实时监控** + +```yaml +查看位置: 【应用详情】→【监控】 + +关键指标: + CPU使用率: + 健康范围: < 30% + 告警阈值: > 60% + 说明: Nginx极少超过30% + + 内存使用率: + 健康范围: < 50% + 告警阈值: > 80% + 说明: Nginx内存占用很低 + + 请求QPS: + 观察访问量趋势 + + 平均响应时间: + 健康范围: < 50ms + 告警阈值: > 200ms + 说明: 静态文件响应极快 + + 错误率: + 健康范围: < 0.1% + 告警阈值: > 1% +``` + +#### **日志查看** + +```yaml +实时日志: + 位置: 【应用详情】→【日志】→【实时日志】 + + 正常日志示例: + 172.17.0.10 - - [23/Dec/2025:10:30:00 +0800] "GET / HTTP/1.1" 200 1234 + 172.17.0.10 - - [23/Dec/2025:10:30:01 +0800] "GET /assets/index.js HTTP/1.1" 200 567890 + + API代理日志: + 172.17.0.10 - - [23/Dec/2025:10:30:02 +0800] "GET /api/v1/projects HTTP/1.1" 200 8765 + + 错误日志: + 2025/12/23 10:30:04 [error] connect() failed (111: Connection refused) + → 后端服务连接失败 + +历史日志: + 位置: 【应用详情】→【日志】→【历史日志】 + 保留时间: 7天 +``` + +--- + +### 🔄 **版本更新流程** + +当前端代码有更新时,按以下流程部署新版本: + +#### **步骤1:本地构建新版本** + +```bash +# 在frontend-v2目录 +cd AIclinicalresearch/frontend-v2 + +# 测试构建 +npm run build + +# 构建Docker镜像(版本号+1) +docker build -t frontend-service:v1.0.1 . + +# 验证镜像大小 +docker images frontend-service:v1.0.1 +``` + +#### **步骤2:推送到ACR** + +```bash +# 登录ACR +echo fengzhibo117 | docker login --username=gofeng117@163.com --password-stdin crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com + +# 打标签 +docker tag frontend-service:v1.0.1 crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0.1 + +docker tag frontend-service:v1.0.1 crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:latest + +# 推送镜像 +docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0.1 + +docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:latest +``` + +#### **步骤3:SAE灰度发布(推荐)** + +```yaml +目的: 降低更新风险,先更新部分实例验证 + +操作步骤: + 1. 登录SAE控制台 → 进入应用详情 + + 2. 点击【部署】→【灰度发布】 + + 3. 配置灰度策略: + 灰度实例数: 1 + 灰度时长: 5分钟 + 镜像版本: v1.0.1 + + 4. 点击【确定】 + + 5. 观察灰度实例: + - 查看实例状态(健康) + - 查看错误日志(无错误) + - 访问测试(功能正常) + + 6. 确认无问题后,点击【全量发布】 + + 7. 如果发现问题,点击【回滚】 + - 自动回滚到上一个版本 + - 无需手动操作 +``` + +#### **步骤4:全量发布** + +如果不使用灰度发布,直接全量更新: + +```yaml +操作步骤: + 1. 登录SAE控制台 → 进入应用详情 + + 2. 点击【部署】 + + 3. 修改镜像版本: + 从: v1.0.0 + 到: v1.0.1 + + 4. 点击【确定】 + + 5. 等待部署完成(2-3分钟) + + 6. 验证新版本: + - 查看实例状态 + - 访问前端页面 + - 测试核心功能 +``` + +--- + +### 🔙 **回滚操作** + +如果新版本出现问题,可以快速回滚: + +```yaml +操作步骤: + 1. 登录SAE控制台 → 进入应用详情 + + 2. 点击【变更记录】 + + 3. 找到上一个稳定版本(如v1.0.0) + + 4. 点击【回滚】 + + 5. 确认回滚 + + 6. 等待回滚完成(1-2分钟) + +回滚时间: + - 镜像已缓存: 1-2分钟 + - 镜像未缓存: 2-3分钟 +``` + +--- + +### 🗑️ **清理旧版本镜像** + +定期清理ACR中的旧版本镜像,节省存储空间: + +```yaml +清理策略: + - 保留最近3个版本 + - 删除30天前的旧版本 + - 保留带有特殊标签的版本(如stable、prod) + +操作步骤: + 1. 登录ACR控制台 + + 2. 进入镜像仓库 → ai-clinical_frontend-nginx + + 3. 查看所有版本 + + 4. 选择要删除的版本(勾选) + + 5. 点击【删除】 + + 6. 确认删除 + +⚠️ 注意: + - 不要删除正在使用的版本 + - 删除前确认SAE应用已更新到新版本 + - 建议至少保留2个版本以便回滚 +``` + +--- + +### 📈 **弹性伸缩配置** + +前端Nginx服务通常不需要频繁扩缩容,但可以配置自动伸缩: + +```yaml +配置位置: 【应用配置】→【弹性伸缩】 + +最小实例数: 2 + 说明: 保证高可用,至少2个实例 + +最大实例数: 5 + 说明: 前端流量波动通常不大,5个实例足够 + +扩容策略: + 指标: CPU使用率 + 阈值: > 60% 持续 3分钟 + 每次扩容: +1个实例 + 冷却时间: 3分钟 + + 说明: Nginx很少达到60% CPU + +缩容策略: + 指标: CPU使用率 + 阈值: < 20% 持续 5分钟 + 每次缩容: -1个实例 + 冷却时间: 5分钟 + 最小保留: 2个实例 + +⚠️ 实际情况: + 前端Nginx性能极高,2个0.5核实例可以支撑: + - 1000+ QPS(静态文件) + - 100+ QPS(API代理) + - 几乎不需要扩容 +``` + +--- + +### 🚨 **告警配置** + +配置关键指标告警,及时发现问题: + +```yaml +配置位置: 【云监控】→【应用监控】→【创建告警规则】 + +推荐告警规则: + +1. 实例健康检查失败 + - 条件: 健康检查失败 > 3次 + - 级别: 紧急 + - 通知: 短信 + 钉钉 + +2. CPU使用率过高 + - 条件: CPU > 60% 持续 5分钟 + - 级别: 警告 + - 通知: 钉钉 + 邮件 + +3. 内存使用率过高 + - 条件: 内存 > 80% 持续 5分钟 + - 级别: 警告 + - 通知: 钉钉 + 邮件 + +4. 错误率过高 + - 条件: 错误率 > 1% 持续 3分钟 + - 级别: 紧急 + - 通知: 短信 + 钉钉 + +5. 平均响应时间过长 + - 条件: 响应时间 > 500ms 持续 5分钟 + - 级别: 警告 + - 通知: 钉钉 + 邮件 + +通知方式配置: + - 钉钉机器人: 创建群聊机器人,获取Webhook + - 邮件: 配置告警联系人邮箱 + - 短信: 配置手机号(建议仅用于紧急告警) +``` + +--- + +## 📚 附录 + +### 📝 **配置文件清单** + +部署过程中涉及的配置文件: + +```yaml +本地文件 (AIclinicalresearch/frontend-v2/): + - Dockerfile (多阶段构建配置) + - nginx.conf (Nginx服务器配置) + - docker-entrypoint.sh (容器启动脚本) + - .dockerignore (构建排除文件) + +SAE配置 (在控制台配置): + - 应用基本信息 + - 实例规格和数量 + - VPC网络配置 + - 镜像地址和版本 + - 环境变量 + - 健康检查 + - 公网访问配置 +``` + +--- + +### 🔗 **相关文档链接** + +```yaml +阿里云官方文档: + - SAE产品文档: https://help.aliyun.com/product/1172298.html + - ACR产品文档: https://help.aliyun.com/product/60716.html + - VPC产品文档: https://help.aliyun.com/product/27706.html + +项目内部文档: + - 前端Nginx部署指南: docs/05-部署文档/06-前端Nginx-SAE容器部署指南.md + - 快速部署SOP: docs/05-部署文档/01-快速部署SOP-零基础版.md + - 部署架构总览: docs/05-部署文档/00-部署架构总览.md +``` + +--- + +### 💡 **最佳实践总结** + +```yaml +安全性: + ✅ 使用专有网络(VPC)隔离 + ✅ 环境变量存储敏感信息 + ✅ 启用HTTPS(生产环境) + ✅ 配置安全组规则 + ✅ 隐藏Nginx版本号 + +性能: + ✅ 启用Gzip压缩(减少70%传输) + ✅ 配置合理的缓存策略 + ✅ 使用CDN加速(可选) + ✅ 优化Docker镜像大小 + +可靠性: + ✅ 至少2个实例(高可用) + ✅ 配置健康检查 + ✅ 启用自动伸缩 + ✅ 配置告警监控 + ✅ 灰度发布降低风险 + +可维护性: + ✅ 使用语义化版本号 + ✅ 保留最近3个版本以便回滚 + ✅ 定期清理旧版本镜像 + ✅ 记录变更日志 + ✅ 文档及时更新 +``` + +--- + +### ❓ **常见问题FAQ** + +**Q1: 前端服务需要多大的规格?** +``` +A: 0.5核1GB足够。 + - Nginx极其高效,占用资源很少 + - 0.5核可以支撑1000+ QPS + - 不要过度配置浪费资源 +``` + +**Q2: 需要配置多少个实例?** +``` +A: 生产环境建议2个实例。 + - 保证高可用(1个故障时另1个继续服务) + - 前端很少需要3个以上实例 + - 流量特别大时可以配置CDN +``` + +**Q3: 如何知道后端服务的内网地址?** +``` +A: 从后端SAE应用获取: + 1. 登录SAE控制台 + 2. 进入后端应用详情 + 3. 查看【应用访问配置】→【VPC内网访问地址】 + 4. 复制IP地址(格式:172.17.x.x) +``` + +**Q4: 环境变量配置后没生效怎么办?** +``` +A: 需要重启应用: + 1. 修改环境变量 + 2. 点击【重启】或【重新部署】 + 3. 等待实例重启完成 + 4. 查看启动日志确认变量值 +``` + +**Q5: 部署新版本后如何快速回滚?** +``` +A: SAE支持一键回滚: + 1. 进入【变更记录】 + 2. 找到上一个稳定版本 + 3. 点击【回滚】 + 4. 等待1-2分钟完成回滚 +``` + +**Q6: 如何配置HTTPS?** +``` +A: 两种方式: + 1. 使用SAE提供的域名(自动HTTPS) + 2. 绑定自定义域名并上传SSL证书 + + 生产环境强烈建议使用HTTPS +``` + +**Q7: 前端需要连接数据库吗?** +``` +A: 不需要。 + - 前端是纯静态资源(HTML/JS/CSS) + - 只需要通过Nginx代理访问后端API + - 数据库连接由后端服务处理 +``` + +**Q8: 每次更新都要重新构建Docker镜像吗?** +``` +A: 是的。 + 1. 修改前端代码 + 2. npm run build(生成新的dist/) + 3. docker build(打包到镜像) + 4. docker push(推送到ACR) + 5. SAE重新部署(拉取新镜像) + + 这是标准的容器化部署流程 +``` + +**Q9: Docker镜像太大怎么办?** +``` +A: 当前镜像只有92MB,已经很小了。 + - 多阶段构建(只保留运行时文件) + - Alpine基础镜像(最小Linux发行版) + - 已经是最优化的状态 +``` + +**Q10: 如何查看实时访问日志?** +``` +A: SAE控制台查看: + 【应用详情】→【日志】→【实时日志】 + + 可以看到: + - 所有HTTP请求(URL、状态码、响应时间) + - Nginx错误日志 + - 容器启动日志 +``` + +--- + +## 🎯 **部署检查清单** + +最后,用这个清单确认部署完成: + +```yaml +部署前准备: + ☑️ ACR镜像已推送(v1.0.0) + ☑️ 后端服务已部署(获取内网地址) + ☑️ VPC和交换机已创建 + ☑️ 安全组已配置 + +SAE应用配置: + ☑️ 应用名称:frontend-nginx-service + ☑️ 实例规格:0.5核1GB + ☑️ 实例数量:2 + ☑️ 镜像地址:专有网络域名(带-vpc) + ☑️ 镜像版本:v1.0.0 + +环境变量配置: + ☑️ BACKEND_SERVICE_HOST:已配置(172.17.x.x) + ☑️ BACKEND_SERVICE_PORT:已配置(3001) + +健康检查配置: + ☑️ 检查路径:/health + ☑️ 检查端口:80 + ☑️ 检查协议:HTTP + +部署验证: + ☑️ 实例状态:健康 + ☑️ 健康检查:通过 + ☑️ 主页访问:正常 + ☑️ SPA路由:正常(刷新不404) + ☑️ API代理:正常(无CORS错误) + ☑️ 静态资源:正常(缓存生效) + ☑️ Gzip压缩:已启用 + +监控和告警: + ☑️ 实时监控:已配置 + ☑️ 日志查看:可访问 + ☑️ 告警规则:已配置 + +全部完成,部署成功!🎉 +``` + +--- + +**文档结束** + +如有疑问,请查阅相关文档或联系技术支持。 + +祝部署顺利!🚀 + + diff --git a/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md b/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md new file mode 100644 index 00000000..5d9325b9 --- /dev/null +++ b/docs/05-部署文档/08-PostgreSQL数据库部署操作手册.md @@ -0,0 +1,1169 @@ +# PostgreSQL 15 数据库部署操作手册 + +**文档版本**: v1.0 +**创建时间**: 2025-12-24 +**适用场景**: 本地PostgreSQL数据库迁移到阿里云RDS +**数据库版本**: PostgreSQL 15 +**部署方式**: pg_dump全量导入 +**预计时间**: 30分钟 + +--- + +## 📋 目录 + +1. [部署概述](#1-部署概述) +2. [前置条件检查](#2-前置条件检查) +3. [部署步骤](#3-部署步骤) +4. [验证测试](#4-验证测试) +5. [安全加固](#5-安全加固) +6. [常见问题](#6-常见问题) +7. [回滚方案](#7-回滚方案) +8. [最佳实践](#8-最佳实践) + +--- + +## 1. 部署概述 + +### 1.1 部署目标 + +```yaml +目标: 将本地Docker PostgreSQL数据库完整迁移到阿里云RDS PostgreSQL 15 + +方法: pg_dump全量导出 + psql导入 + +优势: + ✅ 100%完整(结构+数据+索引+外键) + ✅ 一次性完成 + ✅ 可重复执行 + ✅ 简单可靠 + ✅ 包含pg-boss表(不需要单独处理) +``` + +### 1.2 部署架构 + +``` +本地环境 阿里云RDS +┌─────────────────┐ ┌─────────────────┐ +│ │ │ │ +│ Docker │ pg_dump导出 │ RDS PostgreSQL │ +│ PostgreSQL 15 │ ────────────────>│ 15.14 │ +│ │ psql导入 │ │ +│ 26 MB数据 │ │ VPC内网 │ +│ 10个Schema │ │ 2核4GB │ +│ 34个表 │ │ 50GB存储 │ +└─────────────────┘ └─────────────────┘ +``` + +### 1.3 数据库信息 + +#### 本地数据库 + +```yaml +容器名称: ai-clinical-postgres +镜像: postgres:15-alpine +数据库名: ai_clinical_research +用户名: postgres +密码: postgres +端口: 5432 +数据大小: 约26 MB +``` + +#### RDS数据库 + +```yaml +实例ID: pgm-2zex1m2y3r23hdn5 +内网地址: pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432 +数据库名: ai_clinical_research +用户名: airesearch +密码: Xibahe@fengzhibo117 +版本: PostgreSQL 15.14 +规格: 2核4GB +存储: 50GB SSD +地域: 华北2(北京) +VPC: vpc-2ze055cptkew9c38w4r06 (172.17.0.0/16) +白名单: 172.17.0.0/16(VPC网段) +时区: Asia/Shanghai +``` + +--- + +## 2. 前置条件检查 + +### 2.1 本地环境检查 + +```powershell +# 1. 检查Docker是否运行 +docker --version + +# 2. 检查PostgreSQL容器状态 +docker ps --filter "name=ai-clinical-postgres" +# 预期输出: 容器状态为 Up,健康状态为 healthy + +# 3. 验证本地数据库连接 +docker exec ai-clinical-postgres psql -U postgres -d ai_clinical_research -c "SELECT version();" +# 预期输出: PostgreSQL 15.x + +# 4. 检查数据库大小 +docker exec ai-clinical-postgres psql -U postgres -d ai_clinical_research -c "SELECT pg_size_pretty(pg_database_size('ai_clinical_research'));" +# 预期输出: 约26 MB +``` + +### 2.2 RDS环境检查 + +```yaml +☑️ RDS实例已创建且运行中 +☑️ VPC和交换机已配置 +☑️ 白名单已配置: 172.17.0.0/16 +☑️ 时区已设置: Asia/Shanghai +☑️ 数据库用户已创建: airesearch +☑️ 数据库密码已记录: Xibahe@fengzhibo117 +``` + +### 2.3 网络连接检查 + +```yaml +方案A: 有ECS跳板机 + - 准备ECS公网IP + - 准备SSH密钥或密码 + - 确保ECS在同一VPC + +方案B: 临时外网访问(本文档采用) + - 需要临时开启RDS外网地址 + - 需要配置白名单(临时使用0.0.0.0/0) + - ⚠️ 完成后立即关闭外网访问 +``` + +--- + +## 3. 部署步骤 + +### 步骤1: 导出本地数据库(5分钟) + +#### 1.1 导出数据库 + +```powershell +# 在项目根目录执行 +cd D:\MyCursor\AIclinicalresearch + +# 导出完整数据库(包括结构、数据、索引、外键) +docker exec ai-clinical-postgres pg_dump ` + -U postgres ` + -d ai_clinical_research ` + --format=plain ` + --no-owner ` + --no-acl ` + --encoding=UTF8 ` + > "rds_init_$(Get-Date -Format 'yyyyMMdd_HHmmss').sql" +``` + +**参数说明:** + +```yaml +-U postgres: 使用postgres用户 +-d ai_clinical_research: 指定数据库名 +--format=plain: 纯文本SQL格式 +--no-owner: 不导出所有者信息(避免用户名冲突) +--no-acl: 不导出权限信息(使用RDS默认权限) +--encoding=UTF8: UTF-8编码(中文支持) +``` + +#### 1.2 验证导出文件 + +```powershell +# 检查文件大小和创建时间 +Get-ChildItem rds_init_*.sql | + Sort-Object LastWriteTime -Descending | + Select-Object -First 1 | + Format-Table Name, @{Name="Size(MB)";Expression={[math]::Round($_.Length/1MB,2)}}, LastWriteTime -AutoSize +``` + +**预期结果:** + +``` +Name Size(MB) LastWriteTime +---- -------- ------------- +rds_init_20251224_154529.sql 88.23 2025/12/24 15:45:30 +``` + +**检查要点:** + +```yaml +✅ 文件大小合理(50-100 MB) +✅ 文件创建时间为刚才 +✅ 文件名包含时间戳 +``` + +--- + +### 步骤2: 开启RDS外网访问(3分钟) + +⚠️ **重要安全提示:** 此步骤会临时开放数据库的公网访问,存在安全风险。必须在导入完成后立即关闭! + +#### 2.1 登录RDS控制台 + +``` +访问: https://rdsnext.console.aliyun.com/ +地域: 华北2(北京) +``` + +#### 2.2 申请外网地址 + +1. 找到实例:`pgm-2zex1m2y3r23hdn5` +2. 点击实例ID,进入实例详情 +3. 左侧菜单:**数据库连接** → **申请外网地址** +4. 端口:`5432`(默认) +5. 点击 **确定** +6. 等待30-60秒,外网地址生成 + +**生成的外网地址示例:** + +``` +pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com +``` + +⚠️ **记录此地址,后续步骤需要使用!** + +#### 2.3 配置白名单 + +**阿里云会弹窗询问:** + +``` +是否将 0.0.0.0/0 加入白名单? +``` + +**选择:点击「是」** + +**风险说明:** + +```yaml +风险: 全世界任何人都可以尝试连接你的RDS + +缓解措施: + ✅ 密码强度高(Xibahe@fengzhibo117) + ✅ 仅用10分钟完成导入 + ✅ 导入后立即关闭外网访问 + ✅ 实际暴露时间极短 + +可接受性: ✅ 临时调试,可接受 +``` + +--- + +### 步骤3: 创建数据库(1分钟) + +#### 3.1 连接到RDS + +```powershell +# 测试连接(连接到默认postgres数据库) +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d postgres ` + -c "SELECT version();" +``` + +**预期输出:** + +``` + version +------------------------------------------------------------ + PostgreSQL 15.14 on x86_64-pc-linux-gnu, compiled by gcc +(1 row) +``` + +#### 3.2 创建数据库 + +```powershell +# 创建ai_clinical_research数据库 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d postgres ` + -c "CREATE DATABASE ai_clinical_research WITH ENCODING='UTF8' LC_COLLATE='en_US.utf8' LC_CTYPE='en_US.utf8' TEMPLATE=template0;" +``` + +**预期输出:** + +``` +CREATE DATABASE +``` + +#### 3.3 验证数据库创建 + +```powershell +# 验证数据库存在 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d postgres ` + -c "\l ai_clinical_research" +``` + +--- + +### 步骤4: 导入数据到RDS(5-8分钟)⭐⭐⭐ + +⏰ **这是最关键的步骤,请耐心等待!** + +#### 4.1 执行导入 + +```powershell +# 通过管道将SQL文件导入RDS +$env:PGPASSWORD="Xibahe@fengzhibo117" +Get-Content "rds_init_20251224_154529.sql" | ` + docker exec -i -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d ai_clinical_research +``` + +**注意:** 请将文件名 `rds_init_20251224_154529.sql` 替换为实际导出的文件名。 + +#### 4.2 导入过程输出示例 + +``` +SET +SET +CREATE SCHEMA +CREATE SCHEMA +...(中间省略数百行)... +CREATE TABLE +CREATE TABLE +COPY 1204 ← 导入1204行数据 +COPY 783 +COPY 3 +... +CREATE INDEX +CREATE INDEX +ALTER TABLE +... +``` + +**导入时间估算:** + +```yaml +文件大小: 88 MB +预计时间: 5-8 分钟 +取决于: 网络带宽和RDS写入速度 + +进度指示: + - 看到 CREATE SCHEMA → Schema创建中 + - 看到 CREATE TABLE → 表创建中 + - 看到 COPY 数字 → 数据导入中(数字是行数) + - 看到 CREATE INDEX → 索引创建中 + - 看到 ALTER TABLE → 外键创建中 +``` + +#### 4.3 导入完成标志 + +当命令执行完成返回提示符时,说明导入完成。 + +--- + +### 步骤5: 验证导入结果(3分钟) + +#### 5.1 验证Schema + +```powershell +# 检查Schema数量 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d ai_clinical_research ` + -c "SELECT nspname FROM pg_namespace WHERE nspname LIKE '%_schema' ORDER BY nspname;" +``` + +**预期输出:** + +``` + nspname +-------------------- + admin_schema + aia_schema + asl_schema + common_schema + dc_schema + pkb_schema + platform_schema + rvw_schema + ssa_schema + st_schema +(10 rows) +``` + +✅ **应该看到10个Schema** + +#### 5.2 验证表数量 + +```powershell +# 检查每个Schema的表数量 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d ai_clinical_research ` + -c "SELECT schemaname, COUNT(*) as table_count FROM pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema') GROUP BY schemaname ORDER BY schemaname;" +``` + +**预期输出:** + +``` + schemaname | table_count +-----------------+------------- + aia_schema | 5 + asl_schema | 6 + dc_schema | 6 + pkb_schema | 5 + platform_schema | 8 + public | 4 +(6 rows) +``` + +✅ **总计:34个表** + +#### 5.3 验证pg-boss表(关键) + +```powershell +# 检查pg-boss的6个表是否存在 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d ai_clinical_research ` + -c "SELECT tablename FROM pg_tables WHERE schemaname = 'platform_schema' AND tablename IN ('job', 'queue', 'schedule', 'subscription', 'job_common', 'version') ORDER BY tablename;" +``` + +**预期输出:** + +``` + tablename +-------------- + job + job_common + queue + schedule + subscription + version +(6 rows) +``` + +✅ **pg-boss的6个表全部存在** + +**说明:** + +```yaml +pg-boss表的作用: + - job: 任务队列表 + - queue: 队列配置表 + - schedule: 定时任务表 + - subscription: 订阅表 + - job_common: 任务通用配置表 + - version: pg-boss版本表 + +为什么重要: + - backend应用依赖pg-boss进行异步任务处理 + - 如果这些表不存在,backend启动会失败 + - 通过pg_dump导入,这些表会自动包含 + - 不需要在Prisma Schema中定义 +``` + +#### 5.4 验证数据量 + +```powershell +# 检查关键表的数据量 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d ai_clinical_research ` + -c "SELECT COUNT(*) as user_count, 'platform_schema.users' as table_name FROM platform_schema.users UNION ALL SELECT COUNT(*), 'aia_schema.projects' FROM aia_schema.projects UNION ALL SELECT COUNT(*), 'asl_schema.literatures' FROM asl_schema.literatures;" +``` + +**预期输出示例:** + +``` + user_count | table_name +------------+------------------------ + 3 | platform_schema.users + 2 | aia_schema.projects + 1204 | asl_schema.literatures +(3 rows) +``` + +✅ **数据量与本地一致** + +#### 5.5 验证索引和外键 + +```powershell +# 检查索引数量 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d ai_clinical_research ` + -c "SELECT schemaname, COUNT(*) as index_count FROM pg_indexes WHERE schemaname NOT IN ('pg_catalog', 'information_schema') GROUP BY schemaname ORDER BY schemaname;" +``` + +```powershell +# 检查外键约束数量 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d ai_clinical_research ` + -c "SELECT COUNT(*) as fk_count FROM pg_constraint WHERE contype = 'f';" +``` + +--- + +### 步骤6: 关闭外网访问(2分钟)⭐⭐⭐⭐⭐ + +⚠️ **这是最重要的安全步骤,必须立即执行!** + +#### 6.1 释放外网地址 + +1. **回到RDS控制台** + - 实例详情页面 + +2. **找到「数据库连接」** + +3. **找到外网地址** + ``` + pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com + ``` + +4. **点击「释放外网地址」** + +5. **在确认对话框中点击「确定」** + +6. **等待几秒钟** + +7. **确认状态变为「未申请」** ✅ + +#### 6.2 验证外网访问已关闭 + +```powershell +# 尝试从本地连接外网地址(应该失败) +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d ai_clinical_research ` + -c "SELECT 1;" ` + --connect-timeout=5 + +# 预期结果: 连接超时或连接失败 +``` + +**预期错误:** + +``` +psql: error: connection timed out +``` + +✅ **这个错误说明外网访问已成功关闭!** + +#### 6.3 最终安全状态 + +```yaml +RDS连接配置: + 内网地址: pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com ✅ (保留) + 外网地址: 已删除 ✅ + 白名单: 172.17.0.0/16 (VPC网段) ✅ + +安全状态: + ✅ 外网无法访问 + ✅ 只有VPC内的SAE应用可以连接 + ✅ 安全风险已消除 + ✅ 数据库处于最安全状态 +``` + +--- + +## 4. 验证测试 + +### 4.1 本地应用连接测试(可选) + +如果需要本地测试连接RDS,需要建立SSH隧道: + +```powershell +# 前提: 需要有ECS跳板机 + +# 建立SSH隧道 +ssh -N -L 5433:pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432 root@ECS公网IP + +# 在另一个终端测试连接 +$env:PGPASSWORD="Xibahe@fengzhibo117" +psql -h localhost -p 5433 -U airesearch -d ai_clinical_research -c "SELECT version();" +``` + +### 4.2 配置backend连接RDS + +```bash +# backend/.env +DATABASE_URL=postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research?connection_limit=10&pool_timeout=10&connect_timeout=10 + +# ⚠️ 注意: 密码中的 @ 符号必须转义为 %40 +``` + +**URL编码规则:** + +```yaml +特殊字符转义: + @ -> %40 + # -> %23 + $ -> %24 + % -> %25 + & -> %26 + + -> %2B + 空格 -> %20 +``` + +### 4.3 backend启动测试 + +```powershell +cd backend +npm run dev + +# 预期日志: +# ✅ 数据库连接成功 +# ✅ pg-boss started +# ✅ Server listening on 0.0.0.0:3001 +``` + +--- + +## 5. 安全加固 + +### 5.1 密码安全 + +```yaml +当前密码: Xibahe@fengzhibo117 + +强度评估: + ✅ 长度: 21个字符 + ✅ 大写字母: Xibahe, X, S + ✅ 小写字母: ibahe, fengzhibo + ✅ 数字: 117 + ✅ 特殊符号: @ + ✅ 强度: 高 + +建议: + - 定期轮换密码(每3-6个月) + - 不要在代码中硬编码密码 + - 只在SAE环境变量中配置 + - 不要提交到Git仓库 +``` + +### 5.2 白名单配置 + +```yaml +当前配置: 172.17.0.0/16 (VPC网段) + +最佳实践: + ✅ 使用VPC网段,不用单机IP + ✅ SAE实例IP会变化,单机IP会导致连接失败 + ❌ 不要配置 0.0.0.0/0(全网开放) + ❌ 不要配置多个单机IP(维护困难) + +验证: + - RDS控制台 > 数据安全性 > 白名单设置 + - 确认只有 172.17.0.0/16 + - 确认没有 0.0.0.0/0 +``` + +### 5.3 访问控制 + +```yaml +用户权限: + airesearch: 应用专用用户 + - 权限: SELECT, INSERT, UPDATE, DELETE + - 不要用超级用户 postgres + - 最小权限原则 + +连接限制: + - 配置 connection_limit=10(每个SAE实例) + - 避免连接池耗尽 + - RDS最大连接数: 400 +``` + +### 5.4 备份策略 + +```yaml +RDS自动备份(强制开启): + 数据备份: 每天一次 + 日志备份: 实时(PITR支持) + 保留时间: 7天(免费) + 备份时间: 凌晨2:00-4:00 + +手动快照(重要操作前): + - Schema变更前 + - 大版本升级前 + - 删除大量数据前 + - 保留30-60天 + +恢复能力: + ✅ 时间点恢复(PITR) + ✅ 可恢复到任意秒 + ✅ 备份存储在OSS +``` + +--- + +## 6. 常见问题 + +### 问题1: 导出时提示权限不足 + +**症状:** + +``` +pg_dump: error: permission denied for table xxx +``` + +**原因:** 使用的用户没有足够权限 + +**解决:** + +```bash +# 使用超级用户postgres +docker exec ai-clinical-postgres pg_dump -U postgres -d ai_clinical_research ... + +# 而不是普通用户 +``` + +--- + +### 问题2: 导入时连接超时 + +**症状:** + +``` +psql: error: connection timed out +``` + +**原因:** + +1. 外网地址未开启 +2. 白名单未配置 +3. 网络问题 + +**排查步骤:** + +```bash +# 1. 确认外网地址已开启 +# RDS控制台 > 数据库连接 > 查看外网地址 + +# 2. 确认白名单配置 +# RDS控制台 > 数据安全性 > 白名单设置 +# 应该包含 0.0.0.0/0(临时)或你的公网IP + +# 3. 测试网络连通性 +ping pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com + +# 4. 测试端口连通性 +Test-NetConnection -ComputerName pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com -Port 5432 +``` + +--- + +### 问题3: 导入时提示数据库不存在 + +**症状:** + +``` +psql: error: database "ai_clinical_research" does not exist +``` + +**原因:** 忘记创建数据库 + +**解决:** + +```bash +# 先创建数据库 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d postgres ` + -c "CREATE DATABASE ai_clinical_research WITH ENCODING='UTF8';" + +# 然后再导入 +``` + +--- + +### 问题4: 导入后pg-boss表缺失 + +**症状:** + +``` +backend启动日志显示: +Error: relation "platform_schema.job" does not exist +``` + +**原因:** 导出时未包含pg-boss表 + +**排查:** + +```bash +# 1. 检查导出的SQL文件 +Get-Content rds_init_*.sql | Select-String "CREATE TABLE.*job" + +# 应该看到: +# CREATE TABLE platform_schema.job ... +# CREATE TABLE platform_schema.queue ... +# 等6个表 + +# 2. 如果没有,重新导出 +docker exec ai-clinical-postgres pg_dump -U postgres -d ai_clinical_research --format=plain --no-owner --no-acl > rds_init_new.sql + +# 3. 重新导入 +``` + +**预防:** + +```yaml +确保使用正确的导出命令: + ✅ 使用 pg_dump(导出整个数据库) + ❌ 不要用 prisma migrate(只导出Prisma定义的表) +``` + +--- + +### 问题5: 密码中的特殊字符导致连接失败 + +**症状:** + +``` +backend启动失败: +Error: password authentication failed for user "airesearch" +``` + +**原因:** DATABASE_URL中的密码未正确转义 + +**解决:** + +```bash +# 错误示例(@ 未转义) +DATABASE_URL=postgresql://airesearch:Xibahe@fengzhibo117@host:5432/db + +# 正确示例(@ 转义为 %40) +DATABASE_URL=postgresql://airesearch:Xibahe%40fengzhibo117@host:5432/db +``` + +**URL编码工具:** + +```javascript +// 在浏览器控制台运行 +encodeURIComponent("Xibahe@fengzhibo117") +// 输出: Xibahe%40fengzhibo117 +``` + +--- + +### 问题6: SAE应用无法连接RDS + +**症状:** + +``` +SAE日志显示: +connection to server failed: Connection timed out +``` + +**原因:** + +1. 使用了外网地址(已删除) +2. 白名单未包含VPC网段 +3. SAE和RDS不在同一VPC + +**排查步骤:** + +```yaml +1. 确认使用内网地址: + ✅ pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com(内网) + ❌ pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com(外网,已删除) + +2. 确认白名单配置: + RDS控制台 > 数据安全性 > 白名单设置 + 应该包含: 172.17.0.0/16 + +3. 确认VPC一致: + - RDS VPC: vpc-2ze055cptkew9c38w4r06 + - SAE VPC: 应该相同 + - 查看方式: SAE控制台 > 应用详情 > 网络配置 + +4. 确认SAE环境变量: + DATABASE_URL=postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research + 注意: 不要有 -ko 后缀 +``` + +--- + +## 7. 回滚方案 + +### 7.1 回滚场景 + +```yaml +需要回滚的情况: + - 导入后发现数据不完整 + - 导入过程中断 + - 数据验证失败 + - 应用连接异常 +``` + +### 7.2 回滚步骤 + +```bash +# 方案A: 删除数据库重新导入(推荐) + +# 1. 连接到RDS +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h pgm-2zex1m2y3r23hdn5ko.pg.rds.aliyuncs.com ` + -p 5432 ` + -U airesearch ` + -d postgres + +# 2. 终止所有连接 +SELECT pg_terminate_backend(pid) +FROM pg_stat_activity +WHERE datname = 'ai_clinical_research' AND pid <> pg_backend_pid(); + +# 3. 删除数据库 +DROP DATABASE ai_clinical_research; + +# 4. 重新创建并导入 +CREATE DATABASE ai_clinical_research WITH ENCODING='UTF8'; +\q + +# 5. 重新导入 +Get-Content rds_init_*.sql | docker exec -i -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql -h ... -d ai_clinical_research +``` + +```bash +# 方案B: 使用RDS快照恢复(如果创建了快照) + +# 1. 登录RDS控制台 +# 2. 备份恢复 > 备份列表 +# 3. 找到导入前的快照 +# 4. 点击「恢复」 +# 5. 选择恢复方式: +# - 按备份集恢复(恢复到快照时间点) +# - 按时间点恢复(PITR,恢复到任意时间) +# 6. 确认恢复 +``` + +### 7.3 回滚验证 + +```bash +# 验证回滚后的数据 +docker exec -e PGPASSWORD="Xibahe@fengzhibo117" ai-clinical-postgres psql ` + -h ... ` + -d ai_clinical_research ` + -c "SELECT schemaname, COUNT(*) FROM pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema') GROUP BY schemaname;" +``` + +--- + +## 8. 最佳实践 + +### 8.1 部署前准备 + +```yaml +☑️ 准备检查清单: + 1. 本地数据库已备份 + 2. RDS实例已创建并配置完成 + 3. VPC网络已规划 + 4. 白名单已配置(VPC网段) + 5. 数据库用户和密码已记录 + 6. 时区已设置(Asia/Shanghai) + 7. 自动备份已开启 + +☑️ 时间窗口选择: + - 业务低峰期(如晚上11点后) + - 预留足够时间(30-60分钟) + - 团队成员在线支持 +``` + +### 8.2 执行过程中 + +```yaml +☑️ 操作规范: + 1. 逐步执行,不要跳步骤 + 2. 每步验证结果再继续 + 3. 记录每步的输出和时间 + 4. 遇到错误立即停止排查 + 5. 不要同时执行多个操作 + +☑️ 安全意识: + 1. 外网访问最小化(10分钟内完成) + 2. 导入完成立即关闭外网 + 3. 不要在公共网络操作 + 4. 不要泄露连接信息 +``` + +### 8.3 部署后检查 + +```yaml +☑️ 功能验证: + 1. Schema和表数量正确 + 2. 数据量与本地一致 + 3. pg-boss表存在 + 4. 索引和外键完整 + 5. backend能正常连接 + 6. 应用功能正常 + +☑️ 性能验证: + 1. 连接延迟 < 50ms(VPC内网) + 2. 查询响应时间正常 + 3. RDS CPU使用率 < 30% + 4. 连接数 < 100 + +☑️ 安全验证: + 1. 外网地址已删除 ✅ + 2. 白名单只有VPC网段 ✅ + 3. 密码强度高 ✅ + 4. 自动备份已开启 ✅ +``` + +### 8.4 监控告警 + +```yaml +☑️ 配置监控: + 1. RDS连接数告警(>300) + 2. RDS CPU告警(>70%) + 3. RDS磁盘告警(>80%) + 4. 慢查询告警(>1秒) + 5. 备份失败告警 + +☑️ 日常巡检: + 1. 每天检查RDS监控 + 2. 每周查看慢查询日志 + 3. 每月验证备份可用性 + 4. 每季度恢复演练 +``` + +### 8.5 文档维护 + +```yaml +☑️ 更新文档: + 1. 记录实际执行时间 + 2. 记录遇到的问题和解决方案 + 3. 更新连接信息 + 4. 补充特殊情况处理 + +☑️ 知识沉淀: + 1. 总结经验教训 + 2. 优化部署流程 + 3. 培训团队成员 + 4. 建立FAQ +``` + +--- + +## 9. 附录 + +### 9.1 完整检查清单 + +```yaml +部署前检查 (Before): + ☐ 本地数据库运行正常 + ☐ Docker Desktop运行正常 + ☐ RDS实例已创建 + ☐ VPC和交换机已配置 + ☐ 白名单已配置(172.17.0.0/16) + ☐ 数据库用户已创建(airesearch) + ☐ 时区已设置(Asia/Shanghai) + ☐ 自动备份已开启 + +部署过程检查 (During): + ☐ 导出文件大小正常(50-100 MB) + ☐ 外网地址申请成功 + ☐ 白名单临时配置(0.0.0.0/0) + ☐ 数据库创建成功 + ☐ 数据导入完成(无错误) + ☐ 外网地址已删除 ⭐⭐⭐ + +部署后检查 (After): + ☐ 10个Schema全部存在 + ☐ 34个表全部存在 + ☐ pg-boss的6个表存在 + ☐ 用户数据完整 + ☐ 索引完整 + ☐ 外键完整 + ☐ backend能连接RDS + ☐ 应用功能正常 + ☐ 外网访问已关闭 ⭐⭐⭐ +``` + +### 9.2 快速参考 + +#### 连接信息 + +```yaml +RDS内网地址: pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432 +数据库名: ai_clinical_research +用户名: airesearch +密码: Xibahe@fengzhibo117 + +DATABASE_URL: +postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research?connection_limit=10&pool_timeout=10 +``` + +#### 常用命令 + +```powershell +# 导出数据库 +docker exec ai-clinical-postgres pg_dump -U postgres -d ai_clinical_research --no-owner --no-acl > backup.sql + +# 导入数据库 +Get-Content backup.sql | docker exec -i -e PGPASSWORD="密码" ai-clinical-postgres psql -h RDS地址 -U airesearch -d ai_clinical_research + +# 检查Schema +docker exec -e PGPASSWORD="密码" ai-clinical-postgres psql -h RDS地址 -U airesearch -d ai_clinical_research -c "\dn" + +# 检查表 +docker exec -e PGPASSWORD="密码" ai-clinical-postgres psql -h RDS地址 -U airesearch -d ai_clinical_research -c "\dt platform_schema.*" + +# 检查数据量 +docker exec -e PGPASSWORD="密码" ai-clinical-postgres psql -h RDS地址 -U airesearch -d ai_clinical_research -c "SELECT COUNT(*) FROM platform_schema.users;" +``` + +--- + +## 📚 相关文档 + +- [部署架构总览](./00-部署架构总览.md) +- [快速部署SOP](./01-快速部署SOP-零基础版.md) +- [PostgreSQL部署策略摸底报告](./PostgreSQL部署策略-摸底报告.md) +- [Node.js后端部署指南](./05-Node.js后端-SAE容器部署指南.md) + +--- + +## 📝 变更历史 + +| 版本 | 日期 | 作者 | 变更说明 | +|------|------|------|---------| +| v1.0 | 2025-12-24 | AI助手 | 初始版本,基于实际部署经验 | + +--- + +## 🆘 支持 + +如有问题,请检查: + +1. ✅ 本文档的「常见问题」章节 +2. ✅ RDS实时日志(RDS控制台 > 日志管理) +3. ✅ backend应用日志(SAE控制台 > 日志) +4. ✅ PostgreSQL部署策略摸底报告 + +--- + +**文档结束** + +祝部署顺利!🎉 + diff --git a/docs/05-部署文档/文档修正报告-20251214.md b/docs/05-部署文档/文档修正报告-20251214.md index a5e51d5d..80244311 100644 --- a/docs/05-部署文档/文档修正报告-20251214.md +++ b/docs/05-部署文档/文档修正报告-20251214.md @@ -473,3 +473,5 @@ NAT网关成本¥100/月,对初创团队是一笔开销 + + diff --git a/docs/07-运维文档/03-SAE环境变量配置指南.md b/docs/07-运维文档/03-SAE环境变量配置指南.md index cf2f0a83..0e279940 100644 --- a/docs/07-运维文档/03-SAE环境变量配置指南.md +++ b/docs/07-运维文档/03-SAE环境变量配置指南.md @@ -378,3 +378,5 @@ curl http://你的SAE地址:3001/health + + diff --git a/docs/07-运维文档/05-Redis缓存与队列的区别说明.md b/docs/07-运维文档/05-Redis缓存与队列的区别说明.md index 2a9c6859..05f6948b 100644 --- a/docs/07-运维文档/05-Redis缓存与队列的区别说明.md +++ b/docs/07-运维文档/05-Redis缓存与队列的区别说明.md @@ -710,3 +710,5 @@ const job = await queue.getJob(jobId); + + diff --git a/docs/07-运维文档/06-长时间任务可靠性分析.md b/docs/07-运维文档/06-长时间任务可靠性分析.md index 5a9f2014..e841835b 100644 --- a/docs/07-运维文档/06-长时间任务可靠性分析.md +++ b/docs/07-运维文档/06-长时间任务可靠性分析.md @@ -477,3 +477,5 @@ processLiteraturesInBackground(task.id, projectId, testLiteratures); + + diff --git a/docs/07-运维文档/07-Redis使用需求分析(按模块).md b/docs/07-运维文档/07-Redis使用需求分析(按模块).md index 3e496751..66051737 100644 --- a/docs/07-运维文档/07-Redis使用需求分析(按模块).md +++ b/docs/07-运维文档/07-Redis使用需求分析(按模块).md @@ -954,3 +954,5 @@ 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 ae179c0a..d2f4097b 100644 --- a/docs/08-项目管理/03-每周计划/2025-12-13-Postgres-Only架构改造完成.md +++ b/docs/08-项目管理/03-每周计划/2025-12-13-Postgres-Only架构改造完成.md @@ -1011,3 +1011,5 @@ Redis 实例:¥500/月 + + diff --git a/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md b/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md index a2800383..7abf8fc6 100644 --- a/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md +++ b/docs/08-项目管理/05-技术债务/通用对话服务抽取计划.md @@ -466,6 +466,8 @@ import { ChatContainer } from '@/shared/components/Chat'; + + diff --git a/extraction_service/.dockerignore b/extraction_service/.dockerignore new file mode 100644 index 00000000..6ed478c7 --- /dev/null +++ b/extraction_service/.dockerignore @@ -0,0 +1,48 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +venv/ +env/ +ENV/ +.venv + +# 测试 +.pytest_cache/ +.coverage +htmlcov/ +*.log + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# 文档 +*.md +docs/ + +# Git +.git/ +.gitignore + +# 环境变量 +.env +.env.local + +# 临时文件 +*.tmp +temp/ +tmp/ +uploads/ + +# 模型缓存 (避免打包Nougat模型) +.cache/ +models/ +*.pth +*.pt +*.onnx + diff --git a/extraction_service/Dockerfile b/extraction_service/Dockerfile new file mode 100644 index 00000000..4d646cdf --- /dev/null +++ b/extraction_service/Dockerfile @@ -0,0 +1,56 @@ +# ======================================== +# 多阶段构建:Python微服务 +# ======================================== + +# -------------------- 阶段1: 构建阶段 -------------------- +FROM python:3-slim AS builder + +# 设置工作目录 +WORKDIR /app + +# 替换为阿里云镜像源(为将来可能的构建依赖做准备) +RUN sed -i 's|http://deb.debian.org|http://mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources \ + && sed -i 's|http://security.debian.org|http://mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources + +# 复制依赖文件 +COPY requirements-prod.txt . + +# 安装Python依赖到临时目录(使用预编译wheel,无需编译依赖) +RUN pip install --no-cache-dir --user -r requirements-prod.txt + +# -------------------- 阶段2: 运行阶段 -------------------- +FROM python:3-slim + +# 设置工作目录 +WORKDIR /app + +# 替换为阿里云镜像源并安装运行时依赖 +RUN sed -i 's|http://deb.debian.org|http://mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources \ + && sed -i 's|http://security.debian.org|http://mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + libgl1 \ + libglib2.0-0 \ + libgomp1 \ + && rm -rf /var/lib/apt/lists/* + +# 从构建阶段复制Python包 +COPY --from=builder /root/.local /root/.local + +# 复制应用代码 +COPY . . + +# 设置Python路径 +ENV PATH=/root/.local/bin:$PATH +ENV PYTHONUNBUFFERED=1 + +# 暴露端口 +EXPOSE 8000 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ + CMD python -c "import requests; requests.get('http://localhost:8000/api/health', timeout=5)" + +# 启动命令 +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "2"] + diff --git a/extraction_service/operations/__init__.py b/extraction_service/operations/__init__.py index 7b6a3230..a7d75e3a 100644 --- a/extraction_service/operations/__init__.py +++ b/extraction_service/operations/__init__.py @@ -31,4 +31,6 @@ __version__ = '1.0.0' + + diff --git a/extraction_service/operations/dropna.py b/extraction_service/operations/dropna.py index ac113316..1c9581d7 100644 --- a/extraction_service/operations/dropna.py +++ b/extraction_service/operations/dropna.py @@ -164,4 +164,6 @@ def get_missing_summary(df: pd.DataFrame) -> dict: + + diff --git a/extraction_service/operations/filter.py b/extraction_service/operations/filter.py index e6a7e4ec..8907f151 100644 --- a/extraction_service/operations/filter.py +++ b/extraction_service/operations/filter.py @@ -124,4 +124,6 @@ def apply_filter( + + diff --git a/extraction_service/operations/unpivot.py b/extraction_service/operations/unpivot.py index 0ed840e8..43a71956 100644 --- a/extraction_service/operations/unpivot.py +++ b/extraction_service/operations/unpivot.py @@ -289,3 +289,5 @@ def get_unpivot_preview( + + diff --git a/extraction_service/requirements-prod.txt b/extraction_service/requirements-prod.txt new file mode 100644 index 00000000..27b6d172 --- /dev/null +++ b/extraction_service/requirements-prod.txt @@ -0,0 +1,43 @@ +# ======================================== +# 生产环境依赖 (移除Nougat和重量级依赖) +# ======================================== + +# Web框架 +fastapi==0.104.1 +uvicorn[standard]==0.24.0 +python-multipart==0.0.6 + +# 数据处理 (DC工具必需) +pandas>=2.0.0 +numpy>=1.24.0 +polars>=0.19.0 + +# PDF处理 (核心轻量级库) +PyMuPDF>=1.24.0 +pdfplumber==0.10.3 + +# Docx处理 +mammoth==1.6.0 +python-docx==1.1.0 + +# 语言检测 +langdetect==1.0.9 + +# 编码检测 +chardet==5.2.0 + +# 工具 +python-dotenv==1.0.0 +pydantic>=2.10.0 + +# 日志 +loguru==0.7.2 + +# 测试工具 +requests==2.31.0 + +# ======================================== +# 注意:生产环境已移除以下重量级依赖 +# - nougat-ocr==0.1.17 (约1.5GB) +# - albumentations==1.3.1 (Nougat依赖) +# ======================================== diff --git a/extraction_service/test_dc_api.py b/extraction_service/test_dc_api.py index c003c91c..2adc9222 100644 --- a/extraction_service/test_dc_api.py +++ b/extraction_service/test_dc_api.py @@ -296,6 +296,8 @@ if __name__ == "__main__": + + diff --git a/extraction_service/test_execute_simple.py b/extraction_service/test_execute_simple.py index c4dfbbc3..685c2e4d 100644 --- a/extraction_service/test_execute_simple.py +++ b/extraction_service/test_execute_simple.py @@ -62,6 +62,8 @@ except Exception as e: + + diff --git a/extraction_service/test_module.py b/extraction_service/test_module.py index 87ccc6e1..a914bf63 100644 --- a/extraction_service/test_module.py +++ b/extraction_service/test_module.py @@ -42,6 +42,8 @@ except Exception as e: + + diff --git a/frontend-v2/.dockerignore b/frontend-v2/.dockerignore new file mode 100644 index 00000000..88d04361 --- /dev/null +++ b/frontend-v2/.dockerignore @@ -0,0 +1,68 @@ +# Node.js +node_modules +npm-debug.log +yarn-error.log +.npm +.yarn + +# 开发文件 +.env +.env.* +*.local + +# 构建产物(Dockerfile 中会重新生成) +dist + +# 测试文件 +test +tests +*.test.ts +*.test.tsx +*.spec.ts +*.spec.tsx +coverage +.nyc_output + +# 文档和临时文件 +docs +*.md +!README.md +.vscode +.idea +.DS_Store +Thumbs.db + +# Git +.git +.gitignore +.gitattributes + +# CI/CD +.github +.gitlab-ci.yml +.travis.yml + +# 日志 +*.log +logs + +# 临时文件 +temp +tmp +*.swp +*.swo +*~ + +# 编辑器配置 +.editorconfig +.prettierrc +.eslintrc* + +# TypeScript 配置(保留 tsconfig.json,其他忽略) +tsconfig.tsbuildinfo + +# Vite +.vite +vite.config.*.timestamp-* + + diff --git a/frontend-v2/Dockerfile b/frontend-v2/Dockerfile new file mode 100644 index 00000000..5d6ac842 --- /dev/null +++ b/frontend-v2/Dockerfile @@ -0,0 +1,64 @@ +# ==================== 阶段 1: 构建阶段 ==================== +# ⚠️ 使用 Node Alpine 最新版(包含 Node 22+) +FROM node:alpine AS builder + +# 设置工作目录 +WORKDIR /app + +# 1. 复制依赖文件 +COPY package*.json ./ + +# 2. 安装依赖 +# 使用国内镜像加速(可选,如果网络慢可以取消注释) +# RUN npm config set registry https://registry.npmmirror.com +RUN npm ci --only=production=false + +# 3. 复制源代码 +COPY . . + +# 4. 构建生产版本 +# ⚠️ 注意:如果需要在构建时注入环境变量,在这里设置 ARG +# ARG VITE_API_BASE_URL +# ENV VITE_API_BASE_URL=$VITE_API_BASE_URL +RUN npm run build + +# 验证构建产物 +RUN ls -la /app/dist/ + +# ==================== 阶段 2: 运行阶段 ==================== +FROM nginx:alpine + +# 安装必要工具(包括时区数据) +RUN apk add --no-cache \ + bash \ + gettext \ + curl \ + tzdata + +# 设置容器时区为上海(否则日志时间会比北京时间慢 8 小时) +RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ + echo "Asia/Shanghai" > /etc/timezone + +# 创建 Nginx 配置目录 +RUN mkdir -p /etc/nginx/templates + +# 1. 复制 Nginx 配置模板(支持环境变量替换) +COPY nginx.conf /etc/nginx/templates/nginx.conf.template + +# 2. 复制构建产物到 Nginx 默认目录 +COPY --from=builder /app/dist /usr/share/nginx/html + +# 3. 复制启动脚本 +COPY docker-entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \ + CMD curl -f http://localhost/health || exit 1 + +# 暴露端口 +EXPOSE 80 + +# 启动命令 +ENTRYPOINT ["/docker-entrypoint.sh"] + diff --git a/frontend-v2/docker-entrypoint.sh b/frontend-v2/docker-entrypoint.sh new file mode 100644 index 00000000..70e16613 --- /dev/null +++ b/frontend-v2/docker-entrypoint.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e + +# ⚠️ 关键:不给默认值,强制在 SAE 控制台配置 +# 如果未配置,报错退出(避免使用错误的后端地址) +if [ -z "$BACKEND_SERVICE_HOST" ]; then + echo "❌ ERROR: BACKEND_SERVICE_HOST environment variable is required!" + echo "Please configure it in SAE console with backend internal IP (e.g., 172.17.x.x)" + exit 1 +fi + +if [ -z "$BACKEND_SERVICE_PORT" ]; then + echo "⚠️ WARNING: BACKEND_SERVICE_PORT not set, using default: 3001" + export BACKEND_SERVICE_PORT=3001 +fi + +echo "============================================" +echo "Starting Frontend Nginx Service" +echo "Backend Service: ${BACKEND_SERVICE_HOST}:${BACKEND_SERVICE_PORT}" +echo "Container Timezone: $(cat /etc/timezone)" +echo "Current Time: $(date)" +echo "============================================" + +# 使用 envsubst 替换 Nginx 配置中的环境变量 +envsubst '${BACKEND_SERVICE_HOST} ${BACKEND_SERVICE_PORT}' \ + < /etc/nginx/templates/nginx.conf.template \ + > /etc/nginx/nginx.conf + +# 验证 Nginx 配置 +nginx -t + +# 启动 Nginx +exec nginx -g 'daemon off;' + + diff --git a/frontend-v2/nginx.conf b/frontend-v2/nginx.conf new file mode 100644 index 00000000..2ae58361 --- /dev/null +++ b/frontend-v2/nginx.conf @@ -0,0 +1,191 @@ +# Nginx 配置文件 - AI临床研究平台前端服务 +# 用途:托管 React SPA + 反向代理后端 API + +user nginx; +worker_processes auto; # 自动根据 CPU 核心数调整 + +# ⚠️ 日志输出到 stderr(SAE 会自动收集) +error_log /dev/stderr warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; # 每个 worker 进程的最大连接数 + use epoll; # Linux 下使用 epoll(高性能) +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # 日志格式 + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + # ⚠️ 日志输出到 stdout(SAE 会自动收集,避免磁盘写满) + access_log /dev/stdout main; + + # 性能优化 + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + # Gzip 压缩(减少传输大小) + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_types text/plain text/css text/xml text/javascript + application/json application/javascript application/xml+rss + application/rss+xml font/truetype font/opentype + application/vnd.ms-fontobject image/svg+xml; + gzip_disable "msie6"; + + # 上游后端服务(Backend Service) + upstream backend { + # ⚠️ 重要:这里的地址在部署时需要替换为真实的后端内网地址 + # SAE 部署时,通过环境变量注入,详见 Dockerfile + server ${BACKEND_SERVICE_HOST}:${BACKEND_SERVICE_PORT} fail_timeout=30s max_fails=3; + + # 如果有多个后端实例(负载均衡) + # server 172.17.x.x:3001 weight=1; + # server 172.17.x.y:3001 weight=1; + + keepalive 32; # 保持连接池 + } + + server { + listen 80; + server_name _; # 接受所有域名 + + # 根目录(React 构建产物) + root /usr/share/nginx/html; + index index.html; + + # 字符集 + charset utf-8; + + # ==================== 静态资源处理 ==================== + + # 主页面(index.html)- 不缓存 + location = / { + try_files /index.html =404; + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires "0"; + } + + location = /index.html { + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires "0"; + } + + # JS/CSS 文件 - 强缓存(文件名带 hash) + location ~* \.(js|css)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + access_log off; + } + + # 图片/字体文件 - 强缓存 + location ~* \.(png|jpg|jpeg|gif|ico|svg|webp|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + access_log off; + } + + # ==================== API 反向代理 ==================== + + # 后端 API 代理(关键配置) + location /api/ { + # 代理到后端服务 + proxy_pass http://backend; + + # 保留原始请求信息 + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # 超时配置(AI 对话、文件处理可能耗时较长) + proxy_connect_timeout 300s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + + # 缓冲配置 + proxy_buffering off; # 关闭缓冲(实时流式响应) + proxy_request_buffering off; # 支持大文件上传 + + # WebSocket 支持(如果后续需要) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # 错误处理 + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; + proxy_next_upstream_tries 2; + } + + # ==================== SPA 路由支持 ==================== + + # React Router 路由回退 + # 所有非文件请求都返回 index.html(SPA 的核心) + location / { + try_files $uri $uri/ /index.html; + + # 禁用缓存(用户刷新时总是获取最新页面) + add_header Cache-Control "no-cache, no-store, must-revalidate"; + } + + # ==================== 安全加固 ==================== + + # 隐藏 Nginx 版本号 + server_tokens off; + + # 禁止访问隐藏文件 + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + + # 禁止访问特定文件 + location ~* \.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)$ { + deny all; + } + + # ==================== 健康检查 ==================== + + # SAE 健康检查端点 + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } + + # Nginx 状态页(用于监控) + location /nginx_status { + stub_status on; + access_log off; + # 仅允许内网访问 + allow 10.0.0.0/8; + allow 172.17.0.0/16; + allow 192.168.0.0/16; + deny all; + } + + # ==================== 错误页面 ==================== + + error_page 404 /index.html; # SPA 路由回退 + error_page 500 502 503 504 /50x.html; + + location = /50x.html { + root /usr/share/nginx/html; + } + } +} + + diff --git a/frontend-v2/src/framework/modules/ModuleErrorFallback.tsx b/frontend-v2/src/framework/modules/ModuleErrorFallback.tsx index c4f0695b..c7449816 100644 --- a/frontend-v2/src/framework/modules/ModuleErrorFallback.tsx +++ b/frontend-v2/src/framework/modules/ModuleErrorFallback.tsx @@ -35,7 +35,7 @@ const ModuleErrorFallback = ({ const navigate = useNavigate() // 是否显示详细错误信息(开发环境显示,生产环境隐藏) - const isDevelopment = import.meta.env?.DEV ?? false + const isDevelopment = import.meta.env.DEV /** * 处理重试 diff --git a/frontend-v2/src/main.tsx b/frontend-v2/src/main.tsx index ea6ddba2..3e6172a6 100644 --- a/frontend-v2/src/main.tsx +++ b/frontend-v2/src/main.tsx @@ -10,7 +10,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render( = ({ icon: , text: '不确定', }; + case 'pending': + return { + color: 'processing', + icon: , + text: '待处理', + }; default: return { color: 'default', diff --git a/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx b/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx index e3c12c2b..a538d313 100644 --- a/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx +++ b/frontend-v2/src/modules/asl/components/FulltextDetailDrawer.tsx @@ -531,6 +531,8 @@ export default FulltextDetailDrawer; + + diff --git a/frontend-v2/src/modules/asl/hooks/useFulltextResults.ts b/frontend-v2/src/modules/asl/hooks/useFulltextResults.ts index 794143b0..91caeafc 100644 --- a/frontend-v2/src/modules/asl/hooks/useFulltextResults.ts +++ b/frontend-v2/src/modules/asl/hooks/useFulltextResults.ts @@ -8,7 +8,6 @@ * 4. 人工复核 */ -import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { message } from 'antd'; import { aslApi } from '../api'; @@ -131,5 +130,6 @@ export function useFulltextResults({ + diff --git a/frontend-v2/src/modules/asl/hooks/useFulltextTask.ts b/frontend-v2/src/modules/asl/hooks/useFulltextTask.ts index 958389c9..2342ff65 100644 --- a/frontend-v2/src/modules/asl/hooks/useFulltextTask.ts +++ b/frontend-v2/src/modules/asl/hooks/useFulltextTask.ts @@ -35,10 +35,10 @@ export function useFulltextTask({ enabled: enabled && !!taskId, refetchInterval: refetchInterval !== undefined ? refetchInterval - : ((data) => { + : ((data: any) => { // 默认行为:任务进行中时每2秒轮询,否则停止 if (!data?.data) return false; - const status = (data.data as any).status; + const status = data.data.status; return status === 'processing' || status === 'pending' ? 2000 : false; }), retry: 1, @@ -94,5 +94,6 @@ export function useFulltextTask({ + diff --git a/frontend-v2/src/modules/asl/hooks/useScreeningResults.ts b/frontend-v2/src/modules/asl/hooks/useScreeningResults.ts index ee9040fb..796add5d 100644 --- a/frontend-v2/src/modules/asl/hooks/useScreeningResults.ts +++ b/frontend-v2/src/modules/asl/hooks/useScreeningResults.ts @@ -33,12 +33,11 @@ export function useScreeningResults({ queryFn: () => aslApi.getScreeningResultsList(projectId, { page, pageSize, filter }), enabled: enabled && !!projectId, staleTime: 1000 * 30, // 30秒内认为数据是新鲜的 - keepPreviousData: true, // 切换页面时保留上一页数据,避免闪烁 }); - const results = data?.data?.items || []; - const total = data?.data?.total || 0; - const totalPages = data?.data?.totalPages || 0; + const results = (data as any)?.data?.items || []; + const total = (data as any)?.data?.total || 0; + const totalPages = (data as any)?.data?.totalPages || 0; // 人工复核Mutation const reviewMutation = useMutation({ diff --git a/frontend-v2/src/modules/asl/pages/FulltextResults.tsx b/frontend-v2/src/modules/asl/pages/FulltextResults.tsx index fe432e80..544da71d 100644 --- a/frontend-v2/src/modules/asl/pages/FulltextResults.tsx +++ b/frontend-v2/src/modules/asl/pages/FulltextResults.tsx @@ -9,7 +9,7 @@ */ import { useState } from 'react'; -import { useParams, useSearchParams } from 'react-router-dom'; +import { useParams } from 'react-router-dom'; import { Card, Statistic, @@ -59,8 +59,6 @@ interface FulltextResultItem { const FulltextResults = () => { const { taskId } = useParams<{ taskId: string }>(); - const [searchParams] = useSearchParams(); - const projectId = searchParams.get('projectId') || ''; const [activeTab, setActiveTab] = useState<'all' | 'included' | 'excluded' | 'pending'>('all'); const [selectedRowKeys, setSelectedRowKeys] = useState([]); @@ -108,7 +106,7 @@ const FulltextResults = () => { const results = resultsData?.items || []; // 导出Excel - const handleExport = async (filter: 'all' | 'included' | 'excluded' | 'pending') => { + const handleExport = async (_filter: 'all' | 'included' | 'excluded' | 'pending') => { try { message.loading({ content: '正在生成Excel...', key: 'export' }); @@ -432,7 +430,7 @@ const FulltextResults = () => { expandable={{ expandedRowRender, expandedRowKeys, - onExpand: (expanded, record) => toggleRowExpanded(record.resultId), + onExpand: (_expanded, record) => toggleRowExpanded(record.resultId), expandIcon: () => null, }} pagination={{ @@ -485,5 +483,6 @@ export default FulltextResults; + diff --git a/frontend-v2/src/modules/dc/hooks/useAssets.ts b/frontend-v2/src/modules/dc/hooks/useAssets.ts index ddf52f28..00973915 100644 --- a/frontend-v2/src/modules/dc/hooks/useAssets.ts +++ b/frontend-v2/src/modules/dc/hooks/useAssets.ts @@ -124,6 +124,8 @@ 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 e893fdf7..01d1d353 100644 --- a/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts +++ b/frontend-v2/src/modules/dc/hooks/useRecentTasks.ts @@ -114,6 +114,8 @@ export const useRecentTasks = () => { + + diff --git a/frontend-v2/src/modules/dc/pages/tool-b/Step4Verify.tsx b/frontend-v2/src/modules/dc/pages/tool-b/Step4Verify.tsx index 031d5d9d..a821dd17 100644 --- a/frontend-v2/src/modules/dc/pages/tool-b/Step4Verify.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-b/Step4Verify.tsx @@ -22,7 +22,7 @@ interface VerifyRow { status: 'clean' | 'conflict' | 'pending' | 'failed'; // 行状态 } -const Step4Verify: React.FC = ({ state, updateState, onComplete }) => { +const Step4Verify: React.FC = ({ state, onComplete }) => { const [rows, setRows] = useState([]); const [selectedRowId, setSelectedRowId] = useState(null); const [isLoading, setIsLoading] = useState(false); diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/BinningDialog_improved.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/BinningDialog_improved.tsx index fcb1eff2..c6376d9b 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/BinningDialog_improved.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/BinningDialog_improved.tsx @@ -9,7 +9,7 @@ import React, { useState } from 'react'; import { Modal, Select, Input, Button, Radio, Space, Tag, App, Alert } from 'antd'; -import { Plus, X, Info } from 'lucide-react'; +import { Info } from 'lucide-react'; interface BinningDialogProps { visible: boolean; @@ -353,3 +353,4 @@ export default BinningDialog; + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/ConditionalDialog.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/ConditionalDialog.tsx index 6b3e2404..be0e7dca 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/ConditionalDialog.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/ConditionalDialog.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Modal, Input, Button, Select, Space, Alert, App, Card, Tag } from 'antd'; +import { Modal, Input, Button, Select, Alert, App, Card, Tag } from 'antd'; import { PlusCircle, Trash2, AlertCircle } from 'lucide-react'; interface Condition { @@ -28,7 +28,6 @@ const ConditionalDialog: React.FC = ({ onClose, onApply, columns, - data, sessionId, }) => { const { message } = App.useApp(); diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/DropnaDialog.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/DropnaDialog.tsx index a06801ea..0615e0c3 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/DropnaDialog.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/DropnaDialog.tsx @@ -315,4 +315,6 @@ export default DropnaDialog; + + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/MetricTimePanel.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/MetricTimePanel.tsx index 1bbccaa8..5c4cde06 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/MetricTimePanel.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/MetricTimePanel.tsx @@ -401,3 +401,5 @@ export default MetricTimePanel; + + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/PivotDialog.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/PivotDialog.tsx index dae6bb09..7d99726e 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/PivotDialog.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/PivotDialog.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { Modal, Select, Button, Alert, Checkbox, Radio, App, Tag } from 'antd'; +import { Modal, Select, Button, Alert, Checkbox, Radio, App } from 'antd'; import { ArrowLeftRight, Info } from 'lucide-react'; interface Props { diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/PivotPanel.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/PivotPanel.tsx index 6a6c8bb7..d7f073b5 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/PivotPanel.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/PivotPanel.tsx @@ -287,3 +287,5 @@ export default PivotPanel; + + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/RecodeDialog.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/RecodeDialog.tsx index 4aab0686..e9de5bcf 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/RecodeDialog.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/RecodeDialog.tsx @@ -27,14 +27,13 @@ interface MappingRow { const RecodeDialog: React.FC = ({ visible, columns, - data, sessionId, onClose, onApply, }) => { const { message } = App.useApp(); const [selectedColumn, setSelectedColumn] = useState(''); - const [uniqueValues, setUniqueValues] = useState([]); + const [_uniqueValues, setUniqueValues] = useState([]); const [mappingTable, setMappingTable] = useState([]); const [createNewColumn, setCreateNewColumn] = useState(true); const [newColumnName, setNewColumnName] = useState(''); diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/Toolbar.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/Toolbar.tsx index b31b685c..d83ac924 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/Toolbar.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/Toolbar.tsx @@ -6,9 +6,7 @@ import { Calculator, - CalendarClock, ArrowLeftRight, - FileSearch, Wand2, Filter, Search, @@ -71,9 +69,7 @@ const Toolbar: React.FC = ({ onConditionalClick, onDropnaClick, onComputeClick, - onDedupClick, onPivotClick, - onMiceClick, sessionId, }) => { return ( diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/TransformDialog.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/TransformDialog.tsx index 8701bdae..d4b712bc 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/TransformDialog.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/TransformDialog.tsx @@ -9,7 +9,7 @@ import React, { useState } from 'react'; import { Modal, Tabs } from 'antd'; -import { ArrowLeftRight, Sparkles, BarChart3 } from 'lucide-react'; +import { ArrowLeftRight, BarChart3 } from 'lucide-react'; import PivotPanel from './PivotPanel'; import UnpivotPanel from './UnpivotPanel'; import { MultiMetricPanel } from './MultiMetricPanel'; diff --git a/frontend-v2/src/modules/dc/pages/tool-c/components/UnpivotPanel.tsx b/frontend-v2/src/modules/dc/pages/tool-c/components/UnpivotPanel.tsx index 44cd20cb..1a13e060 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/components/UnpivotPanel.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/components/UnpivotPanel.tsx @@ -4,7 +4,7 @@ */ import React, { useState } from 'react'; -import { Select, Button, Alert, Checkbox, App, Input, Collapse, Radio } from 'antd'; +import { Button, Alert, Checkbox, App, Input, Collapse, Radio } from 'antd'; import { ArrowLeftRight, Info } from 'lucide-react'; interface Props { @@ -392,3 +392,4 @@ export default UnpivotPanel; + 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 f155b208..3ab3495c 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 @@ -87,3 +87,5 @@ export function useSessionStatus({ }; } + + diff --git a/frontend-v2/src/modules/dc/pages/tool-c/index.tsx b/frontend-v2/src/modules/dc/pages/tool-c/index.tsx index 27239be8..3e988cfd 100644 --- a/frontend-v2/src/modules/dc/pages/tool-c/index.tsx +++ b/frontend-v2/src/modules/dc/pages/tool-c/index.tsx @@ -460,7 +460,6 @@ const ToolC = () => { updateState({ dropnaDialogVisible: false })} onApply={handleQuickActionDataUpdate} 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 59e2a706..6e901d8e 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 @@ -76,6 +76,8 @@ export interface DataStats { + + diff --git a/frontend-v2/src/modules/dc/types/portal.ts b/frontend-v2/src/modules/dc/types/portal.ts index debe434a..263901f9 100644 --- a/frontend-v2/src/modules/dc/types/portal.ts +++ b/frontend-v2/src/modules/dc/types/portal.ts @@ -72,6 +72,8 @@ export type AssetTabType = 'all' | 'processed' | 'raw'; + + diff --git a/frontend-v2/src/shared/components/Placeholder.tsx b/frontend-v2/src/shared/components/Placeholder.tsx index 7e4ea46b..b9087661 100644 --- a/frontend-v2/src/shared/components/Placeholder.tsx +++ b/frontend-v2/src/shared/components/Placeholder.tsx @@ -5,14 +5,18 @@ import { RocketOutlined } from '@ant-design/icons' interface PlaceholderProps { title?: string description?: string + message?: string // 别名,等同于description moduleName?: string } const Placeholder = ({ title = '功能开发中', description = '该模块正在规划和开发中,敬请期待', + message, // message是description的别名 moduleName }: PlaceholderProps) => { + // 优先使用message,如果没有则使用description + const displayDescription = message || description; const navigate = useNavigate() return ( @@ -22,7 +26,7 @@ const Placeholder = ({ title={{title}} subTitle={
-

{description}

+

{displayDescription}

{moduleName && (

模块名称:{moduleName} diff --git a/frontend-v2/src/shared/components/index.ts b/frontend-v2/src/shared/components/index.ts index 090db4a4..dcb4fef0 100644 --- a/frontend-v2/src/shared/components/index.ts +++ b/frontend-v2/src/shared/components/index.ts @@ -27,6 +27,8 @@ export { default as Placeholder } from './Placeholder'; + + diff --git a/frontend-v2/src/vite-env.d.ts b/frontend-v2/src/vite-env.d.ts new file mode 100644 index 00000000..aaf79a5c --- /dev/null +++ b/frontend-v2/src/vite-env.d.ts @@ -0,0 +1,14 @@ +/// + +interface ImportMetaEnv { + readonly DEV: boolean + readonly PROD: boolean + readonly SSR: boolean + // 更多环境变量... +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} + + diff --git a/frontend-v2/tsconfig.tsbuildinfo b/frontend-v2/tsconfig.tsbuildinfo new file mode 100644 index 00000000..ed543b9b --- /dev/null +++ b/frontend-v2/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/framework/layout/mainlayout.tsx","./src/framework/layout/topnavigation.tsx","./src/framework/modules/errorboundary.tsx","./src/framework/modules/moduleerrorfallback.tsx","./src/framework/modules/moduleregistry.ts","./src/framework/modules/types.ts","./src/framework/permission/permissioncontext.tsx","./src/framework/permission/index.ts","./src/framework/permission/types.ts","./src/framework/permission/usepermission.ts","./src/framework/router/permissiondenied.tsx","./src/framework/router/routeguard.tsx","./src/framework/router/index.ts","./src/modules/aia/index.tsx","./src/modules/asl/index.tsx","./src/modules/asl/api/index.ts","./src/modules/asl/components/asllayout.tsx","./src/modules/asl/components/conclusiontag.tsx","./src/modules/asl/components/detailreviewdrawer.tsx","./src/modules/asl/components/fulltextdetaildrawer.tsx","./src/modules/asl/components/judgmentbadge.tsx","./src/modules/asl/hooks/usefulltextresults.ts","./src/modules/asl/hooks/usefulltexttask.ts","./src/modules/asl/hooks/usescreeningresults.ts","./src/modules/asl/hooks/usescreeningtask.ts","./src/modules/asl/pages/fulltextprogress.tsx","./src/modules/asl/pages/fulltextresults.tsx","./src/modules/asl/pages/fulltextsettings.tsx","./src/modules/asl/pages/fulltextworkbench.tsx","./src/modules/asl/pages/screeningresults.tsx","./src/modules/asl/pages/screeningworkbench.tsx","./src/modules/asl/pages/titlescreeningsettings.tsx","./src/modules/asl/types/index.ts","./src/modules/asl/utils/excelexport.ts","./src/modules/asl/utils/excelutils.ts","./src/modules/asl/utils/tabletransform.ts","./src/modules/dc/index.tsx","./src/modules/dc/api/toolb.ts","./src/modules/dc/api/toolc.ts","./src/modules/dc/components/assetlibrary.tsx","./src/modules/dc/components/tasklist.tsx","./src/modules/dc/components/toolcard.tsx","./src/modules/dc/hooks/useassets.ts","./src/modules/dc/hooks/userecenttasks.ts","./src/modules/dc/pages/portal.tsx","./src/modules/dc/pages/tool-b/step1upload.tsx","./src/modules/dc/pages/tool-b/step2schema.tsx","./src/modules/dc/pages/tool-b/step3processing.tsx","./src/modules/dc/pages/tool-b/step4verify.tsx","./src/modules/dc/pages/tool-b/step5result.tsx","./src/modules/dc/pages/tool-b/index.tsx","./src/modules/dc/pages/tool-b/components/stepindicator.tsx","./src/modules/dc/pages/tool-c/index.tsx","./src/modules/dc/pages/tool-c/components/binningdialog.tsx","./src/modules/dc/pages/tool-c/components/binningdialog_improved.tsx","./src/modules/dc/pages/tool-c/components/computedialog.tsx","./src/modules/dc/pages/tool-c/components/conditionaldialog.tsx","./src/modules/dc/pages/tool-c/components/datagrid.tsx","./src/modules/dc/pages/tool-c/components/dropnadialog.tsx","./src/modules/dc/pages/tool-c/components/filterdialog.tsx","./src/modules/dc/pages/tool-c/components/header.tsx","./src/modules/dc/pages/tool-c/components/metrictimepanel.tsx","./src/modules/dc/pages/tool-c/components/missingvaluedialog.tsx","./src/modules/dc/pages/tool-c/components/multimetricpanel.tsx","./src/modules/dc/pages/tool-c/components/pivotdialog.tsx","./src/modules/dc/pages/tool-c/components/pivotpanel.tsx","./src/modules/dc/pages/tool-c/components/recodedialog.tsx","./src/modules/dc/pages/tool-c/components/sidebar.tsx","./src/modules/dc/pages/tool-c/components/streamingsteps.tsx","./src/modules/dc/pages/tool-c/components/toolbar.tsx","./src/modules/dc/pages/tool-c/components/transformdialog.tsx","./src/modules/dc/pages/tool-c/components/unpivotpanel.tsx","./src/modules/dc/pages/tool-c/hooks/usesessionstatus.ts","./src/modules/dc/pages/tool-c/types/index.ts","./src/modules/dc/types/portal.ts","./src/modules/pkb/index.tsx","./src/modules/ssa/index.tsx","./src/modules/st/index.tsx","./src/pages/homepage.tsx","./src/shared/components/placeholder.tsx","./src/shared/components/index.ts","./src/shared/components/chat/chatcontainer.tsx","./src/shared/components/chat/codeblockrenderer.tsx","./src/shared/components/chat/messagerenderer.tsx","./src/shared/components/chat/index.ts","./src/shared/components/chat/types.ts"],"version":"5.9.3"} \ No newline at end of file diff --git a/python-microservice/operations/__init__.py b/python-microservice/operations/__init__.py index 7b6a3230..a7d75e3a 100644 --- a/python-microservice/operations/__init__.py +++ b/python-microservice/operations/__init__.py @@ -31,4 +31,6 @@ __version__ = '1.0.0' + + diff --git a/python-microservice/operations/binning.py b/python-microservice/operations/binning.py index b1d7cd4f..0fcaa314 100644 --- a/python-microservice/operations/binning.py +++ b/python-microservice/operations/binning.py @@ -138,4 +138,6 @@ def apply_binning( + + diff --git a/python-microservice/operations/filter.py b/python-microservice/operations/filter.py index e6a7e4ec..8907f151 100644 --- a/python-microservice/operations/filter.py +++ b/python-microservice/operations/filter.py @@ -124,4 +124,6 @@ def apply_filter( + + diff --git a/python-microservice/operations/recode.py b/python-microservice/operations/recode.py index e76ac9fe..26f24497 100644 --- a/python-microservice/operations/recode.py +++ b/python-microservice/operations/recode.py @@ -94,4 +94,6 @@ def apply_recode( + + diff --git a/rds_init_20251224_154529.sql b/rds_init_20251224_154529.sql new file mode 100644 index 00000000..92855662 Binary files /dev/null and b/rds_init_20251224_154529.sql differ diff --git a/recover_dc_code.py b/recover_dc_code.py index d2545166..86731fb5 100644 --- a/recover_dc_code.py +++ b/recover_dc_code.py @@ -236,6 +236,8 @@ if __name__ == "__main__": + + diff --git a/run_recovery.ps1 b/run_recovery.ps1 index aab33e4b..906019e1 100644 --- a/run_recovery.ps1 +++ b/run_recovery.ps1 @@ -60,6 +60,8 @@ Write-Host "==================================================================== + + diff --git a/tests/QUICKSTART_快速开始.md b/tests/QUICKSTART_快速开始.md index 6b9737b3..180877e4 100644 --- a/tests/QUICKSTART_快速开始.md +++ b/tests/QUICKSTART_快速开始.md @@ -110,3 +110,5 @@ INFO: Uvicorn running on http://0.0.0.0:8001 + + diff --git a/tests/README_测试说明.md b/tests/README_测试说明.md index 4b36db43..c739bdb5 100644 --- a/tests/README_测试说明.md +++ b/tests/README_测试说明.md @@ -266,3 +266,5 @@ df_numeric.to_excel('test_data/numeric_test.xlsx', index=False) + + diff --git a/tests/run_tests.bat b/tests/run_tests.bat index 44754064..230e15ae 100644 --- a/tests/run_tests.bat +++ b/tests/run_tests.bat @@ -61,3 +61,5 @@ pause + + diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 7dc20a0d..64a73bca 100644 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -57,3 +57,5 @@ echo "========================================" + + diff --git a/快速部署到SAE.md b/快速部署到SAE.md index b9330843..2e9b255d 100644 --- a/快速部署到SAE.md +++ b/快速部署到SAE.md @@ -322,3 +322,5 @@ OSS AccessKeySecret:_______________ + + diff --git a/部署检查清单.md b/部署检查清单.md index a6e52493..65dea2f4 100644 --- a/部署检查清单.md +++ b/部署检查清单.md @@ -358,3 +358,5 @@ OSS配置: + +