基于 3 个并行探索代理的全面扫描结果,更新 wiki 数据至实际状态: - index.md: 18 crate / 76 迁移 / 44 实体 / 77k 行 / 409 提交 - erp-health.md: 44 实体 / 21 handler / 22 权限 / 25 事件 / 6 消费者 - erp-server.md: 9 后台任务 / RLS 中间件栈 - architecture.md: 新增 erp-ai/dialysis 到依赖图 / 测试覆盖表 - testing.md: 225 单元 + 159 集成 / 4 模块零测试警告 - database.md: 76 迁移 / RLS+哈希链+盲索引+Dead Letter - erp-core.md: PiiCrypto 加密体系 / EventBus 完整描述 - frontend.md: 163 文件 / 5 store / 10 API 文件 - CLAUDE.md: 新增 health/ai/dialysis/assessment scope 头脑风暴 4 个议题决策: - dialysis: 接入激活 - 测试: 按风险排序(workflow > ai > message > config) - AI: 数据桥接优先 - 路线图: AI 驱动 3 个月 5 Phase
6.9 KiB
6.9 KiB
title, updated, status, tags
| title | updated | status | tags | ||||
|---|---|---|---|---|---|---|---|
| 数据库迁移与模式 | 2026-04-28 | stable |
|
数据库迁移与模式
从 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) |