--- title: 数据库迁移与模式 updated: 2026-04-28 status: stable tags: [database, seaorm, migration, multi-tenant] --- # 数据库迁移与模式 > 从 [[index]] 导航。关联: [[erp-core]] [[erp-server]] [[infrastructure]] [[erp-health]] ## 1. 设计决策 - **SeaORM Migration** — 异步、类型安全、幂等(`if_not_exists`),每个迁移必须实现 `down()` 可回滚 - **所有表必须含标准字段** — `id`(UUIDv7), `tenant_id`, `created_at`, `updated_at`, `created_by`, `updated_by`, `deleted_at`, `version` - **软删除** — 不硬删除,设置 `deleted_at` 时间戳 - **乐观锁** — 更新时检查 `version` 字段 - **多租户** — 所有业务表含 `tenant_id`,中间件自动过滤 ## 2. 关键文件 + 数据流 ### 核心文件 | 文件 | 职责 | |------|------| | `crates/erp-server/migration/src/lib.rs` | Migrator 注册所有迁移 | | `crates/erp-server/migration/src/m*.rs` | 76 个迁移文件 | | `crates/erp-core/src/types.rs` | BaseFields 标准字段定义 | ### 迁移命名规则 ``` m{YYYYMMDD}_{6位序号}_{描述}.rs 例: m20260410_000001_create_tenant.rs ``` ### 当前表概览(67+ 张) | 模块 | 表 | |------|-----| | 基础 | tenant, tenant_crypto_keys | | 认证 (auth) | users, user_credentials, user_tokens, roles, permissions, role_permissions, user_roles, organizations, departments, positions, user_departments | | 配置 (config) | dictionaries, dictionary_items, menus, menu_roles, settings, numbering_rules | | 工作流 (workflow) | process_definitions, process_instances, tokens, tasks, process_variables | | 消息 (message) | message_templates, messages, message_subscriptions | | 审计 | audit_logs, domain_events | | 插件 (plugin) | plugins, entity_registry, plugin_market, plugin_user_views | | **健康 (health)** | patient, patient_family_member, patient_tag, patient_tag_relation, patient_doctor_relation, doctor_profile, health_record, vital_signs, daily_monitoring, lab_report, health_trend, diagnosis, dialysis_record, critical_value_thresholds, consent, appointment, doctor_schedule, follow_up_task, follow_up_record, consultation_session, consultation_message | | **内容 (article)** | article, article_category, article_tag, article_article_tag, article_revision | | **积分 (points)** | points_account, points_rule, points_product, points_order, points_transaction, points_checkin | | **线下活动** | offline_event, offline_event_registration | | **AI (ai)** | ai_prompt, ai_analysis, ai_usage | | **微信 (wechat)** | wechat_users | ### 健康模块迁移(m000042 - m000072) | 迁移 | 变更 | |------|------| | m000042 | 创建 17 张健康业务表 | | m000043 | 创建 wechat_users 表 | | m000044 | 创建 article 表 | | m000045 | 健康模块索引优化 | | m000046 | 健康模块约束修复 | | m000047 | 健康模块索引修复 | | m000048 | 添加 patient.id_number_hash 列 | | m000049 | 拓宽 patient.id_number 列 | | m000050 | 添加 appointment.doctor_name 列 | | m000051 | 透析/化验增强字段 | | m000052 | 创建 AI 分析表(ai_prompt/ai_analysis/ai_usage) | | m000053 | 创建积分商城表(points_account/rule/product/order/transaction) | | m000054 | 创建日常监测表(daily_monitoring) | | m000055 | 积分签到标准字段 | | m000056 | 创建诊断表(diagnosis) | | m000057 | 重命名 points_transaction 类型列 | | m000058 | 合并 daily_monitoring 到 vital_signs | | m000059 | 种子菜单数据 | | m000060 | 创建危急值阈值表 | | m000061 | 创建知情同意表 | | m000062 | 创建租户加密密钥表(tenant_crypto_keys) | | m000063 | 内容管理表(article_category/article_tag/article_article_tag/article_revision) | | m000064-000068 | PII 加密扩展(patient/consultation/follow_up/family_member/doctor_profile) | | m000069-000071 | 加密字段 key_version(dialysis_record/lab_report/diagnosis) | | m000072 | 拓宽加密手机号列 | | m000073-000075 | 设备数据采集(device_readings) | | m000076 | 告警系统(alerts, alert_rules) | | m000077 | 危急值告警(critical_alert, critical_alert_response) | | m000078-000079 | 随访模板(follow_up_template, follow_up_template_field) | | m000080 | 用药记录(medication_record) | | m000081 | 透析处方增强 | | m000082 | AI 用量统计表增强 | | m000083-000085 | 索引和约束优化 | | m000086 | 启用 RLS 所有表 | | m000087 | 审计日志哈希链 | | m000088 | RLS 严格策略(FORCE) | | m000089 | 盲索引(blind_index 表) | | m000090 | 告警阈值表增强 | | m000091 | Dead Letter 事件表 | ### 集成契约 | 方向 | 模块 | 触发时机 | |------|------|---------| | 消费 ← | [[erp-server]] | 启动时自动运行 `Migrator::up()` | | 依赖 ← | [[erp-core]] | BaseFields 定义标准字段规范 | | 提供 → | 所有业务模块 | 表结构供 SeaORM Entity 使用 | | 提供 → | [[erp-health]] | 44 张健康业务表 | ## 3. 代码逻辑 ⚡ **不变量**: 所有业务表必须含 `tenant_id` 列 — 多租户是核心能力,不可事后补 ⚡ **不变量**: 迁移必须幂等 — 使用 `if_not_exists`,可重复执行 ⚡ **不变量**: 迁移执行由 erp-server 启动自动触发,不手动执行 SQL ⚡ **不变量**: 健康模块 PII 数据使用 AES-256-GCM 加密存储,身份证号额外 HMAC-SHA256 哈希 ### 关键结构变更迁移 | 迁移 | 变更 | |------|------| | m000027 | 修复唯一索引 + 软删除冲突 | | m000034 | 种子插件权限 | | m000035 | pg_trgm 扩展 + entity 列 | | m000036 | role_permissions 添加 data_scope(行级数据权限) | | m000038 | 修复 CRM 权限码 | | m000039 | entity_registry 列 | | m000041 | plugin_user_views | | m000042 | 17 张健康业务表 | | m000048 | patient.id_number_hash HMAC 列 | ## 4. 活跃问题 + 陷阱 ### 历史教训 - 唯一索引 + 软删除冲突 — 已删除记录的 unique key 阻止新建(m000027 修复) - tenant 表缺少 `created_by`/`updated_by`/`version` 字段 — 首个迁移早于 BaseFields 规范 - wechat_users 表初始缺少标准字段列 — 需 ALTER TABLE 补充(m000043 已包含完整字段) ⚠️ settings 表的唯一索引曾需修复(m000032) ⚠️ 新增表时务必对齐 `crates/erp-core/src/types.rs` 中的 BaseFields ⚠️ 已应用的迁移文件被删除会导致启动失败 — 需创建空 stub 迁移(m000050 案例) ## 5. 变更记录 | 日期 | 变更 | |------|------| | 2026-04-28 | 更新至 76 迁移,新增设备采集/告警/RLS/审计哈希链/盲索引/Dead Letter/透析处方等 19 个迁移 | | 2026-04-26 | 更新至 72 迁移、67+ 表,新增积分商城/透析/诊断/内容管理/线下活动/PII 加密扩展等 22 个迁移 | | 2026-04-25 | 更新至 50 迁移、48 表,新增健康模块迁移(m000042-m000050)和 18 张健康业务表 | | 2026-04-23 | 重构为 5 节结构,更新表清单至 41 个迁移 | | 2026-04-19 | CRM 权限码修复迁移 (m000038) |