# 数据库开发规范 > 版本: v3.0 > 更新日期: 2026-02-27 > v3.0 更新: 新增部署变更实时记录规则、Shadow DB 降级方案、0227 事故教训 --- ## 📢 核心原则 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ 🎯 三条铁律 │ │ │ │ 1. ✅ 所有数据库变更必须通过 Prisma migrate 管理 │ │ 2. ✅ 变更同时必须记录到「待部署变更清单」 │ │ 3. ❌ 绝对禁止 prisma db push(除非你愿意花一天修 drift) │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 变更记录规则(v3.0 新增) **每次修改 schema.prisma 并生成迁移后,立即做两件事**: 1. 提交迁移文件到 Git 2. 在 `docs/05-部署文档/03-待部署变更清单.md` 追加一行记录 ```markdown | DB-N | 简述变更 | `迁移文件名` | 高/中/低 | 备注 | ``` > Cursor Rule `.cursor/rules/deployment-change-tracking.mdc` 会在你修改 schema.prisma 时自动提醒。 --- ## 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` | 🟠 **高** | 不生成迁移文件,无法追踪变更历史 | | `prisma db push --force-reset` | 🔴 **极高** | 会删除所有数据 | | `prisma migrate reset` | 🔴 **极高** | 重置整个数据库 | | 手工执行 `ALTER TABLE` | 🟠 **高** | 导致 Schema 与数据库不一致 | | 手工执行 `CREATE TABLE` | 🟠 **高** | 导致 Schema 与数据库不一致 | --- ## 2. Schema 变更示例 ### 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 # 2. 生成迁移 npx prisma migrate dev --name add_new_feature_table # 3. 检查生成的 SQL cat prisma/migrations/xxx_add_new_feature_table/migration.sql ``` ### 2.2 新增字段 ```prisma // 1. 在模型中添加字段 model User { id String @id email String phone String? // 新增字段,可为空 createdAt DateTime @default(now()) @@schema("platform_schema") } ``` ```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. 迁移文件管理 ### 3.1 迁移文件结构 ``` prisma/ ├── schema.prisma # Schema 定义文件 ├── migrations/ │ ├── 20251010075003_init/ │ │ └── migration.sql # 初始化迁移 │ ├── 20251012124747_add_batch/ │ │ └── migration.sql # 功能迁移 │ └── migration_lock.toml # 迁移锁文件 └── manual_sql_scripts/ # 手动 SQL(仅用于特殊场景) └── *.sql ``` ### 3.2 迁移文件命名规范 ```bash # 格式:动词_对象_描述 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 ``` ### 3.3 迁移文件版本控制 ``` ✅ 必须提交的文件: - prisma/schema.prisma - prisma/migrations/*/migration.sql - prisma/migrations/migration_lock.toml ❌ 不要提交的文件: - 本地测试的临时迁移 ``` --- ## 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 # 方案2:手动回滚迁移(需要准备回滚 SQL) # 在 migrations/ 目录下准备 rollback_xxx.sql ``` --- ## 5. 多 Schema 架构规范 ### 5.1 当前 Schema 列表 > 完整的表级清单见 `docs/01-平台基础层/07-数据库/00-数据库架构总览.md` | Schema | 用途 | 表数量 | 管理方式 | |--------|------|--------|----------| | `platform_schema` | 平台基础设施(用户、租户、pg-boss) | 19 | Prisma + pg-boss | | `iit_schema` | IIT 临床试验管理 Agent | 20 | Prisma | | `asl_schema` | AI 智能文献 | 11 | Prisma | | `ssa_schema` | 智能统计分析 | 11 | Prisma | | `dc_schema` | 数据清洗 | 6 | Prisma | | `agent_schema` | 通用 Agent 框架 | 6 | Prisma | | `pkb_schema` | 个人知识库 | 5 | Prisma | | `capability_schema` | Prompt 管理 + 系统知识库 | 4 | Prisma | | `aia_schema` | AI 智能问答 | 3 | Prisma | | `ekb_schema` | 企业知识库(向量) | 3 | Prisma | | `admin_schema` | 运营管理 | 2 | Prisma | | `protocol_schema` | 方案 Agent | 2 | Prisma | | `rvw_schema` | 稿件审查 | 1 | Prisma | | `public` | 遗留 + Prisma 迁移表 | 3 | Prisma | ### 5.2 新增 Schema 规范 ```prisma // 1. 在 datasource 中声明 datasource db { provider = "postgresql" url = env("DATABASE_URL") schemas = [ "platform_schema", "aia_schema", // ... 现有 schemas "new_module_schema" // 新增 ] } // 2. 在模型中使用 model NewModuleTable { id String @id @default(uuid()) name String @@map("new_module_tables") @@schema("new_module_schema") } ``` ### 5.3 命名规范 | 类型 | 格式 | 示例 | |------|------|------| | 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` | --- ## 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 # 4. 验证 npx prisma migrate status ``` --- ## 7. 备份规范 ### 7.1 备份时机 | 时机 | 是否必须 | 备份方式 | |------|----------|----------| | 执行 `prisma migrate deploy` 前 | ✅ 必须 | 全量备份 | | 重大功能发布前 | ✅ 必须 | 全量备份 | | 每日自动备份 | ✅ 推荐 | 增量/全量 | | 数据导入前 | ✅ 必须 | 全量备份 | ### 7.2 备份命令 ```bash # 本地 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 # 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. 常见问题 ### 8.1 迁移冲突 ```bash # 问题:多人开发时迁移文件冲突 # 解决: 1. git pull 获取最新代码 2. npx prisma migrate status 查看状态 3. 如有冲突,手动合并迁移文件或重新生成 ``` ### 8.2 迁移失败回滚 ```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 每次变更前 - [ ] 已从主分支更新代码 - [ ] 已运行 `npx prisma migrate status` - [ ] 已备份本地数据库(重要数据) ### 9.2 每次变更后 - [ ] 迁移文件已生成 - [ ] 本地功能测试通过 - [ ] 已检查生成的迁移 SQL - [ ] 已提交 schema.prisma 和迁移文件 ### 9.3 生产部署时 - [ ] 已备份生产数据库 - [ ] 已在测试环境验证迁移 - [ ] 已准备回滚方案 - [ ] 已执行 `npx prisma migrate deploy` - [ ] 已验证应用正常运行 --- ## 10. Shadow DB 失败时的降级方案(v3.0 新增) 当 `prisma migrate dev` 因 Shadow DB 重放失败时(例如引用了 `db push` 创建的表),使用以下降级流程: ```bash # 1. 手动创建迁移目录 mkdir prisma/migrations/YYYYMMDD_migration_name # 2. 编写迁移 SQL(参考 prisma migrate diff 的输出) npx prisma migrate diff \ --from-url "$DATABASE_URL" \ --to-schema-datamodel prisma/schema.prisma \ --script > prisma/migrations/YYYYMMDD_migration_name/migration.sql # 3. 审查 SQL,确认无破坏性操作 # 4. 手动执行 SQL 到数据库 # 5. 标记为已应用 npx prisma migrate resolve --applied YYYYMMDD_migration_name ``` > 详见 `docs/01-平台基础层/07-数据库/03-技术债务追踪.md` TD-001 --- ## 附录:历史事故 ### 案例1:2026-01-11 数据库重置事故 **原因**:使用 `prisma db push --force-reset` **影响**:pg-boss 函数丢失,用户数据丢失 **教训**:永远不要使用 `--force-reset`,操作前必须备份 ### 案例2:手工 SQL 导致 Schema 不一致 **原因**:直接执行 `ALTER TABLE` 添加字段 **影响**:Prisma Schema 与数据库不一致,后续迁移失败 **教训**:所有变更必须通过 Prisma Schema ### 案例3:2026-02-27 prisma db push 引发的部署 drift(v3.0 新增) **原因**:开发过程中大量使用 `prisma db push` 快速迭代,绕过了迁移系统 **影响**: - 部署到测试环境时发现 6 张表 + 10 个列不在任何迁移文件中 - 部署后运行时报错 `column does not exist`(ssa_sessions.data_profile, review_tasks.context_data) - 需要紧急编写 drift patch 迁移 + 线上热修 SQL - Shadow DB 重放失败,`prisma migrate dev` 不可用 **修复耗时**:约 3 小时(drift 分析 + patch 编写 + 线上热修 + Schema 类型对齐) **教训**: 1. `prisma db push` 是"技术债 ATM"——每用一次就欠一笔 2. 即使是快速原型,也应使用 `prisma migrate dev --create-only` 生成迁移后再审查执行 3. 变更后必须立即记录到 `03-待部署变更清单.md` --- ## 附录:相关文档索引 | 文档 | 位置 | |------|------| | 数据库架构全景(96 张表) | `docs/01-平台基础层/07-数据库/00-数据库架构总览.md` | | 迁移历史(14 个迁移) | `docs/01-平台基础层/07-数据库/01-Prisma迁移历史与变更日志.md` | | 环境差异对照 | `docs/01-平台基础层/07-数据库/02-环境状态对照表.md` | | 技术债务追踪 | `docs/01-平台基础层/07-数据库/03-技术债务追踪.md` | | 种子数据管理 | `docs/01-平台基础层/07-数据库/04-种子数据管理.md` | | 待部署变更清单 | `docs/05-部署文档/03-待部署变更清单.md` | --- > 📌 **记住**:Prisma Schema 是唯一真相来源(Single Source of Truth) > 所有数据库结构变更必须先修改 Schema,再通过迁移应用到数据库 > **v3.0 补充**:变更后必须同步更新「待部署变更清单」,否则部署时一定会遗漏