deploy: Complete 0126-27 deployment - database upgrade, services update, code recovery

Major Changes:
- Database: Install pg_bigm/pgvector plugins, create test database
- Python service: v1.0 -> v1.1, add pymupdf4llm/openpyxl/pypandoc
- Node.js backend: v1.3 -> v1.7, fix pino-pretty and ES Module imports
- Frontend: v1.2 -> v1.3, skip TypeScript check for deployment
- Code recovery: Restore empty files from local backup

Technical Fixes:
- Fix pino-pretty error in production (conditional loading)
- Fix ES Module import paths (add .js extensions)
- Fix OSSAdapter TypeScript errors
- Update Prisma Schema (63 models, 16 schemas)
- Update environment variables (DATABASE_URL, EXTRACTION_SERVICE_URL, OSS)
- Remove deprecated variables (REDIS_URL, DIFY_API_URL, DIFY_API_KEY)

Documentation:
- Create 0126 deployment folder with 8 documents
- Update database development standards v2.0
- Update SAE deployment status records

Deployment Status:
- PostgreSQL: ai_clinical_research_test with plugins
- Python: v1.1 @ 172.17.173.84:8000
- Backend: v1.7 @ 172.17.173.89:3001
- Frontend: v1.3 @ 172.17.173.90:80

Tested: All services running successfully on SAE
This commit is contained in:
2026-01-27 08:13:27 +08:00
parent 01a17f1e6f
commit 2481b786d8
318 changed files with 5290 additions and 3216 deletions

View File

