Files
hms/docs/superpowers/specs/2026-04-26-platform-retrospective-and-evolution-design.md
iven 1265935fa3 chore: 设计规格文档 + 销售数据 + 脚本工具 + 根目录 monorepo 配置
- docs/: 设计规格、讨论记录、销售数据、健康管理文档
- scripts/: 辅助脚本
- package.json + pnpm-lock.yaml: monorepo 根配置
2026-04-28 00:20:37 +08:00

407 lines
19 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.
# HMS 平台基座回顾与演进设计
> 日期: 2026-04-26 | 状态: Draft | 方法: 三专家多视角评审
---
## 1. 概述
### 1.1 回顾目的
HMS 健康管理平台经过 17 天密集开发2026-04-10 ~ 2026-04-26从 ERP 底座演进到包含 16 个 Rust crate、62 个前端页面、27 个小程序页面的综合医疗 SaaS 平台。本次回顾旨在:
- **验证基座设计** — 星形依赖拓扑、ErpModule trait、事件总线、多租户策略是否经得起实践检验
- **评估演进路径** — 从插件开发模式到原生模块开发的决策是否正确
- **识别缺口与风险** — 通过多专家视角发现盲点
- **制定演进路线** — 基于 P0/P1/P2 优先级指导后续迭代
### 1.2 评审方法
采用三专家独立评审,每个专家从不同视角分析相同的诊断和建议:
| 专家 | 视角 | 关注点 |
|------|------|--------|
| 高级系统架构师 | 架构可持续性 | 模块边界、事件可靠性、技术债 |
| 医疗信息化专家 | 临床安全与合规 | 患者安全、PIPL 合规、领域模型 |
| 产品策略专家 | ROI 与开发节奏 | 优先级、技术债量化、路线图现实性 |
### 1.3 核心结论
**基座设计方向正确,但深度不足。** 星形依赖、trait 抽象、事件总线等基础架构经受住了实践检验。但在临床安全(危急值告警未闭环)、合规(知情同意缺失)、事件可靠性(无重放机制)方面存在需立即修复的缺口。插件系统已验证可行性但对 HMS 核心业务贡献有限,建议有条件冻结。
---
## 2. 基座设计验证
### 2.1 评分总览
| 维度 | 评分 | 说明 |
|------|------|------|
| 模块边界 | ★★★★ | 星形拓扑零循环依赖trait 契约清晰 |
| ErpModule trait | ★★★★ | 生命周期/权限/事件/健康检查统一接口 |
| 事件总线 | ★★★☆ | 基础设施扎实broadcast+outbox但无重放机制消费侧不完整 |
| 多租户 | ★★★☆ | JWT→TenantContext 全链路贯通,但缺 RLS 兜底和集成测试 |
| 权限体系 | ★★★★ | RBAC + 行级数据权限 + 按钮级控制 |
| 插件系统 | ★★★☆ | CRUD 场景验证通过,医疗场景天花板明显 |
| API 一致性 | ★★★★ | 统一 envelope、分页、OpenAPI 自动文档 |
| 数据库迁移 | ★★★★ | 59 个迁移幂等、可回滚、fixup 模式健康 |
| 测试覆盖 | ★☆☆☆ | 36 后端 + 3 前端,覆盖率 < 5% |
| 合规性 | ★☆☆☆ | 知情同意缺失审计不完整PIE 加密范围不足 |
### 2.2 星形依赖拓扑
```
erp-core (L1)
/ | \ \ \ \
erp-auth workflow message config erp-health erp-plugin erp-ai
\ | / / / / /
erp-server (L3, 组装入口)
```
- `erp-core`:零业务依赖,纯净基础层
- 7 个业务 crate各只依赖 `erp-core`,兄弟间无横向依赖
- `erp-server`:唯一组装点,负责路由合并和模块初始化
- **无循环依赖** — 架构师验证通过
### 2.3 ErpModule trait
当前 trait 提供统一的模块接口:
- **身份**`name()` / `id()` / `version()`
- **依赖声明**`dependencies()` — 用于拓扑排序启动顺序
- **生命周期**`on_startup()` / `on_shutdown()` / `health_check()`
- **多租户**`on_tenant_created()` / `on_tenant_deleted()`
- **权限自描述**`permissions()` — 模块声明自己需要的权限码
- **事件订阅**`register_event_handlers()` / `as_any()`
**已知张力**:路由注册不在 trait 中,而是通过各模块的 inherent method (`public_routes()` / `protected_routes()`) 手动在 `main.rs` 中合并。原因是 Axum 的 `Router<S>` 泛型约束不适合 trait object。这是务实的妥协但在添加新模块时有 boilerplate 成本。
### 2.4 事件总线
**实现机制**`tokio::sync::broadcast` (容量 1024) + `domain_events` 表持久化best-effort+ Outbox relay (5秒轮询3次重试)
**发布侧**(已识别的事件类型):
| 模块 | 事件类型数 | 示例 |
|------|-----------|------|
| erp-auth | 10 | `user.login`, `user.created`, `role.created` |
| erp-workflow | 4 | `process_instance.started`, `task.completed` |
| erp-message | 1 | `message.sent` |
| erp-health | 13 | `patient.created`, `health_data.critical_alert`, `follow_up.overdue` |
| erp-plugin | 2+ | `plugin.config.updated`, `plugin.trigger.*` |
**消费侧**(已识别的订阅者):
| 订阅者 | 订阅方式 | 处理的事件 |
|--------|---------|-----------|
| erp-message | `subscribe()` 全量 | `appointment.*`, `process_instance.*`, `task.*` |
| erp-health | `register_handlers_with_state` | `workflow.task.completed` |
| erp-plugin 通知 | `subscribe_filtered("plugin.trigger.*")` | 插件触发通知 |
| outbox relay | 轮询 DB | 重发 pending 事件 |
**已识别缺陷**
1. **无重放机制** — 内存 broadcast服务重启后未消费的事件丢失
2. **无幂等保护**`follow_up.overdue` 每 6 小时检查会重复发布同一条逾期事件
3. **全量订阅** — erp-message 使用 `subscribe()` 而非 `subscribe_filtered()`,所有事件都经过消息模块
### 2.5 多租户
**已实现**
- JWT claims 提取 `tenant_id``TenantContext` 注入请求扩展
- 所有 Entity 含 `tenant_id` 字段BaseFields 统一
- 所有 DomainEvent 携带 `tenant_id`
- `on_tenant_created()` / `on_tenant_deleted()` 钩子auth 和 health 已实现)
- 部门级数据范围(`department_ids` 在 TenantContext 中)
**缺失**
- 无 PostgreSQL RLS policy 作为兜底层
- 无强制 tenant_id 过滤的查询层机制 — 依赖每个 service 手动 `.filter()`
- 当前实际只有 default_tenant微信登录硬编码使用 `default_tenant_id`
- 无多租户管理 API创建/配置/迁移)
---
## 3. 演进路径回顾
### 3.1 时间线
```
4/10-4/16 基座搭建 (Phase 1-6)
→ core → auth → config → workflow → message
→ 全部原生 Rust 模块30+ 数据库表
4/13-4/18 WASM 插件实验
→ 插件系统设计与实现 (Wasmtime + WIT bindgen)
→ CRM (5实体) → Inventory (6实体) → Freelance → ITOps
→ 证明CRUD 密集型领域可行,沙盒隔离有效
→ 跨插件数据引用未解决
4/23-4/26 HMS 分叉 — 健康模块原生开发
→ 18+ 强类型实体 (患者/家属/医生/预约/排班/随访/咨询/体征/化验/透析/诊断/积分...)
→ PII 加密 (AES-256-GCM)、脱敏管道
→ AI 模块 (4 SSE 流式端点 + 3 REST 端点)
→ 微信小程序 (27 页面)
→ 按钮级权限控制
```
### 3.2 从插件到原生的决策链
**原始插件愿景**(设计规格 2026-04-13
- 平台模块原生,行业模块 WASM 插件
- 插件通过 9 个 Host API 函数通信db_insert/query/update/delete、event_publish、config_get 等)
- 数据存 JSONB 动态表,路由自动生成
- UI 配置驱动,通用 PluginCRUDPage 组件
**健康模块原生的 5 个硬限制**(设计规格 2026-04-23 §1.3
| 限制 | 影响 | 不可妥协原因 |
|------|------|-------------|
| 20 实体上限 | 健康平台轻松超过 | 18+ 实体已是最低合理粒度 |
| JSONB 存储 | 无强类型、无外键约束 | 医疗数据需要引用完整性和精确索引 |
| 无自定义 API | 只有自动 CRUD | 趋势分析/统计报表/日历视图无法实现 |
| 无文件上传 | 沙盒阻止文件系统访问 | 化验单/体检报告需要文件存储 |
| WASM 沙盒限制 | 无 native crypto/外部 API/后台任务 | PII 加密、微信集成、定时任务全部需要 |
### 3.3 得失评估
**得 — 正确的决策:**
| 决策 | 收益 |
|------|------|
| 星形依赖拓扑 | 模块独立性强,可独立测试和替换 |
| ErpModule 统一接口 | 新模块注册流程标准化 |
| 事件总线 | 跨模块解耦通信的基础设施已就绪 |
| JWT→TenantContext | 多租户全链路贯通 |
| 健康模块原生 | 不受沙盒限制,加密/文件/后台任务全部可用 |
| 插件实验 | 验证了平台灵活性CRM/库存可正常使用 |
**失 — 需要修正的问题:**
| 决策 | 代价 |
|------|------|
| 插件系统投入过大 | 22,000 行代码41% Rust 总量),对 HMS 核心业务贡献接近零 |
| 积分系统混入 health | 8 实体/12+ 路由,增加合规复杂度和数据泄露面 |
| 事件消费侧忽视 | 13 个事件只有 3 个被消费,危急告警和逾期通知空转 |
| 测试覆盖极薄 | 36 后端 + 3 前端测试,覆盖率 < 5% |
| 合规意识不足 | 知情同意缺失、审计不完整、PIE 加密范围不足 |
---
## 4. 三专家评审摘要
### 4.1 高级系统架构师
**诊断准确度7/10** — 四个张力都真实存在,但优先级和细节有偏差。
关键补充:
| 发现 | 严重程度 |
|------|---------|
| WIT 接口是同步调用阻塞WASM 运行时嵌入主进程(故障隔离不足) | 架构隐患 |
| EventBus 内存 broadcast 无重放机制,服务重启丢事件 | P1 |
| `follow_up.overdue` 无幂等保护,每 6h 检查重复发布 | P0 |
| erp-message 用 `subscribe()` 全量订阅,性能隐患 | P1 |
| RLS 不是 P0多租户集成测试才是 | 观点 |
| 积分系统8 独立实体、12+ 路由)不应在 erp-health 内 | 共识 |
| 缺监控/可观测性、数据备份策略、API 版本升级路线图 | 盲点 |
核心原则:**先补测试再重构,先修事件再上功能,先验证再加固。**
### 4.2 医疗信息化专家
**发现了比原始诊断更深层的临床安全风险。**
| 新发现 | 严重程度 |
|--------|---------|
| 危急值阈值全部硬编码(收缩压 180/80、心率 150/40不可配置 | P0 |
| `daily_monitoring` 表体征数据不经过危急值检测(合并前遗留) | P0 |
| 过敏史更新直接覆盖,无变更历史 | P0 |
| 知情同意完全缺失(搜索 consent/同意/授权/隐私 零结果) | P0 — PIPL 违规 |
| 只有身份证号存储加密,姓名/过敏史/诊断/咨询内容明文 | P1 |
| 审计日志不完整 — 只有预约状态变更记录前后值 | P1 |
| `ip_address``user_agent` 从未被填充 | P1 |
| 读操作(查看患者详情/化验报告)完全没有审计记录 | P1 |
| 诊断记录 `icd_code` 只做字符串约束,无格式校验,无同行审核 | P1 |
合规评估PIPL 第 29 条要求处理敏感个人信息须取得单独同意。医疗数据属于敏感个人信息。知情同意缺失是法律红线。
领域模型建议积分系统6 实体 + 2 线下活动实体)应拆分为独立 `erp-points``erp-engagement` 模块,与健康数据分离以降低合规复杂度。
### 4.3 产品策略专家
**开发节奏不可持续但不必恐慌。**
| 分析 | 结论 |
|------|------|
| 峰值 68 提交/天fix 提交占 21.6% | 短期冲刺可以,长期人会耗竭 |
| 41% Rust 代码在插件系统,对核心业务贡献接近零 | 最大 ROI 失衡 |
| 单人 + AI 的"速度幻觉" | 68 提交/天 = 审查不足,积分混入 health 就是例证 |
| 测试覆盖 < 5% | 正确水位不是 80%,而是关键路径不回退(目标 50-80 用例3-4 天) |
关键风险缓解建议:
- ADR架构决策记录强制化
- 医疗安全代码双人外部 review
- 每日提交上限 15 次
- 每月需求裁剪
V2 血透路线图评估:技术储备已够(`dialysis_service` 286 行骨架在),但缺市场验证。建议先做 3-5 家目标客户调研,确认需求后再做 2 周 MVP 试运行。
---
## 5. 共识优先级
### 5.1 三专家加权共识矩阵
| 议题 | 架构师 | 医疗专家 | 产品策略 | 共识等级 |
|------|--------|---------|---------|---------|
| 危急值告警闭环 | P0 | P0 + 硬编码 | P0 | 三方一致 |
| 知情同意 (PIPL) | 未涉及 | P0 | P0 | 两方一致 |
| 审计日志补全 | 未涉及 | P1 | P0 | P0-P1 |
| EventBus 可靠性 | P1 | 未涉及 | P0 | P0-P1 |
| 随访逾期通知 | P0 | P0 | P0 | 三方一致 |
| 积分系统拆分 | 应拆 | 应拆(合规) | 占 19.5% | 三方一致 |
| RLS | 不是 P0 | P1 | P0 | 有分歧 |
| 插件系统 | 有条件冻结 | 未涉及 | 冻结 | 两方一致 |
| 测试覆盖 | 先补测试 | 上线前必修 | 50-80 用例 | 三方一致 |
| V2 血透 | 未涉及 | 缺标准流程 | 先调研 | 两方一致 |
### 5.2 P0 — 上线前必修(估计 2-3 周)
| 序号 | 项 | 工作量 | 负责 crate | 说明 |
|------|---|--------|-----------|------|
| 1 | 危急值告警消费者 | 1 天 | erp-health + erp-message | `health_data.critical_alert` → 推送通知给责任医护 |
| 2 | 危急值阈值可配置化 | 2 天 | erp-health | 硬编码阈值改为数据库配置,支持科室/年龄差异化 |
| 3 | daily_monitoring 合并后告警验证 | 1 天 | erp-health | 确认合并到 vital_signs 后所有体征数据都经过告警检测 |
| 4 | 随访逾期通知 | 1 天 | erp-health + erp-message | `follow_up.overdue` → 催办通知 + 幂等保护 |
| 5 | 知情同意记录 | 3 天 | erp-health | 患者数据处理同意获取和记录机制 |
| 6 | 审计日志补全 | 3 天 | erp-core + erp-health | 临床数据变更记录前后值、读操作审计、IP/UA 填充 |
| 7 | EventBus 持久化增强 | 2 天 | erp-core | 服务重启不丢事件 + overdue 事件幂等 |
### 5.3 P1 — 治理2-4 周)
| 序号 | 项 | 工作量 | 说明 |
|------|---|--------|------|
| 8 | 积分系统剥离 | 5 天 | 从 erp-health 拆分为独立 erp-engagement crate |
| 9 | 关键路径测试 | 4 天 | 多租户隔离、患者安全路径、预约并发50-80 用例) |
| 10 | 插件系统冻结声明 | 0.5 天 | 保留代码README 声明实验性,不再投入 |
| 11 | erp-message 改用 `subscribe_filtered` | 1 天 | 减少无效事件传递 |
| 12 | 统一事件消费模式 | 2 天 | 消除 `register_event_handlers` vs `on_startup` 双路径 |
| 13 | 过敏史变更历史 | 1 天 | 更新时记录旧值 |
### 5.4 P2 — 扩展(后续迭代)
| 序号 | 项 | 前置条件 |
|------|---|---------|
| 14 | PostgreSQL RLS | P1 测试覆盖完成 |
| 15 | 血透专科 | 3-5 家客户调研完成 |
| 16 | OCR 化验单提取 | 血透验证后 |
| 17 | IM 咨询 | 血透验证后 |
| 18 | health 模块按子域重组目录 | P1 测试覆盖完成 |
| 19 | 前端测试覆盖提升 | P1 后端测试完成 |
| 20 | 动态菜单系统 | 现有计划可用 |
---
## 6. 风险与缓解
### 6.1 开发模式风险
| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| 单人认知单点 | 一人理解 16 个 cratebus factor = 1 | ADR 强制化,关键决策留文档 |
| AI 生成"编译对但逻辑错" | 危急值阈值硬编码、积分混入 health 就是例证 | 医疗安全代码双人外部 review |
| 速度幻觉 | 68 提交/天 = 审查不足 | 每日提交上限 15 次 |
| AI 回音壁 | AI 不质疑需求合理性 | 每月需求裁剪,引入真实用户反馈 |
### 6.2 临床安全风险
| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| 危急值告警未闭环 | 危急体征值无人响应,可致患者安全事故 | P0-1实现消费者 + 阈值可配置 |
| 逾期随访无催办 | 患者失访,影响医疗质量指标 | P0-4实现通知 + 幂等保护 |
| 过敏史无变更记录 | 无法追溯过敏史变更,用药风险 | P1-13添加变更历史 |
| 告警阈值硬编码 | 无法适应儿科/老年科/血透科不同范围 | P0-2数据库配置 |
### 6.3 合规风险
| 风险 | 法规依据 | 缓解措施 |
|------|---------|---------|
| 知情同意缺失 | PIPL 第 29 条 | P0-5实现同意记录机制 |
| 审计不完整 | 医疗机构信息化建设要求 | P0-6补全审计日志 |
| PIE 加密范围不足 | PIPL 第 51 条 | P1扩展加密到姓名/过敏史/诊断 |
| 数据删除权缺失 | PIPL 第 47 条 | P2实现患者数据导出/删除 |
### 6.4 架构风险
| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| EventBus 无重放 | 服务重启丢事件 | P0-7增强持久化 |
| 全量订阅 | 性能隐患,所有事件经消息模块 | P1-11改用过滤订阅 |
| 路由手动合并 | 新模块 boilerplate 成本 | 长期ErpModule trait v2 |
| erp-health 过大 | 18+ 实体,维护复杂度上升 | P2-18按子域重组 |
---
## 7. 附录
### 7.1 关键文件索引
| 文件 | 说明 |
|------|------|
| `crates/erp-core/src/module.rs` | ErpModule trait + ModuleRegistry (拓扑排序) |
| `crates/erp-core/src/events.rs` | EventBus 实现 (broadcast + outbox) |
| `crates/erp-core/src/types.rs` | TenantContext, BaseFields, Pagination |
| `crates/erp-core/src/rbac.rs` | 权限/角色检查 |
| `crates/erp-server/src/main.rs` | 服务组装和手动路由合并 |
| `crates/erp-server/src/state.rs` | AppState + FromRef 桥接 |
| `crates/erp-server/src/outbox.rs` | Outbox relay (5s 轮询, 3 次重试) |
| `crates/erp-auth/src/middleware/jwt_auth.rs` | JWT 认证 + TenantContext 注入 |
| `crates/erp-health/src/module.rs` | HealthModule (ErpModule 实现 + 后台任务) |
| `crates/erp-health/src/event.rs` | 健康模块事件订阅 |
| `crates/erp-health/src/crypto.rs` | AES-256-GCM 加密 |
| `crates/erp-health/src/service/masking.rs` | PII 脱敏管道 |
| `crates/erp-plugin/src/engine.rs` | WASM 插件引擎 |
| `docs/superpowers/specs/2026-04-13-wasm-plugin-system-design.md` | 插件系统设计规格 |
| `docs/superpowers/specs/2026-04-23-health-management-module-design.md` | 健康模块设计规格 |
| `docs/discussions/2026-04-18-plugin-platform-brainstorm.md` | 插件平台演进讨论 |
### 7.2 迁移历史时间线
| 日期 | 迁移范围 | 说明 |
|------|---------|------|
| 4/10-11 | 核心平台 | 租户、用户、凭证、角色、权限、组织、部门、岗位 |
| 4/12 | 配置 + 工作流 | 字典、菜单、设置、编号规则 + 流程定义/实例/令牌/任务 |
| 4/13 | 消息 + 审计 | 模板、消息、订阅 + 审计日志 |
| 4/14 | 修复 | 唯一索引与软删除冲突、标准字段补全 |
| 4/16 | 领域事件 | domain_events 表 |
| 4/17 | 插件系统 | 插件表、动态表 |
| 4/18 | 搜索 + 权限 | pg_trgm、实体注册表、数据范围 |
| 4/19 | 关联修复 | 用户部门、CRM 修复、插件市场 |
| 4/23 | 健康表 | 患者、微信用户、文章 |
| 4/24 | 索引修复 | 3 个 fixup 迁移 |
| 4/25 | 健康扩展 | 患者ID哈希、医生名、透析/化验增强、AI 表、积分 |
| 4/26 | 业务改进 | 诊断、列重命名、daily_monitoring 合并、菜单种子 |
**总计59 个迁移17 天内。** fixup 迁移模式健康(不编辑旧迁移,单独修复)。
### 7.3 项目统计快照 (2026-04-26)
| 指标 | 值 |
|------|-----|
| Rust crate 数 | 16 |
| Rust 代码行 | ~57,000 |
| 前端文件数 | 174 (TSX/TS) |
| 前端页面 | 62 |
| 小程序页面 | 27 |
| 数据库迁移 | 59 |
| 数据库表 | 30 基础 + 18 健康 + 3 AI |
| 后端测试 | 36 |
| 前端单元测试 | 3 |
| Git 提交 | 237 |
| 开发周期 | 17 天 |
---
*本文档由三专家多视角评审生成,作为 HMS 平台基座演进的参考基准。后续实施计划将基于本文档的优先级排序展开。*