Files
AIclinicalresearch/docs/05-部署文档/01-快速部署SOP-零基础版.md
HaHafeng 66255368b7 feat(admin): Add user management and upgrade to module permission system
Features - User Management (Phase 4.1):
- Database: Add user_modules table for fine-grained module permissions
- Database: Add 4 user permissions (view/create/edit/delete) to role_permissions
- Backend: UserService (780 lines) - CRUD with tenant isolation
- Backend: UserController + UserRoutes (648 lines) - 13 API endpoints
- Backend: Batch import users from Excel
- Frontend: UserListPage (412 lines) - list/filter/search/pagination
- Frontend: UserFormPage (341 lines) - create/edit with module config
- Frontend: UserDetailPage (393 lines) - details/tenant/module management
- Frontend: 3 modal components (592 lines) - import/assign/configure
- API: GET/POST/PUT/DELETE /api/admin/users/* endpoints

Architecture Upgrade - Module Permission System:
- Backend: Add getUserModules() method in auth.service
- Backend: Login API returns modules array in user object
- Frontend: AuthContext adds hasModule() method
- Frontend: Navigation filters modules based on user.modules
- Frontend: RouteGuard checks requiredModule instead of requiredVersion
- Frontend: Remove deprecated version-based permission system
- UX: Only show accessible modules in navigation (clean UI)
- UX: Smart redirect after login (avoid 403 for regular users)

Fixes:
- Fix UTF-8 encoding corruption in ~100 docs files
- Fix pageSize type conversion in userService (String to Number)
- Fix authUser undefined error in TopNavigation
- Fix login redirect logic with role-based access check
- Update Git commit guidelines v1.2 with UTF-8 safety rules

Database Changes:
- CREATE TABLE user_modules (user_id, tenant_id, module_code, is_enabled)
- ADD UNIQUE CONSTRAINT (user_id, tenant_id, module_code)
- INSERT 4 permissions + role assignments
- UPDATE PUBLIC tenant with 8 module subscriptions

Technical:
- Backend: 5 new files (~2400 lines)
- Frontend: 10 new files (~2500 lines)
- Docs: 1 development record + 2 status updates + 1 guideline update
- Total: ~4900 lines of code

Status: User management 100% complete, module permission system operational
2026-01-16 13:42:10 +08:00

1268 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AI临床研究平台 - 阿里云快速部署SOP零基础版
> **文档版本:** v1.0
> **创建日期:** 2025-12-16
> **适用场景:** 从零开始部署到阿里云不含Dify
> **预计时间:** 3-4小时
> **目标:** 系统能够正常访问,基本功能可用
---
## 📋 部署检查清单
在开始之前,请确认:
- [ ] 已有阿里云账号,且已完成实名认证
- [ ] 账户余额 ≥ 500元建议1000元包含3个月运行费用
- [ ] 已安装Docker Desktop用于构建镜像
- [ ] 已安装Git用于获取代码
- [ ] 本地能够正常运行项目(数据库已初始化)
---
## 📌 已部署资源快速参考
以下资源已经在阿里云上部署完成,部署过程中可以直接使用这些信息:
### ✅ VPC网络信息
```yaml
VPC ID: vpc-2ze055cptkew9c38w4r06
VPC名称: ai-clinical-vpc
网段: 172.17.0.0/16
地域: 华北2北京
交换机ID: vsw-2zevacop039bxrmj6yc0c (可用区F)
vsw-2zehoeyw9ldncymcyvfwq (可用区A)
安全组ID: sg-2zedk6fi8sgmmcwdu7tu
```
### ✅ RDS PostgreSQL数据库
```yaml
实例ID: pgm-2zex1m2y3r23hdn5
内网地址: pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432
数据库账号: airesearch
数据库密码: Xibahe@fengzhibo117
数据库名称: ai_clinical_research
规格: 2核4GB (pg.n2.2c.1m)
最大连接数: 400
PostgreSQL版本: 15.0
白名单: 172.17.0.0/16 ✅
时区: Asia/Shanghai ✅
```
### ✅ SAE命名空间
```yaml
命名空间ID: cn-beijing:test-airesearch
地域: 华北2北京
```
### ✅ OSS对象存储
```yaml
Bucket名称: ai-clinical-research
地域: 华北2北京
存储类型: 标准存储
读写权限: 私有
存储冗余类型: 同城冗余存储
外网Endpoint: oss-cn-beijing.aliyuncs.com
内网Endpoint: oss-cn-beijing-internal.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仓库
```
### ✅ NAT网关与公网访问
```yaml
NAT网关名称: NAT_airesearch
NAT网关ID: ngw-2zeec9ulzgw7ywvx1pst6
SNAT表ID: stb-2zesszmzx1qpwf1cb2bry
公网IP(EIP): 182.92.176.14
创建时间: 2025-12-16 20:58:12
# SNAT条目配置2条覆盖所有交换机
SNAT条目1:
ID: snat-2zerlp4z0ed2isvq399gn
源网段: 172.17.160.0/20
交换机: vsw-2zevacop039bxrmj6yc0c (可用区F)
公网IP: 182.92.176.14
状态: 可用 ✅
SNAT条目2:
ID: snat-2zegvesjxjwmw7j51m89m
源网段: 172.17.192.0/20
交换机: vsw-2zehoeyw9ldncymcyvfwq (可用区A)
公网IP: 182.92.176.14
状态: 可用 ✅
```
### ✅ ACR容器镜像服务
```yaml
服务类型: 个人版(免费)
命名空间: ai-clinical
用户名: gofeng117@163.com
Registry密码: fengzhibo117
公网域名: crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com
专有网络域名: crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com
# 镜像仓库3个
仓库1 - 前端Nginx:
仓库名称: ai-clinical_frontend-nginx
公网地址: crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx
专有网络地址: crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx
仓库2 - Python微服务:
仓库名称: python-extraction
公网地址: crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction
专有网络地址: crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction
仓库3 - Node.js后端:
仓库名称: 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
⚠️ 安全警告Registry密码是敏感信息请勿提交到公开Git仓库
```
### ⚠️ 待部署资源
- [x] NAT网关 ✅ 已创建SNAT已配置
- [x] OSS存储桶 ✅ 已创建
- [x] ACR容器镜像仓库 ✅ 已创建
- [ ] SAE应用3个Python/Node.js/Frontend
---
## 🎯 部署全流程概览
```
第一阶段阿里云资源准备60分钟
├── 创建VPC网络
├── 创建NAT网关关键
├── 购买RDS PostgreSQL
├── 创建OSS存储桶
└── 创建SAE应用3个空应用
第二阶段数据库初始化30分钟
├── 导出本地数据库
├── 通过ECS跳板机连接RDS
└── 导入数据到RDS
第三阶段Docker镜像准备60分钟
├── 创建阿里云容器镜像服务ACR
├── 构建Python微服务镜像
├── 构建Node.js后端镜像
└── 构建前端Nginx镜像
第四阶段SAE应用部署60分钟
├── 部署Python微服务
├── 部署Node.js后端
└── 部署前端Nginx
第五阶段验证与测试30分钟
├── 健康检查
├── 功能测试
└── 日志排查
```
**总预计时间3.5-4小时**
---
## 第一阶段阿里云资源准备60分钟
### 1.1 创建VPC专有网络10分钟
**目的:** 为所有云资源提供内网隔离环境
**操作步骤:**
1. 登录阿里云控制台https://vpc.console.aliyun.com/
2. 点击【创建专有网络】
3. 填写配置:
```yaml
名称: ai-clinical-vpc
地域: 华北2北京
IPv4网段: 172.17.0.0/16
```
4. 创建交换机vSwitch
```yaml
名称: ai-clinical-vswitch-1
可用区: 北京 可用区H
IPv4网段: 172.17.0.0/20
```
5. 点击【确定】等待创建完成约30秒
**验证:** 在VPC列表中看到"ai-clinical-vpc",状态为"可用"
---
### 1.2 创建NAT网关15分钟⭐⭐⭐⭐⭐
**目的:** 为SAE容器提供公网访问能力调用DeepSeek/OpenAI API必需
**⚠️ 重要警告:** 没有NAT网关AI功能100%超时!
**✅ 实际NAT网关信息已部署**
```yaml
NAT网关名称: NAT_airesearch
NAT网关ID: ngw-2zeec9ulzgw7ywvx1pst6
地域: 华北2北京
VPC: vpc-2ze055cptkew9c38w4r06
SNAT表ID: stb-2zesszmzx1qpwf1cb2bry
创建时间: 2025-12-16 20:58:12
# 弹性公网IP (EIP)
公网IP: 182.92.176.14
# SNAT条目配置2条覆盖所有交换机
SNAT条目1:
ID: snat-2zerlp4z0ed2isvq399gn
源网段: 172.17.160.0/20
交换机: vsw-2zevacop039bxrmj6yc0c (可用区F)
公网IP: 182.92.176.14
状态: ✅ 可用
SNAT条目2:
ID: snat-2zegvesjxjwmw7j51m89m
源网段: 172.17.192.0/20
交换机: vsw-2zehoeyw9ldncymcyvfwq (可用区A)
公网IP: 182.92.176.14
状态: ✅ 可用
```
**⚠️ 如果需要重新创建,操作步骤:**
1. 进入NAT网关控制台https://vpc.console.aliyun.com/nat
2. 点击【创建NAT网关】
3. 填写配置:
```yaml
地域: 华北2北京
VPC: ai-clinical-vpc (vpc-2ze055cptkew9c38w4r06)
规格: 小型默认¥60/月)
计费方式: 按量付费
```
4. 购买弹性公网IPEIP
- 点击【绑定弹性公网IP】
- 选择【购买并绑定EIP】
- 带宽5Mbps按使用流量计费
- 点击【确定】
5. 配置SNAT规则让SAE能访问公网
- 点击【SNAT管理】→【创建SNAT条目】
- 选择交换机为每个交换机创建SNAT条目
- 交换机1`vsw-2zevacop039bxrmj6yc0c` (可用区F)
- 交换机2`vsw-2zehoeyw9ldncymcyvfwq` (可用区A)
- 选择公网IP绑定的EIP
- 点击【确定】
**验证:**
- ✅ NAT网关状态为"运行中"
- ✅ EIP已绑定182.92.176.14
- ✅ SNAT条目状态为"可用"2条
- ✅ 覆盖了所有交换机的网段
**成本估算:**
- NAT网关¥60/月
- EIP¥0.8/GB流量预计¥40/月)
- 合计约¥100/月
---
### 1.3 购买RDS PostgreSQL数据库20分钟
**目的:** 托管的PostgreSQL数据库支持10个Schema隔离
**操作步骤:**
1. 进入RDS控制台https://rdsnext.console.aliyun.com/
2. 点击【创建实例】
3. 填写配置:
```yaml
付费类型: 包年包月首月¥70
地域: 华北2北京
可用区: 北京 可用区H
数据库类型: PostgreSQL
版本: 15
系列: 基础版(节省成本,不支持主备切换)
规格:
- CPU: 2核
- 内存: 4GB
- 存储: 50GB云盘ESSD
网络类型: 专有网络VPC
VPC: ai-clinical-vpc (vpc-2ze055cptkew9c38w4r06)
交换机: ai-clinical-vswitch-1 (vsw-2zevacop039bxrmj6yc0c)
```
4. 高级配置:
```yaml
数据库账号: airesearch
密码: 设置复杂密码记录到密码管理器Xibahe@fengzhibo117
数据库名称: ai_clinical_research
字符集: UTF8
```
5. 点击【立即购买】等待创建约5分钟
**⚠️ 关键配置(创建后):**
1. **白名单配置**(必须配置,否则无法连接):
- 进入实例详情 → 数据安全性 → 白名单设置
- 点击【修改】
- 添加:`172.17.0.0/16`整个VPC网段不要用单机IP
- 点击【确定】
2. **时区配置**(避免日志时间错乱):
- 进入实例详情 → 参数设置
- 搜索:`timezone`
- 修改值:`Asia/Shanghai`
- 点击【提交参数】
-**已配置**可维护时间窗02:00-06:00 Asia/Shanghai UTC+8
**✅ 实际RDS信息已部署**
```yaml
实例ID: pgm-2zex1m2y3r23hdn5
内网地址: pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432
数据库账号: airesearch
数据库密码: Xibahe@fengzhibo117
数据库名称: ai_clinical_research
VPC: vpc-2ze055cptkew9c38w4r06 (172.17.0.0/16)
资源组ID: rg-acfm4nrrfnu6tri
规格: 2核4GB (pg.n2.2c.1m)
最大连接数: 400
最大IOPS: 7550
PostgreSQL版本: 15.0
存储类型: 高性能云盘
白名单: 172.17.0.0/16 ✅
时区: Asia/Shanghai (UTC+8) ✅
```
**验证:**
- ✅ 实例状态为"运行中"
- ✅ 白名单已包含VPC网段 (172.17.0.0/16)
- ✅ 时区已设置为 Asia/Shanghai
- ✅ 可维护时间窗02:00-06:00夜间维护不影响白天使用
---
### 1.4 创建OSS存储桶10分钟
**目的:** 存储文献PDF、稿件文档等文件
**✅ 实际OSS信息已部署**
```yaml
Bucket名称: ai-clinical-research
地域: 华北2北京
存储类型: 标准存储
读写权限: 私有
存储冗余类型: 同城冗余存储
外网Endpoint: oss-cn-beijing.aliyuncs.com
内网Endpoint: oss-cn-beijing-internal.aliyuncs.com
Bucket域名内网: ai-clinical-research.oss-cn-beijing-internal.aliyuncs.com
创建时间: 2025-12-16 20:22
访问控制: 文件不可以被公共访问 ✅
```
**⚠️ 如果需要重新创建,操作步骤:**
1. 进入OSS控制台https://oss.console.aliyun.com/
2. 点击【创建Bucket】
3. 填写配置:
```yaml
Bucket名称: ai-clinical-research全局唯一
地域: 华北2北京
存储类型: 标准存储
读写权限: 私有(默认)
存储冗余类型: 同城冗余存储(推荐)
版本控制: 不开启
```
4. **推荐的目录结构**(应用会自动创建):
```
asl/ # AI文献筛选模块
├── source/ # 原始PDF文件
└── extracted/ # 解析结果JSON
pkb/ # 个人知识库模块
└── documents/ # 知识库文档
dc/ # 数据清洗模块
├── raw/ # 原始数据文件
└── cleaned/ # 清洗后的数据
```
5. **OSS访问授权配置**
**✅ 方案A使用AccessKey已创建推荐初期使用**
```yaml
RAM用户: oss-bucket-put-object@1991407246109125.onaliyun.com
AccessKeyId: LTAI5tB2Dt3NdvBL3G7nYGv7
AccessKeySecret: 1iSN9k39RkApP93QjUhC1DcPIeMG4V
权限: OSS Bucket写入权限
```
**⚠️ 安全警告:**
- AccessKey是敏感信息等同于密码
- 请勿将AccessKey提交到Git仓库
- 只在SAE环境变量中配置不要写入代码
- 定期轮换AccessKey建议每3个月
**方案B使用RAM角色推荐生产环境**
- 进入RAM控制台https://ram.console.aliyun.com/
- 创建角色AliyunSAEDefaultRoleSAE默认角色
- 授予权限AliyunOSSFullAccess
- 优势无需管理AccessKey更安全
**验证:**
- ✅ Bucket已创建成功
- ✅ 内网Endpoint`oss-cn-beijing-internal.aliyuncs.com`
- ✅ Bucket域名`ai-clinical-research.oss-cn-beijing-internal.aliyuncs.com`
- ✅ RAM用户已创建AccessKey已生成
---
### 1.5 创建容器镜像服务ACR5分钟
**目的:** 存储Docker镜像供SAE拉取部署
**✅ 实际ACR信息已部署**
```yaml
服务类型: 个人版(免费)
命名空间: ai-clinical
用户名: gofeng117@163.com
Registry密码: fengzhibo117
公网域名: crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com
专有网络域名: crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com
# 镜像仓库3个
仓库1 - 前端Nginx:
仓库名称: ai-clinical_frontend-nginx
公网地址: crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx
专有网络地址: crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx
类型: 私有
状态: ✅ 已创建
仓库2 - Python微服务:
仓库名称: python-extraction
公网地址: crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction
专有网络地址: crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction
类型: 私有
状态: ✅ 已创建
仓库3 - Node.js后端:
仓库名称: 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
类型: 私有
状态: ✅ 已创建
```
**⚠️ 如果需要重新创建,操作步骤:**
1. 进入容器镜像服务控制台https://cr.console.aliyun.com/
2. 选择【个人版】(免费)
3. 设置Registry密码用于docker login
4. 创建命名空间:`ai-clinical`
5. 创建3个镜像仓库类型私有代码源本地仓库
**验证:**
- ✅ 3个仓库创建成功
- ✅ Registry地址`crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com`
- ✅ 专有网络地址:`crpi-cd5ij4pjt65mweeo-vpc.cn-beijing.personal.cr.aliyuncs.com`
**⚠️ 安全警告:**
- Registry密码是敏感信息等同于Docker镜像访问权限
- 请勿将密码提交到Git仓库
- 定期轮换密码建议每3个月
---
## 第二阶段数据库初始化30分钟
### 2.1 导出本地数据库5分钟
**在本地项目根目录执行:**
```bash
# 确保Docker正在运行
docker ps
# 导出数据库
docker exec ai-clinical-postgres pg_dump \
-U postgres \
-d ai_clinical_research \
--no-owner \
--no-acl \
--clean \
--if-exists \
> rds_init.sql
# 验证文件大小应该有几百KB
ls -lh rds_init.sql
```
**验证:** `rds_init.sql` 文件存在,且大小 > 100KB
---
### 2.2 通过ECS跳板机连接RDS15分钟
**⚠️ 为什么需要跳板机?**
- RDS在VPC内网本地电脑无法直接连接
- 需要一台ECS服务器作为"桥梁"
**操作步骤:**
**方案A使用现有Dify ECS如果已有**
跳过ECS创建步骤直接使用Dify的ECS作为跳板机。
**方案B创建临时ECS推荐初期使用**
1. 进入ECS控制台创建按量付费实例
```yaml
地域: 华北2北京
规格: ecs.t6-c1m1.large1核1GB¥0.05/小时)
镜像: Ubuntu 22.04
网络: ai-clinical-vpc (vpc-2ze055cptkew9c38w4r06) / ai-clinical-vswitch-1
安全组: sg-2zedk6fi8sgmmcwdu7tu允许22端口SSH
购买时长: 按量付费
```
2. 在本地创建SSH隧道
```bash
# 替换以下参数:
# - ECS_PUBLIC_IP: ECS的公网IP
ssh -N -L 5433:pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432 \
root@ECS_PUBLIC_IP
# 输入ECS密码成功后命令会"卡住"(正常现象)
# 保持这个终端窗口打开
```
**验证:** 打开新终端,执行:
```bash
# 测试RDS连接通过SSH隧道
psql -h localhost -p 5433 -U airesearch -d ai_clinical_research
# 输入密码Xibahe@fengzhibo117
# 如果成功连接,说明隧道已建立
```
---
### 2.3 导入数据到RDS10分钟
**在新终端窗口执行:**
```bash
# 导入数据通过SSH隧道
psql -h localhost -p 5433 \
-U airesearch \
-d ai_clinical_research \
-f rds_init.sql
# 输入密码Xibahe@fengzhibo117
# 验证导入成功
psql -h localhost -p 5433 \
-U airesearch \
-d ai_clinical_research \
-c "\dt platform_schema.*"
# 应该看到 platform_schema 下的表
```
**验证:**
- 看到 `platform_schema.users`
- 看到 `aia_schema.*`
- 看到 `_prisma_migrations`
**⚠️ 重要:** pg-boss的6个表job/queue等不在导出文件中会在应用首次启动时自动创建。
---
## 第三阶段Docker镜像构建与推送60分钟
### 3.1 登录阿里云容器镜像服务
**在本地终端执行:**
```bash
# 登录ACR个人版使用真实信息
docker login --username=gofeng117@163.com crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com
# 输入密码fengzhibo117
# 看到 "Login Succeeded" 表示登录成功
```
**⚠️ 注意事项:**
- 个人版使用自定义域名,不是标准的 `registry.cn-beijing.aliyuncs.com`
- 用户名:`gofeng117@163.com`(完整邮箱地址)
- 密码:`fengzhibo117`Registry密码不是阿里云账号密码
---
### 3.2 构建Python微服务镜像15分钟
**在项目根目录执行:**
```bash
cd extraction_service
# 构建镜像确保Dockerfile存在
docker build -t ai-clinical/python-extraction:v1.0.0 .
# 打标签使用真实ACR地址
docker tag ai-clinical/python-extraction:v1.0.0 \
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0.0
docker tag ai-clinical/python-extraction:v1.0.0 \
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:latest
# 推送到ACR
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0.0
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:latest
cd ..
```
**验证:**
- 在ACR控制台看到镜像标签为 `v1.0.0``latest`
- 镜像地址:`crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0.0`
---
### 3.3 构建Node.js后端镜像20分钟
**⚠️ 重要前置步骤复制Prisma目录**
```bash
# 在项目根目录执行
cp -r prisma backend/
# 验证
ls backend/prisma/schema.prisma # 应该存在
```
**构建镜像:**
```bash
cd backend
# 构建镜像
docker build -t ai-clinical/nodejs-backend:v1.0.0 .
# 打标签并推送使用真实ACR地址
docker tag ai-clinical/nodejs-backend:v1.0.0 \
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/nodejs-backend:v1.0.0
docker tag ai-clinical/nodejs-backend:v1.0.0 \
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/nodejs-backend:latest
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/nodejs-backend:v1.0.0
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/nodejs-backend:latest
cd ..
```
**验证:**
- ACR控制台看到Node.js镜像
- 镜像地址:`crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/nodejs-backend:v1.0.0`
---
### 3.4 构建前端Nginx镜像25分钟
**在项目根目录执行:**
```bash
cd frontend-v2
# 构建镜像包含React构建 + Nginx打包
docker build -t ai-clinical/frontend-nginx:v1.0.0 .
# 打标签并推送使用真实ACR地址注意仓库名称带下划线
docker tag ai-clinical/frontend-nginx:v1.0.0 \
crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0.0
docker tag ai-clinical/frontend-nginx:v1.0.0 \
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.0
docker push crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:latest
cd ..
```
**⚠️ 注意:** 前端仓库名称是 `ai-clinical_frontend-nginx`(带下划线),与后端不同。
**验证:**
- ACR控制台看到3个镜像仓库每个都有 `v1.0.0``latest` 标签
- 前端镜像地址:`crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0.0`
---
## 第四阶段SAE应用部署60分钟
### 4.1 部署Python微服务15分钟
**操作步骤:**
1. 进入SAE控制台https://sae.console.aliyun.com/
2. 点击【创建应用】
3. 基础配置:
```yaml
应用名称: python-extraction-service
命名空间: cn-beijing:test-airesearch已创建
地域: 华北2北京
VPC: ai-clinical-vpc (vpc-2ze055cptkew9c38w4r06)
安全组: sg-2zedk6fi8sgmmcwdu7tu
```
4. 应用配置:
```yaml
技术栈: 容器镜像
镜像: crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/python-extraction:v1.0.0
镜像拉取策略: Always重要
版本: v1.0.0
```
**⚠️ 重要:** 使用个人版ACR地址不是标准的 `registry.cn-beijing.aliyuncs.com`
5. 应用实例:
```yaml
CPU: 1核
内存: 2GB
实例数: 1
```
6. 高级配置:
```yaml
端口: 8000
健康检查: HTTP
- 路径: /health
- 初始延迟: 30秒
- 超时: 3秒
- 检查间隔: 5秒
环境变量: 暂时为空Python微服务是纯计算服务
```
7. 点击【创建】等待部署约5分钟
**验证:**
- 应用状态为"运行中"
- 健康检查通过
- 记录内网地址(格式:`172.17.x.x:8000`
---
### 4.2 部署Node.js后端20分钟
**操作步骤:**
1. 创建新应用:`nodejs-backend-service`
2. 应用配置:
```yaml
镜像: crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/nodejs-backend:v1.0.0
镜像拉取策略: Always
CPU: 2核
内存: 4GB
实例数: 1
端口: 3001
```
**⚠️ 重要:** 使用个人版ACR地址
3. **环境变量配置(⭐⭐⭐⭐⭐ 重要):**
```bash
# ==================== 数据库配置 ====================
# ⚠️ 注意:密码中的 @ 符号必须转义为 %40
DATABASE_URL=postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research
# ✅ 已使用实际RDS信息密码已转义
# ==================== 存储配置 ====================
STORAGE_TYPE=oss
OSS_REGION=oss-cn-beijing
OSS_BUCKET=ai-clinical-research
OSS_ENDPOINT=oss-cn-beijing-internal.aliyuncs.com
# ✅ OSS配置已使用实际Bucket信息
# Bucket域名: ai-clinical-research.oss-cn-beijing-internal.aliyuncs.com
# OSS访问凭证方案A使用AccessKey
OSS_ACCESS_KEY_ID=LTAI5tB2Dt3NdvBL3G7nYGv7
OSS_ACCESS_KEY_SECRET=1iSN9k39RkApP93QjUhC1DcPIeMG4V
# ⚠️ 注意AccessKey是敏感信息请勿提交到Git
# OSS访问凭证方案B使用RAM角色更安全
# 在SAE控制台配置RAM角色AliyunSAEDefaultRole
# 优势无需在环境变量中配置AccessKey
# ==================== 微服务地址 ====================
EXTRACTION_SERVICE_URL=http://172.17.x.x:8000
# ⚠️ 替换172.17.x.x从Python微服务控制台获取内网IP
DIFY_API_URL=http://placeholder/v1
DIFY_API_KEY=temp_placeholder
# ⚠️ 暂不部署Dify使用占位符PKB模块会自动禁用
# ==================== LLM配置 ====================
DEEPSEEK_API_KEY=sk-xxxxxxxx
# ⚠️ 替换为真实的DeepSeek API Key
# ==================== 应用配置 ====================
NODE_ENV=production
PORT=3001
```
4. **启动命令(重要!):**
```bash
/bin/sh -c "npx prisma migrate deploy && node dist/index.js"
```
**⚠️ 说明:**
- `npx prisma migrate deploy`:部署数据库迁移
- `node dist/index.js`:启动应用
5. 健康检查:
```yaml
路径: /health
初始延迟: 60秒留时间给Prisma迁移
超时: 5秒
```
6. 点击【创建】等待部署约10分钟
**验证:**
- 查看"实时日志",看到:
```
✅ Prisma migrate deploy 完成
✅ pg-boss 自动创建6个表
✅ 应用启动成功,监听 0.0.0.0:3001
```
- 健康检查通过
- 记录内网地址(格式:`172.17.x.x:3001`
**⚠️ 如果启动失败:**
常见原因:
1. DATABASE_URL错误 → 检查密码、RDS地址
- 当前RDSpgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com
- 用户名airesearch
- 密码中有特殊字符@URL中需要转义为 %40
2. 白名单未配置 → ✅ 已确认配置172.17.0.0/16
3. Prisma迁移失败 → 查看日志,确认数据库权限
**⚠️ 密码特殊字符转义(重要):**
```bash
# 原始密码Xibahe@fengzhibo117
# @ 符号需要转义为 %40
# 错误写法(会导致连接失败):
DATABASE_URL=postgresql://airesearch:Xibahe@fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research
# 正确写法:
DATABASE_URL=postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research
```
---
### 4.3 部署前端Nginx15分钟
**操作步骤:**
1. 创建新应用:`frontend-nginx`
2. 应用配置:
```yaml
镜像: crpi-cd5ij4pjt65mweeo.cn-beijing.personal.cr.aliyuncs.com/ai-clinical/ai-clinical_frontend-nginx:v1.0.0
镜像拉取策略: Always
CPU: 1核
内存: 2GB
实例数: 1
端口: 80
```
**⚠️ 重要:**
- 使用个人版ACR地址
- 注意仓库名称是 `ai-clinical_frontend-nginx`(带下划线)
3. **环境变量配置:**
```bash
# 后端服务地址(内网)
BACKEND_SERVICE_HOST=172.17.x.x
BACKEND_SERVICE_PORT=3001
# ⚠️ 替换172.17.x.x从Node.js后端控制台获取内网IP
```
4. 健康检查:
```yaml
路径: /health
初始延迟: 10秒
超时: 3秒
```
5. **配置公网访问(重要!):**
- 在应用详情 → 基本信息 → 公网访问
- 点击【开启】
- 获得公网域名(格式:`xxxx.cn-beijing.alicontainer.com`
6. 点击【创建】等待部署约5分钟
**验证:**
- 应用状态为"运行中"
- 通过公网域名访问,看到登录页面
---
## 第五阶段验证与测试30分钟
### 5.1 健康检查验证5分钟
**Python微服务**
```bash
# 在本地终端执行(替换为实际公网地址,如果开启了)
# 或通过Node.js后端间接验证
# 直接测试如果Python开启了公网
curl http://python-service-public-url/health
# 预期响应:
{"status":"healthy"}
```
**Node.js后端**
```bash
curl http://backend-public-url/health
# 预期响应:
{"status":"ok","database":"connected","timestamp":"..."}
```
**前端Nginx**
```bash
curl http://frontend-public-url/health
# 预期响应:
{"status":"ok"}
```
---
### 5.2 功能测试15分钟
#### 5.2.1 用户登录测试
1. 访问前端公网地址:`http://xxxxx.cn-beijing.alicontainer.com`
2. 使用测试账号登录:
- 账号:`admin@test.com`
- 密码:`admin123`(或你本地数据库中的密码)
3. 验证:成功跳转到主页,显示用户名
#### 5.2.2 文献筛选测试ASL模块
1. 进入【AI智能文献】模块
2. 创建新项目:
```yaml
项目名称: 测试项目
研究主题: 糖尿病治疗
```
3. 上传测试文献(小文件,< 5MB
4. 验证:
- 文件上传到OSS成功
- 后端调用Python服务解析PDF
- 数据库中生成记录
#### 5.2.3 数据清洗测试DC模块
1. 进入【数据清洗】模块
2. 上传测试Excel文件
3. 验证:
- OSS上传成功
- Python服务处理数据
- 下载清洗结果
---
### 5.3 日志排查10分钟
#### 查看SAE实时日志
**Python微服务**
```
SAE控制台 → python-extraction-service → 日志 → 实时日志
查看是否有错误日志ERROR/WARN
```
**Node.js后端**
```
SAE控制台 → nodejs-backend-service → 日志 → 实时日志
关键日志:
✅ Prisma connected
✅ pg-boss started
✅ Server listening on 0.0.0.0:3001
```
**前端Nginx**
```
SAE控制台 → frontend-nginx → 日志 → 访问日志
查看HTTP请求日志200/404/500状态码
```
---
## 🚨 常见问题与解决方案
### 问题1后端无法连接数据库
**症状:** Node.js日志显示 `connection timeout` 或 `FATAL: no pg_hba.conf entry`
**解决方案:**
1. 检查RDS白名单
```
RDS控制台 → 数据安全性 → 白名单设置
确保包含172.17.0.0/16VPC网段
```
2. 检查DATABASE_URL
```bash
# ✅ 正确格式(特殊字符已转义):
postgresql://airesearch:Xibahe%40fengzhibo117@pgm-2zex1m2y3r23hdn5.pg.rds.aliyuncs.com:5432/ai_clinical_research
# 常见错误:
- 密码中的 @ 符号未转义为 %40最常见
- RDS地址错误应该用内网地址
- 数据库名称错误
# 特殊字符转义规则:
@ -> %40
# -> %23
$ -> %24
% -> %25
```
---
### 问题2后端调用Python微服务超时
**症状:** 日志显示 `ECONNREFUSED` 或 `timeout`
**解决方案:**
1. 检查Python微服务内网地址
```
SAE控制台 → python-extraction-service → 基本信息 → 内网地址
复制IP地址格式172.17.x.x
```
2. 更新Node.js后端环境变量
```bash
EXTRACTION_SERVICE_URL=http://172.17.x.x:8000
```
3. 重启Node.js后端应用
---
### 问题3前端调用后端404
**症状:** 浏览器控制台显示 `/api/xxx 404`
**解决方案:**
1. 检查前端环境变量:
```bash
# 确认 BACKEND_SERVICE_HOST 是Node.js的内网IP
BACKEND_SERVICE_HOST=172.17.x.x
BACKEND_SERVICE_PORT=3001
```
2. 检查Nginx配置已内置在镜像中
```nginx
location /api/ {
proxy_pass http://${BACKEND_SERVICE_HOST}:${BACKEND_SERVICE_PORT};
}
```
3. 重启前端应用
---
### 问题4文件上传到OSS失败
**症状:** 上传文件时报错 `OSS access denied`
**解决方案:**
1. **方案A使用AccessKey已配置**
```bash
# 确认Node.js后端环境变量已配置
OSS_ACCESS_KEY_ID=LTAI5tB2Dt3NdvBL3G7nYGv7
OSS_ACCESS_KEY_SECRET=1iSN9k39RkApP93QjUhC1DcPIeMG4V
```
**验证方法:**
- SAE控制台 → nodejs-backend-service → 应用设置 → 环境变量
- 检查是否包含 `OSS_ACCESS_KEY_ID` 和 `OSS_ACCESS_KEY_SECRET`
2. **方案B使用RAM角色推荐生产环境**
```
SAE控制台 → 应用设置 → 高级设置 → RAM角色
选择AliyunSAEDefaultRole
确保该角色有 AliyunOSSFullAccess 权限
```
**优势:**
- 无需在环境变量中配置AccessKey
- 更安全避免AccessKey泄露风险
- 支持自动轮换凭证
3. **检查RAM用户权限**
```
RAM控制台 → 用户 → oss-bucket-put-object@1991407246109125.onaliyun.com
确认权限PutObject写入权限
```
---
### 问题5AI功能无法调用DeepSeek API超时
**症状:** LLM对话功能报错 `network timeout`
**解决方案:**
1. **检查NAT网关SNAT规则**
```
VPC控制台 → NAT网关 → NAT_airesearch → SNAT管理
✅ 已确认配置:
- 交换机F (vsw-2zevacop039bxrmj6yc0c): 172.17.160.0/20 → 182.92.176.14 (可用)
- 交换机A (vsw-2zehoeyw9ldncymcyvfwq): 172.17.192.0/20 → 182.92.176.14 (可用)
```
2. **验证公网访问能力:**
```bash
# 在SAE应用实例中执行命令通过WebIDE
curl https://api.deepseek.com/v1/models
# 应该返回模型列表,而不是 timeout
```
3. **如果SNAT未生效**
- 检查EIP是否已绑定
- 检查SNAT条目状态是否为"可用"
- 重启SAE应用
---
## 📊 成本估算
| 资源 | 规格 | 月成本 | 说明 |
|------|------|-------|------|
| **RDS PostgreSQL** | 2核4GB/50GB | ¥200-300 | 包年包月(已购买)|
| **SAE - Python** | 1核2GB × 1实例 | ¥60 | 按量付费闲时¥0 |
| **SAE - Node.js** | 2核4GB × 1实例 | ¥120 | 按量付费 |
| **SAE - Frontend** | 1核2GB × 1实例 | ¥60 | 按量付费 |
| **NAT网关** | 小型 | ¥60 | 固定费用(已创建)|
| **EIP流量费** | 5Mbps | ¥40 | 按使用量计费(已配置)|
| **OSS存储** | 10GB | ¥2 | ¥0.12/GB/月(已创建)|
| **ACR容器镜像** | 个人版 | ¥0 | 免费 |
| **总计** | - | **¥542-622/月** | 初创团队成本 |
**节省成本建议:**
1. RDS购买包年包月首月¥70续费¥200/月)
2. 开发环境只开1个SAE实例其他实例缩容到0
3. 使用SAE的"闲时停机"功能(晚上自动停机)
---
## 🎯 下一步工作
### 短期1周内
- [ ] 绑定自定义域名(阿里云域名服务 + SAE绑定
- [ ] 配置HTTPS证书Let's Encrypt免费证书
- [ ] 配置OSS CDN加速前端静态资源加速
- [ ] 开启RDS自动备份数据安全第一
### 中期1个月内
- [ ] 部署Dify平台启用PKB个人知识库功能
- [ ] 配置监控告警ARMS应用监控
- [ ] 优化数据库索引(提升查询性能)
- [ ] 实施CI/CD自动化部署GitHub Actions
### 长期3个月后
- [ ] 多实例部署(提升高可用性)
- [ ] 数据库读写分离RDS主备版
- [ ] OSS生命周期管理自动清理临时文件
- [ ] 性能优化与成本优化
---
## 📚 相关文档
- [部署架构总览](./00-部署架构总览.md)
- [Python微服务部署指南](./04-Python微服务-SAE容器部署指南.md)
- [Node.js后端部署指南](./05-Node.js后端-SAE容器部署指南.md)
- [前端Nginx部署指南](./06-前端Nginx-SAE容器部署指南.md)
- [PostgreSQL部署策略](./PostgreSQL部署策略-摸底报告.md)
- [关键配置补充说明](./07-关键配置补充说明.md)
- [部署检查清单](./08-部署检查清单.md)
---
## 🆘 紧急联系
**如果遇到无法解决的问题:**
1. 查看SAE实时日志90%的问题能从日志中发现)
2. 检查环境变量配置DATABASE_URL、服务地址等
3. 验证网络连通性VPC、白名单、NAT网关
4. 参考详细部署文档(每个模块有独立的完整指南)
**文档版本:** v1.0
**最后更新:** 2025-12-16
**维护者:** AI临床研究平台技术团队