@@ -1,339 +1,512 @@
# 数据库开发规范
> 版本: v1.0
> 更新日期: 2026-01-11
> 编写背景: 2026-01-11 数据库事故后总结
> 版本: v2.0
> 更新日期: 2026-01-26
> 重要更新: 统一使用 Prisma Schema 管理所有数据库变更
---
## 1. 核心原则
### 1.1 安全第一
## 📢 核心原则
```
⚠️ 黄金法则:任何数据库操作前,必须先备份!
┌─────────────────────────────────────────────────────────────────────┐
│ 🎯 统一原则:所有数据库变更必须通过 Prisma Schema 管理 │
│ │
│ ✅ 使用 prisma migrate dev/deploy 进行变更 │
│ ❌ 禁止直接执行手工 SQL 修改表结构 │
│ ❌ 禁止使用 prisma db push仅用于原型开发
└─────────────────────────────────────────────────────────────────────┘
```
### 1.2 禁止使用的危险命令
---
| 命令 | 危险等级 | 说明 |
## 1. 开发流程规范
### 1.1 标准开发流程(必须遵循)
```
┌─────────────────────────────────────────────────────────────────────┐
│ 数据库变更标准流程 │
└─────────────────────────────────────────────────────────────────────┘
开发阶段 部署阶段
──────── ────────
┌─────────────────┐ ┌─────────────────┐
│ 1. 修改 schema.prisma │ │ 1. 代码合并到主分支 │
└────────┬────────┘ └────────┬────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 2. npx prisma migrate dev │ │ 2. 备份生产数据库 │
│ --name feature_name │ └────────┬────────┘
└────────┬────────┘ │
│ ▼
▼ ┌─────────────────┐
┌─────────────────┐ │ 3. npx prisma migrate deploy │
│ 3. 检查生成的迁移SQL │ └────────┬────────┘
└────────┬────────┘ │
│ ▼
▼ ┌─────────────────┐
┌─────────────────┐ │ 4. 验证 & 测试 │
│ 4. 本地测试 │ └─────────────────┘
└────────┬────────┘
┌─────────────────┐
│ 5. 提交代码 + 迁移文件 │
└─────────────────┘
```
### 1.2 命令使用规范
| 场景 | 命令 | 说明 |
|------|------|------|
| **开发时新增/修改表** | `npx prisma migrate dev --name xxx` | ✅ 生成迁移文件 |
| **生产环境部署** | `npx prisma migrate deploy` | ✅ 应用未执行的迁移 |
| **生成 Prisma Client** | `npx prisma generate` | ✅ 更新类型定义 |
| **检查迁移状态** | `npx prisma migrate status` | ✅ 查看待迁移列表 |
| **验证 Schema** | `npx prisma validate` | ✅ 检查语法错误 |
### 1.3 禁止使用的命令
| 命令 | 危险等级 | 原因 |
|------|----------|------|
| `prisma db push --force-reset` | 🔴 **** | 会删除所有数据和非Prisma管理的对象 |
| `prisma db push` | 🟠 **高** | 不生成迁移文件,无法追踪变更历史 |
| `prisma db push --force-reset` | 🔴 **极高** | 会删除所有数据 |
| `prisma migrate reset` | 🔴 **极高** | 重置整个数据库 |
| `DROP DATABASE` | 🔴 **** | 删除整个数据库 |
| `TRUNCATE TABLE` | 🟠 高 | 清空表数据 |
### 1.3 推荐的安全命令
| 命令 | 用途 | 安全性 |
|------|------|--------|
| `prisma migrate dev` | 开发环境迁移 | ✅ 安全 |
| `prisma migrate deploy` | 生产环境迁移 | ✅ 安全 |
| `prisma db push` (无 --force-reset) | 同步schema到数据库 | ⚠️ 谨慎使用 |
| `prisma generate` | 生成客户端 | ✅ 安全 |
| 手工执行 `ALTER TABLE` | 🟠 **高** | 导致 Schema 与数据库不一致 |
| 手工执行 `CREATE TABLE` | 🟠 **高** | 导致 Schema 与数据库不一致 |
---
## 2. 数据库备份规范
## 2. Schema 变更示例
### 2.1 备份命令
### 2.1 新增表
```prisma
// 1. 在 schema.prisma 中添加模型
model NewFeature {
id String @id @default(uuid())
name String
createdAt DateTime @default(now()) @map("created_at")
@@map("new_features") // 表名使用下划线
@@schema("feature_schema") // 指定 Schema
}
```
```bash
# 通过 Docker 备份(推荐)
docker exec ai-clinical-postgres pg_dump -U postgres -d ai_clinical_research > backup_$(date +%Y%m%d_%H%M%S).sql
# 2. 生成迁移
npx prisma migrate dev --name add_new_feature_table
# PowerShell 版本
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
docker exec ai-clinical-postgres pg_dump -U postgres -d ai_clinical_research > "backup_$timestamp.sql"
# 3. 检查生成的 SQL
cat prisma/migrations/xxx_add_new_feature_table/migration.sql
```
### 2.2 备份时机
| 时机 | 是否必须 |
|------|----------|
| 执行任何 `prisma migrate` 前 | ✅ 必须 |
| 执行 `prisma db push` 前 | ✅ 必须 |
| 部署到生产环境前 | ✅ 必须 |
| 每日自动备份 | ✅ 推荐 |
| 重大功能发布前 | ✅ 必须 |
### 2.3 备份文件管理
### 2.2 新增字段
```prisma
// 1. 在模型中添加字段
model User {
id String @id
email String
phone String? // 新增字段,可为空
createdAt DateTime @default(now())
@@schema("platform_schema")
}
```
AIclinicalresearch/
├── backup_20260111_131506.sql # 日期_时间命名
├── rds_init_20251224_154529.sql # 历史备份
└── ...
```bash
# 2. 生成迁移
npx prisma migrate dev --name add_user_phone_field
```
### 2.3 修改字段
```prisma
// 1. 修改字段类型或约束
model Document {
id String @id
title String @db.VarChar(500) // 修改长度
description String? @db.Text // 改为 Text 类型
@@schema("pkb_schema")
}
```
```bash
# 2. 生成迁移(注意:某些修改可能导致数据丢失)
npx prisma migrate dev --name update_document_fields
```
### 2.4 新增 Schema
```prisma
// 1. 在 datasource 中添加新 Schema
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
schemas = ["platform_schema", "aia_schema", "new_schema"] // 添加新 Schema
}
// 2. 创建使用新 Schema 的模型
model NewModule {
id String @id
name String
@@schema("new_schema")
}
```
---
## 3. Schema 变更流程
## 3. 迁移文件管理
### 3.1 标准流程
### 3.1 迁移文件结构
```mermaid
graph TD
A[修改 schema.prisma] --> B[备份数据库]
B --> C[运行 prisma migrate dev]
C --> D{迁移成功?}
D -->|是| E[测试功能]
D -->|否| F[从备份恢复]
E --> G{测试通过?}
G -->|是| H[提交代码]
G -->|否| F
```
prisma/
├── schema.prisma # Schema 定义文件
├── migrations/
├── 20251010075003_init/
│ └── migration.sql # 初始化迁移
├── 20251012124747_add_batch/
│ │ └── migration.sql # 功能迁移
└── migration_lock.toml # 迁移锁文件
└── manual_sql_scripts/ # 手动 SQL仅用于特殊场景
└── *.sql
```
### 3.2 具体步骤
### 3.2 迁移文件命名规范
```bash
# 1. 备份数据库
docker exec ai-clinical-postgres pg_dump -U postgres -d ai_clinical_research > backup_before_migration.sql
# 格式动词_对象_描述
npx prisma migrate dev --name add_user_phone_field
npx prisma migrate dev --name create_iit_schema_tables
npx prisma migrate dev --name update_document_status_enum
npx prisma migrate dev --name remove_deprecated_columns
```
# 2. 修改 schema.prisma
### 3.3 迁移文件版本控制
# 3. 创建迁移
npx prisma migrate dev --name describe_your_change
```
✅ 必须提交的文件:
- prisma/schema.prisma
- prisma/migrations/*/migration.sql
- prisma/migrations/migration_lock.toml
# 4. 检查生成的迁移 SQL
cat prisma/migrations/xxx_describe_your_change/migration.sql
❌ 不要提交的文件:
- 本地测试的临时迁移
```
# 5. 测试
---
# 6. 如果失败,恢复备份
## 4. 生产环境部署规范
### 4.1 部署前检查清单
```
┌─────────────────────────────────────────────────────────────────────┐
│ 📋 生产部署前检查清单 │
├─────────────────────────────────────────────────────────────────────┤
│ □ 本地开发环境测试通过 │
│ □ 迁移文件已提交到代码仓库 │
│ □ 已执行 npx prisma migrate status 确认待迁移列表 │
│ □ 已审查迁移 SQL确认无破坏性变更 │
│ □ 已备份生产数据库 │
│ □ 已准备回滚方案 │
│ □ 已通知相关人员 │
└─────────────────────────────────────────────────────────────────────┘
```
### 4.2 部署命令
```bash
# 1. 检查迁移状态
npx prisma migrate status
# 2. 执行迁移(仅应用未执行的迁移)
npx prisma migrate deploy
# 3. 生成 Prisma Client
npx prisma generate
```
### 4.3 SAE 环境部署
在 SAE 部署时Dockerfile 中应包含:
```dockerfile
# 构建阶段
RUN npx prisma generate
# 启动命令package.json 中配置)
# "start:prod": "npx prisma migrate deploy && node dist/main.js"
```
或在启动脚本中:
```bash
#!/bin/bash
# 应用迁移
npx prisma migrate deploy
# 启动应用
node dist/main.js
```
### 4.4 回滚方案
```bash
# 方案1从备份恢复推荐
cat backup_before_migration.sql | docker exec -i ai-clinical-postgres psql -U postgres -d ai_clinical_research
```
---
## 4. Prisma 与数据库不一致问题
### 4.1 Prisma 不管理的对象
以下数据库对象不在 `schema.prisma` 中定义,需要单独管理:
| 对象 | 类型 | 来源 | 恢复脚本 |
|------|------|------|----------|
| `platform_schema.job_common` | 表 | pg-boss 运行时创建 | `restore_job_common.sql` |
| `platform_schema.create_queue()` | 函数 | pg-boss 初始化 | `restore_pgboss_functions.sql` |
| `platform_schema.delete_queue()` | 函数 | pg-boss 初始化 | `restore_pgboss_functions.sql` |
### 4.2 恢复非 Prisma 管理的对象
```bash
# 如果误删了 pg-boss 相关对象,执行:
npx prisma db execute --file restore_job_common.sql --schema prisma/schema.prisma
npx prisma db execute --file restore_pgboss_functions.sql --schema prisma/schema.prisma
```
### 4.3 检查数据库与 Prisma 一致性
```bash
# 查看数据库中的函数
SELECT routine_name FROM information_schema.routines WHERE routine_schema = 'platform_schema';
# 查看数据库中的表
SELECT table_name FROM information_schema.tables WHERE table_schema = 'platform_schema';
# 对比 schema.prisma 定义
# 方案2手动回滚迁移需要准备回滚 SQL
# 在 migrations/ 目录下准备 rollback_xxx.sql
```
---
## 5. 多 Schema 架构规范
### 5.1 Schema 命名规范
### 5.1 当前 Schema 列表
| Schema | 用途 | 示例表 |
|--------|------|--------|
| `platform_schema` | 平台基础设施 | users, tenants, app_cache |
| `admin_schema` | 运营管理 | admin_operation_logs |
| `aia_schema` | AI智能问答 | conversations, messages |
| `asl_schema` | 文献筛选 | screening_projects, literatures |
| `dc_schema` | 数据清洗 | dc_templates, dc_extraction_tasks |
| `pkb_schema` | 个人知识库 | knowledge_bases, documents |
| `iit_schema` | IIT项目 | projects, audit_logs |
| `rvw_schema` | 论文预审 | review_tasks |
| `capability_schema` | 通用能力 | prompt_templates |
| `public` | 旧数据/兼容 | users (旧), admin_logs |
| Schema | 用途 | 表数量 | 管理方式 |
|--------|------|--------|----------|
| `platform_schema` | 平台基础设施用户、租户、pg-boss | 19 | Prisma + pg-boss |
| `aia_schema` | AI智能问答 | 3 | Prisma |
| `asl_schema` | 文献筛选 | 7 | Prisma |
| `pkb_schema` | 个人知识库 | 5 | Prisma |
| `dc_schema` | 数据清洗 | 6 | Prisma |
| `iit_schema` | IIT项目管理 | 5 | Prisma |
| `agent_schema` | Agent框架 | 6 | Prisma |
| `ekb_schema` | 企业知识库 | 3 | Prisma |
| `capability_schema` | 通用能力 | 2 | Prisma |
| `protocol_schema` | 方案设计 | 2 | Prisma |
| `rvw_schema` | 论文预审 | 1 | Prisma |
| `admin_schema` | 运营管理 | 2 | Prisma |
| `public` | 兼容旧数据 | 2 | Prisma |
### 5.2 表命名规范
```
{schema_name}.{module_prefix}_{entity_name}
示例:
- dc_schema.dc_templates
- dc_schema.dc_extraction_tasks
- asl_schema.screening_projects
```
---
## 6. 外键与数据完整性
### 6.1 跨 Schema 外键
### 5.2 新增 Schema 规范
```prisma
// ✅ 正确:明确指定关系
model ReviewTask {
userId String @map("user_id")
user PublicUser @relation(fields: [userId], references: [id])
@@schema("rvw_schema")
// 1. 在 datasource 中声明
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
schemas = [
"platform_schema",
"aia_schema",
// ... 现有 schemas
"new_module_schema" // 新增
]
}
model PublicUser {
id String @id
reviewTasks ReviewTask[]
// 2. 在模型中使用
model NewModuleTable {
id String @id @default(uuid())
name String
@@schema("public")
@@map("new_module_tables")
@@schema("new_module_schema")
}
```
### 6.2 外键指向检查
### 5.3 命名规范
在使用 `prisma db push` 后,检查外键是否正确:
| 类型 | 格式 | 示例 |
|------|------|------|
| Schema | `{module}_schema` | `iit_schema`, `asl_schema` |
| 表名 | `{module_prefix}_{entity_name}` | `dc_templates`, `asl_literatures` |
| 字段名 | `snake_case` | `created_at`, `user_id` |
| 索引名 | `idx_{table}_{column}` | `idx_users_email` |
```sql
SELECT
tc.table_schema, tc.table_name, kcu.column_name,
ccu.table_schema AS foreign_schema, ccu.table_name AS foreign_table
FROM information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY';
---
## 6. 特殊场景处理
### 6.1 pg-boss 表(自动管理)
pg-boss 会自动创建和管理以下表,**不需要**在 Prisma Schema 中定义:
| 表名 | 用途 |
|------|------|
| `platform_schema.job` | 任务队列 |
| `platform_schema.job_common` | 任务通用信息 |
| `platform_schema.queue` | 队列定义 |
| `platform_schema.schedule` | 定时任务 |
| `platform_schema.subscription` | 订阅信息 |
| `platform_schema.version` | 版本信息 |
### 6.2 pgvector 字段
```prisma
// pgvector 类型使用 Unsupported
model EkbChunk {
id String @id
content String
embedding Unsupported("vector")? // 向量字段
@@schema("ekb_schema")
}
```
操作 vector 字段时使用原生 SQL
```typescript
// 插入向量
await prisma.$executeRaw`
UPDATE ekb_schema.ekb_chunk
SET embedding = ${embedding}::vector
WHERE id = ${id}
`
// 相似度查询
const results = await prisma.$queryRaw`
SELECT id, content, 1 - (embedding <=> ${queryVector}::vector) as similarity
FROM ekb_schema.ekb_chunk
ORDER BY embedding <=> ${queryVector}::vector
LIMIT 10
`
```
### 6.3 从数据库同步 Schema紧急情况
仅在 Schema 与数据库严重不一致时使用:
```bash
# 1. 备份当前 Schema
cp prisma/schema.prisma prisma/schema.prisma.backup
# 2. 从数据库拉取
npx prisma db pull
# 3. 标记所有现有迁移为已应用
npx prisma migrate resolve --applied <migration_name>
# 4. 验证
npx prisma migrate status
```
---
## 7. 事故恢复流程
## 7. 备份规范
### 7.1 误删数据恢复
### 7.1 备份时机
| 时机 | 是否必须 | 备份方式 |
|------|----------|----------|
| 执行 `prisma migrate deploy` 前 | ✅ 必须 | 全量备份 |
| 重大功能发布前 | ✅ 必须 | 全量备份 |
| 每日自动备份 | ✅ 推荐 | 增量/全量 |
| 数据导入前 | ✅ 必须 | 全量备份 |
### 7.2 备份命令
```bash
# 1. 停止应用
# 2. 从备份恢复
cat backup_xxx.sql | docker exec -i ai-clinical-postgres psql -U postgres -d ai_clinical_research
# 本地 Docker 备份
docker exec ai-clinical-postgres pg_dump \
-U postgres \
-d ai_clinical_research \
--format=plain \
--no-owner \
--no-acl \
> backup_$(date +%Y%m%d_%H%M%S).sql
# 3. 验证数据
npx tsx verify_system.ts
# 4. 重启应用
```
### 7.2 Schema 不一致恢复
```bash
# 1. 检查差异
npx tsx compare_schema_db.ts
# 2. 恢复缺失的对象
npx prisma db execute --file restore_xxx.sql --schema prisma/schema.prisma
# 3. 验证
# RDS 备份(需要开启外网访问)
PGPASSWORD='xxx' pg_dump \
-h pgm-xxx.pg.rds.aliyuncs.com \
-p 5432 \
-U airesearch \
-d ai_clinical_research_test \
--format=plain \
--no-owner \
> rds_backup_$(date +%Y%m%d_%H%M%S).sql
```
---
## 8. 开发环境 vs 生产环境
## 8. 常见问题
### 8.1 开发环境
### 8.1 迁移冲突
- 可以使用 `prisma migrate dev`
- 可以使用 `prisma db push`(谨慎)
- 定期同步生产数据库结构
```bash
# 问题:多人开发时迁移文件冲突
# 解决:
1. git pull 获取最新代码
2. npx prisma migrate status 查看状态
3. 如有冲突,手动合并迁移文件或重新生成
```
### 8.2 生产环境
### 8.2 迁移失败回滚
- **只能**使用 `prisma migrate deploy`
- **禁止**使用任何 `--force``--reset` 参数
- 变更前必须有回滚计划
- 必须有最新备份
```bash
# 问题migrate deploy 失败
# 解决:
1. 从备份恢复数据库
2. 修复 schema.prisma
3. 重新生成迁移
4. 再次尝试部署
```
### 8.3 Schema 与数据库不一致
```bash
# 检查差异
npx prisma migrate diff \
--from-schema-datasource prisma/schema.prisma \
--to-schema-datamodel prisma/schema.prisma
# 如果需要重新同步
npx prisma db pull # 从数据库拉取
# 或
npx prisma migrate dev # 从 Schema 推送
```
---
## 9. 检查清单
### 9.1 数据库变更前检查
### 9.1 每次变更前
- [ ]备份数据库
- [ ]审查 schema.prisma 变更
- [ ]检查是否影响非 Prisma 管理的对象
- [ ]从主分支更新代码
- [ ]运行 `npx prisma migrate status`
- [ ]备份本地数据库(重要数据)
### 9.2 每次变更后
- [ ] 迁移文件已生成
- [ ] 本地功能测试通过
- [ ] 已检查生成的迁移 SQL
- [ ] 已提交 schema.prisma 和迁移文件
### 9.3 生产部署时
- [ ] 已备份生产数据库
- [ ] 已在测试环境验证迁移
- [ ] 已准备回滚方案
- [ ]在开发环境测试
### 9.2 部署后检查
- [ ] 应用正常启动
- [ ] 数据库连接正常
- [ ] pg-boss 队列正常工作
- [ ] 核心功能测试通过
- [ ]执行 `npx prisma migrate deploy`
- [ ] 已验证应用正常运行
---
## 10. 常用脚本
### 10.1 验证脚本位置
```
backend/
├── verify_system.ts # 系统完整性验证
├── compare_schema_db.ts # Schema与数据库对比
├── check_iit_asl_data.ts # 检查模块数据
├── restore_job_common.sql # 恢复 job_common 表
└── restore_pgboss_functions.sql # 恢复 pg-boss 函数
```
### 10.2 快速验证命令
```bash
# 设置环境变量
$env:DATABASE_URL="postgresql://postgres:postgres123@localhost:5432/ai_clinical_research"
# 验证系统
npx tsx verify_system.ts
# 检查数据
npx tsx check_iit_asl_data.ts
```
---
## 附录:事故案例
## 附录:历史事故
### 案例12026-01-11 数据库重置事故
**原因**:使用 `prisma db push --force-reset` 导致非 Prisma 管理的对象丢失
**影响**
- pg-boss 函数丢失,队列无法注册
- job_common 表丢失
- 用户数据丢失(已通过 seed 恢复)
**教训**
1. 永远不要使用 `--force-reset`
2. 操作前必须备份
3. 了解 Prisma 的管理边界
详见:`docs/08-项目管理/2026-01-11-数据库事故总结.md`
**原因**:使用 `prisma db push --force-reset`
**影响**pg-boss 函数丢失,用户数据丢失
**教训**永远不要使用 `--force-reset`,操作前必须备份
### 案例2手工 SQL 导致 Schema 不一致
**原因**:直接执行 `ALTER TABLE` 添加字段
**影响**Prisma Schema 与数据库不一致,后续迁移失败
**教训**:所有变更必须通过 Prisma Schema
---
> 📌 **记住**Prisma Schema 是唯一真相来源Single Source of Truth
> 所有数据库结构变更必须先修改 Schema再通过迁移应用到数据库