docs: T40 UI 审计报告 + wiki 更新 + Docker 配置
- T40 UI 审计计划和结果文档(docs/qa/) - wiki 更新:miniprogram 设计系统合规审计记录 + index 关键数字更新 - 审计 V2 完整报告(docs/audits/v2/) - 讨论记录文档(docs/discussions/) - 设计规格和实施计划(docs/superpowers/) - 角色测试计划和结果(docs/qa/role-test-*) - Docker 生产部署配置
This commit is contained in:
269
docs/audits/e2e-consistency-report.md
Normal file
269
docs/audits/e2e-consistency-report.md
Normal file
@@ -0,0 +1,269 @@
|
||||
# HMS 三端一致性检查报告
|
||||
|
||||
> 日期: 2026-05-08 | 审查范围: 后端 API / Web 前端 / 微信小程序
|
||||
|
||||
## 一、审查概要
|
||||
|
||||
| 维度 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 功能设计一致性 | ⚠️ 基本一致 | 三端定位不同(管理端/患者端/医护端),功能差异多为设计意图 |
|
||||
| 数据接口一致性 | ✅ 高度一致 | 小程序 91 个端点 / Web 270+ 端点,路径/参数/响应格式统一 |
|
||||
| 业务流程链路一致性 | ⚠️ 存在差异 | 透析管理、积分商城、AI 分析存在端间覆盖不完整 |
|
||||
|
||||
**总体评分**: **一致性 82%** — 不一致项多为设计意图(端定位不同),少量为遗漏需修复。
|
||||
|
||||
---
|
||||
|
||||
## 二、三端功能覆盖矩阵
|
||||
|
||||
### 2.1 完整覆盖(三端一致)✅
|
||||
|
||||
| 业务模块 | 后端 | Web | 小程序 | 说明 |
|
||||
|----------|------|-----|--------|------|
|
||||
| 患者管理 CRUD | ✅ | ✅ | ✅(患者端) | Web 管理端 + MP 患者端 |
|
||||
| 预约管理 | ✅ | ✅ | ✅ | 完整覆盖 |
|
||||
| 咨询管理 | ✅ | ✅ | ✅ | 含医生端会话处理 |
|
||||
| 随访管理 | ✅ | ✅ | ✅ | Web 管理 + MP 医生端 + 患者端 |
|
||||
| 化验报告 | ✅ | ✅ | ✅ | 含医生端审阅 |
|
||||
| 告警管理 | ✅ | ✅ | ✅ | 确认/忽略/解除三端一致 |
|
||||
| 健康记录 | ✅ | ✅ | ✅ | CRUD 完整 |
|
||||
| 知情同意 | ✅ | ✅ | ✅ | 授权/撤回 |
|
||||
| 诊断记录 | ✅ | ✅ | ✅ | CRUD 完整 |
|
||||
| 消息通知 | ✅ | ✅ | ✅ | 列表/已读/未读(MP 不支持 SSE) |
|
||||
| 日常监测 | ✅ | ✅ | ✅ | 创建/查看 |
|
||||
| 设备读数 | ✅ | ✅ | ✅ | BLE 上传 + 查询 |
|
||||
|
||||
### 2.2 部分覆盖(存在差异)⚠️
|
||||
|
||||
| 业务模块 | 后端 | Web | 小程序 | 差异说明 |
|
||||
|----------|------|-----|--------|----------|
|
||||
| 透析管理 | ✅ 46 端点 | ⚠️ 冻结 | ✅ 完整 | **Web 端路由标记 frozen**,小程序医生端完整可用 |
|
||||
| 透析处方 | ✅ | ❌ | ✅ | **Web 端无处方管理页面**,小程序医生端有 |
|
||||
| 积分商城(患者) | ✅ | ❌ | ✅ | 签到/兑换/商品浏览仅小程序 |
|
||||
| 积分商城(管理) | ✅ | ✅ | ❌ | 规则/商品/订单管理仅 Web |
|
||||
| AI 分析(SSE) | ✅ | ✅ | ❌ | 小程序不支持 SSE 流式,仅查看历史 |
|
||||
| AI 建议审批 | ✅ | ✅ | ❌ | 仅 Web 端可审批 |
|
||||
| 文章审核流程 | ✅ | ✅ | ❌ | submit/approve/reject 仅 Web |
|
||||
| 班次管理 | ✅ | ✅ | ❌ | 管理功能仅 Web |
|
||||
| 护理计划 | ✅ | ⚠️ 冻结 | ❌ | Web 冻结,小程序无 |
|
||||
| 排班管理 | ✅ | ✅ | ❌ | 创建/管理仅 Web,小程序仅查看 |
|
||||
| 设备管理 | ✅ | ✅ | ❌ | 解绑/管理仅 Web,小程序仅 BLE 同步 |
|
||||
| BLE 网关管理 | ✅ | ✅ | ❌ | 注册/绑定/管理仅 Web |
|
||||
| 危急值阈值 | ✅ | ✅ | ⚠️ | Web 可管理,MP 仅查看 public 端点 |
|
||||
| OAuth 客户端 | ✅ | ✅ | ❌ | FHIR 合作方管理仅 Web |
|
||||
| 用药提醒 | ✅ | ❌ | ✅ | **Web 端无用药提醒页面**,小程序有 CRUD |
|
||||
|
||||
### 2.3 单端独有(设计意图,非遗漏)
|
||||
|
||||
| 独有功能 | 端 | 说明 |
|
||||
|----------|-----|------|
|
||||
| 用户/角色/权限管理 | Web | 管理后台职责 |
|
||||
| 组织/部门/岗位 | Web | 管理后台职责 |
|
||||
| 工作流引擎 | Web | 管理后台职责 |
|
||||
| 插件系统 | Web | 管理后台职责 |
|
||||
| 系统设置/字典/编号规则 | Web | 管理后台职责 |
|
||||
| 微信登录+手机号绑定 | MP | 小程序专属 |
|
||||
| 每日签到 | MP | 小程序用户粘性功能 |
|
||||
| 线下活动报名 | MP | 患者端功能 |
|
||||
| 法律文件(用户协议/隐私) | MP | 小程序合规要求 |
|
||||
| BLE 设备蓝牙连接 | MP | 小程序蓝牙能力 |
|
||||
| 埋点数据上报 | MP | 小程序分析功能 |
|
||||
| FHIR R4 接口 | 后端 | 标准互操作,无前端页面 |
|
||||
|
||||
---
|
||||
|
||||
## 三、API 接口一致性分析
|
||||
|
||||
### 3.1 请求格式一致性 ✅
|
||||
|
||||
| 维度 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| URL 路径前缀 | ✅ 一致 | 三端统一 `/api/v1/` |
|
||||
| 分页参数 | ✅ 一致 | `page`, `page_size`, 响应 `PaginatedResponse<T>` |
|
||||
| 乐观锁参数 | ✅ 一致 | 更新/删除均带 `version` 字段 |
|
||||
| 认证方式 | ✅ 一致 | Bearer JWT Token |
|
||||
| 多租户 | ✅ 一致 | 中间件自动注入 `tenant_id` |
|
||||
|
||||
### 3.2 接口覆盖统计
|
||||
|
||||
| 指标 | 后端 | Web 前端 | 小程序 |
|
||||
|------|------|----------|--------|
|
||||
| API 端点总数 | ~300+ | ~270 | ~91 |
|
||||
| Health 端点 | ~200 | ~140 | ~70 |
|
||||
| AI 端点 | ~18 | ~18 | ~3 |
|
||||
| Auth 端点 | ~8 | ~4 | ~4 |
|
||||
| Config/基础端点 | ~74 | ~108 | ~4 |
|
||||
| 消息端点 | ~7 | ~9 | ~4 |
|
||||
|
||||
### 3.3 发现的接口不一致
|
||||
|
||||
| # | 不一致项 | 后端 | Web | 小程序 | 严重度 |
|
||||
|---|----------|------|-----|--------|--------|
|
||||
| 1 | **透析处方 CRUD** | ✅ 完整端点 | ❌ 无 API 调用 | ✅ 完整调用 | **HIGH** |
|
||||
| 2 | **用药提醒 CRUD** | ✅ 完整端点 | ❌ 无 API 调用 | ✅ 完整调用 | **MEDIUM** |
|
||||
| 3 | **小程序趋势查询** `GET /health/vital-signs/trend` | ✅ 专属端点 | ❌ 使用患者级趋势 | ✅ 专属调用 | LOW(设计意图) |
|
||||
| 4 | **小程序今日体征** `GET /health/vital-signs/today` | ✅ 专属端点 | ❌ 不需要 | ✅ 专属调用 | LOW(设计意图) |
|
||||
| 5 | **公开阈值** `GET /health/critical-value-thresholds/public` | ✅ 专属端点 | ❌ 使用管理端点 | ✅ 专属调用 | LOW(设计意图) |
|
||||
| 6 | **小程序未调用透析审阅** `PUT /health/dialysis-records/:id/review` | ✅ | ❌ 冻结 | ✅ 医生端调用 | LOW |
|
||||
| 7 | **AI SSE 端点** | ✅ 4 个 SSE | ✅ 调用 | ❌ 不支持 SSE | LOW(平台限制) |
|
||||
|
||||
---
|
||||
|
||||
## 四、业务流程链路一致性
|
||||
|
||||
### 4.1 用户认证流程
|
||||
|
||||
| 步骤 | Web | 小程序 | 一致性 |
|
||||
|------|-----|--------|--------|
|
||||
| 登录方式 | 账号密码 `POST /auth/login` | 微信授权 `POST /auth/wechat/login` | ⚠️ 设计意图不同 |
|
||||
| Token 管理 | 自动刷新(过期前 30s) | 自动刷新(401 触发) | ✅ 机制一致 |
|
||||
| 登出 | `POST /auth/logout` | 清除本地 token | ✅ |
|
||||
| 手机号绑定 | N/A | `POST /auth/wechat/bind-phone` | ⚠️ MP 独有 |
|
||||
|
||||
**结论**: 认证流程符合各端定位,设计合理。
|
||||
|
||||
### 4.2 预约流程
|
||||
|
||||
| 步骤 | Web | 小程序 | 一致性 |
|
||||
|------|-----|--------|--------|
|
||||
| 选择医生 | ✅ 医生列表 | ✅ 医生列表 | ✅ |
|
||||
| 查看排班 | ✅ 日历视图 | ✅ 日历视图 | ✅ |
|
||||
| 创建预约 | ✅ `POST /health/appointments` | ✅ 相同 | ✅ |
|
||||
| 查看预约 | ✅ 列表+详情 | ✅ 列表+详情 | ✅ |
|
||||
| 取消预约 | ✅ `PUT /appointments/:id/status` | ✅ 相同 | ✅ |
|
||||
|
||||
**结论**: 预约流程三端完全一致。
|
||||
|
||||
### 4.3 健康数据录入流程
|
||||
|
||||
| 步骤 | Web | 小程序 | 一致性 |
|
||||
|------|-----|--------|--------|
|
||||
| 体征录入 | ✅ `POST /patients/:id/vital-signs` | ✅ 相同 | ✅ |
|
||||
| 查看趋势 | ✅ `GET /patients/:id/trends` | ✅ `GET /vital-signs/trend` | ⚠️ 路径不同 |
|
||||
| 今日概览 | ❌ 无此功能 | ✅ `GET /vital-signs/today` | ⚠️ MP 独有 |
|
||||
| 日常监测 | ✅ | ✅ | ✅ |
|
||||
| 化验报告上传 | ✅ 含文件上传 | ✅ 仅查看 | ⚠️ MP 无上传 |
|
||||
|
||||
**结论**: 核心录入一致,查看路径有差异(患者自服务 vs 管理端视角)。
|
||||
|
||||
### 4.4 咨询流程
|
||||
|
||||
| 步骤 | Web | 小程序 | 一致性 |
|
||||
|------|-----|--------|--------|
|
||||
| 创建会话 | ✅ | ✅ | ✅ |
|
||||
| 发送消息 | ✅ `POST /consultation-messages` | ✅ 相同 | ✅ |
|
||||
| 接收消息 | ✅ SSE 实时 | ⚠️ 8s 轮询 | ⚠️ 实时性差异 |
|
||||
| 标记已读 | ✅ | ✅ | ✅ |
|
||||
| 关闭会话 | ✅ | ✅(仅医生端) | ✅ |
|
||||
|
||||
**结论**: 核心流程一致,消息接收机制因平台限制不同。
|
||||
|
||||
### 4.5 透析管理流程 ⚠️
|
||||
|
||||
| 步骤 | Web | 小程序 | 一致性 |
|
||||
|------|-----|--------|--------|
|
||||
| 透析记录列表 | ⚠️ 冻结 | ✅ | ❌ |
|
||||
| 创建透析记录 | ⚠️ 冻结 | ✅(医生端) | ❌ |
|
||||
| 审阅透析记录 | ⚠️ 冻结 | ✅(医生端) | ❌ |
|
||||
| 透析处方管理 | ❌ 无页面 | ✅(医生端) | ❌ |
|
||||
| 透析统计 | ✅ | ✅(医生端) | ✅ |
|
||||
|
||||
**结论**: Web 端透析模块冻结,小程序端完整可用。这是最大的不一致项。
|
||||
|
||||
### 4.6 积分商城流程
|
||||
|
||||
| 步骤 | Web(管理) | 小程序(患者) | 一致性 |
|
||||
|------|------------|----------------|--------|
|
||||
| 每日签到 | ❌ | ✅ | ⚠️ MP 独有 |
|
||||
| 积分查询 | ✅ | ✅ | ✅ |
|
||||
| 商品浏览 | ✅(管理) | ✅(浏览) | ✅ |
|
||||
| 积分兑换 | ❌ | ✅ | ⚠️ MP 独有 |
|
||||
| 订单核销 | ✅ | ❌ | ⚠️ Web 独有 |
|
||||
|
||||
**结论**: 管理端与患者端分工明确,无遗漏。
|
||||
|
||||
---
|
||||
|
||||
## 五、权限码一致性
|
||||
|
||||
### 5.1 权限覆盖
|
||||
|
||||
| 模块 | 后端权限码 | Web 路由守卫 | 小程序角色检查 |
|
||||
|------|-----------|-------------|---------------|
|
||||
| health.patient | .list / .manage | ✅ 路由守卫 | ✅ isMedicalStaff |
|
||||
| health.health-data | .list / .manage | ✅ | ✅ |
|
||||
| health.appointment | .list / .manage | ✅ | ✅ |
|
||||
| health.follow-up | .list / .manage | ✅ | ✅ |
|
||||
| health.consultation | .list / .manage | ✅ | ✅ |
|
||||
| health.alerts | .list / .manage | ✅ | ✅ |
|
||||
| health.dialysis | .list / .manage | ⚠️ 冻结路由 | ✅ 医生角色 |
|
||||
| health.points | .list / .manage | ✅ | ✅ |
|
||||
| ai.analysis | .list / .manage | ✅ | ✅(仅查看) |
|
||||
| ai.suggestion | .list / .manage | ✅ | ⚠️ 仅 list |
|
||||
|
||||
**结论**: 权限码体系完整,Web 路由守卫与后端权限一一对应。
|
||||
|
||||
---
|
||||
|
||||
## 六、需要修复的不一致项
|
||||
|
||||
### CRITICAL — 无
|
||||
|
||||
### HIGH — 1 项
|
||||
|
||||
| # | 问题 | 影响 | 状态 |
|
||||
|---|------|------|------|
|
||||
| H1 | **小程序咨询消息为 8s 轮询,Web 为 SSE 实时** | 小程序消息延迟,体验不一致 | 🔧 待实现 |
|
||||
|
||||
### 已关闭(产品决策冻结)
|
||||
|
||||
| # | 问题 | 决策 |
|
||||
|---|------|------|
|
||||
| ~~H1~~ | Web 端透析管理路由冻结 | ✅ 保持冻结,当前版本不涉及医疗业务 |
|
||||
| ~~H2~~ | Web 端无透析处方管理页面 | ✅ 冻结,与透析管理同步 |
|
||||
| ~~M1~~ | Web 端无用药提醒功能 | ✅ 三端冻结 |
|
||||
| ~~M2~~ | 小程序 AI 分析仅查看历史 | ✅ 设计意图,小程序仅展示结果 |
|
||||
|
||||
### LOW — 5 项(多为设计意图)
|
||||
|
||||
| # | 问题 | 说明 |
|
||||
|---|------|------|
|
||||
| L1 | 小程序趋势查询使用专属端点 | 患者自服务视角 vs 管理端视角,设计意图 |
|
||||
| L2 | 小程序今日体征为独有功能 | 患者端需求,管理端不需要 |
|
||||
| L3 | 小程序不支持 SSE 流式分析 | 平台限制,非遗漏 |
|
||||
| L4 | 积分签到仅小程序 | 用户粘性功能,管理端不需要 |
|
||||
| L5 | 法律文件仅小程序 | 小程序上架合规要求 |
|
||||
|
||||
---
|
||||
|
||||
## 七、统计数据
|
||||
|
||||
| 指标 | 值 |
|
||||
|------|-----|
|
||||
| 后端 API 端点 | ~300+ |
|
||||
| Web 前端 API 调用 | ~270 |
|
||||
| 小程序 API 调用 | ~91 |
|
||||
| 三端完全一致的业务流程 | 8/11 (73%) |
|
||||
| 需要修复的不一致项 | HIGH ×2 + MEDIUM ×3 + LOW ×5 |
|
||||
| 设计意图导致的差异 | 13 项(非遗漏) |
|
||||
| 总体一致性评分 | **82%** |
|
||||
|
||||
---
|
||||
|
||||
## 八、结论与建议
|
||||
|
||||
### 8.1 总体评价
|
||||
|
||||
HMS 三端在 API 接口层面保持了高度一致性(统一前缀、统一响应格式、统一分页、统一乐观锁),差异主要集中在:
|
||||
|
||||
1. **端定位不同导致的功能差异** — 这是设计意图,不需要修复
|
||||
2. **Web 端透析模块冻结** — 这是最大的不一致项,需要产品决策
|
||||
3. **个别功能仅在单端实现** — 用药提醒、透析处方等需评估是否补齐
|
||||
|
||||
### 8.2 优先行动建议
|
||||
|
||||
1. **产品决策**: 确认透析管理模块是否在 Web 端解冻。如果血透中心是首发场景,Web 管理端的透析能力不应缺失
|
||||
2. **功能补齐**: Web 端补充透析处方管理页面(后端 API 已就绪)
|
||||
3. **功能补齐**: Web 端患者详情增加用药提醒管理(后端 API 已就绪)
|
||||
4. **体验优化**: 评估小程序咨询消息是否需要更实时的方案
|
||||
5. **能力对齐**: 评估小程序是否需要 AI 分析触发入口
|
||||
154
docs/audits/v2/00-baseline-refresh.md
Normal file
154
docs/audits/v2/00-baseline-refresh.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# V2 审计基线刷新 — 2026-05-04
|
||||
|
||||
> 日期: 2026-05-04 | Git HEAD: 95fa09c | 提交数: 623
|
||||
|
||||
## 一、代码库规模
|
||||
|
||||
| 维度 | V1 (2026-04-30) | V2 (2026-05-04) | 增量 |
|
||||
|------|-----------------|-----------------|------|
|
||||
| Rust 源文件 | 462 | **551** | +89 (+19%) |
|
||||
| Rust 总行数 | ~77,000 | **98,501** | +21,501 (+28%) |
|
||||
| Web TS/TSX | 225 | **264** | +39 (+17%) |
|
||||
| MP TS/TSX | 182 | **116** | *(统计口径不同)* |
|
||||
| Git 提交 | 409 | **623** | +214 |
|
||||
| 迁移文件 | 96 | **115** | +19 (+20%) |
|
||||
|
||||
## 二、Entity 统计(97 个)
|
||||
|
||||
| Crate | Entity 数 | V1 数 | 增量 |
|
||||
|-------|----------|-------|------|
|
||||
| erp-health | **55** | 46 | +9 |
|
||||
| erp-auth | 12 | 11 | +1 |
|
||||
| erp-plugin | 5 | 4 | +1 |
|
||||
| erp-config | 6 | 6 | 0 |
|
||||
| erp-workflow | 5 | 5 | 0 |
|
||||
| erp-core | 4 | 4 | 0 |
|
||||
| erp-ai | **5** | 3 | +2 (suggestion, risk_threshold) |
|
||||
| erp-message | 3 | 3 | 0 |
|
||||
| erp-dialysis | **2** | 1 | +1 |
|
||||
| **合计** | **97** | 83 | **+14** |
|
||||
|
||||
## 三、Handler 统计(54 文件)
|
||||
|
||||
| Crate | Handler 数 |
|
||||
|-------|----------|
|
||||
| erp-health | **29** |
|
||||
| erp-config | 6 |
|
||||
| erp-auth | 5 |
|
||||
| erp-message | 4 |
|
||||
| erp-dialysis | 3 |
|
||||
| erp-plugin | 3 |
|
||||
| erp-workflow | 3 |
|
||||
| erp-ai | 1 |
|
||||
|
||||
## 四、路由统计
|
||||
|
||||
| Crate | 公开路由 | 受保护路由 | 特殊认证 | 合计 |
|
||||
|-------|---------|-----------|---------|------|
|
||||
| erp-health | 1 | 145 | FHIR 18 + OAuth 1 + 网关 2 | **167** |
|
||||
| erp-auth | 4 | 20 | - | **24** |
|
||||
| erp-plugin | 0 | 31 | - | **31** |
|
||||
| erp-ai | 0 | 17 | - | **17** |
|
||||
| erp-config | 1 | 16 | - | **17** |
|
||||
| erp-workflow | 0 | 14 | - | **14** |
|
||||
| erp-message | 0 | 9 | - | **9** |
|
||||
| erp-dialysis | 0 | 7 | - | **7** |
|
||||
| erp-server | 3 | 4 | - | **7** |
|
||||
| **合计** | **9** | **263** | **21** | **293** |
|
||||
|
||||
> 注:V1 计为 328 路由,V2 计为 293 `.route()` 调用。差异可能因 V1 含中间件链中隐式注册的路由或统计口径不同。
|
||||
|
||||
### 新增路由亮点
|
||||
- **FHIR R4**: 18 条路由(OAuth client_credentials 认证)
|
||||
- **BLE 网关**: 2 条路由(API Key 认证)
|
||||
- **班次管理**: 新增 handler(13 次权限检查)
|
||||
- **护理计划**: 新增 handler(14 次权限检查)
|
||||
- **行动收件箱**: 新增 handler
|
||||
- **日聚合**: 新增 handler
|
||||
|
||||
## 五、事件系统
|
||||
|
||||
| 指标 | V1 | V2 |
|
||||
|------|-----|-----|
|
||||
| 事件类型总数 | 25 | **51** |
|
||||
| OK(完整链路) | 11 | **24** |
|
||||
| FIRE-AND-FORGET | 14 | **25** |
|
||||
| PENDING | 2 | **2** |
|
||||
|
||||
**PENDING 事件**: `patient.verified`、`patient.deceased`
|
||||
|
||||
## 六、DTO 与权限
|
||||
|
||||
| 指标 | V1 | V2 |
|
||||
|------|-----|-----|
|
||||
| erp-health DTO 文件 | 23 | **19** (*拆分后文件减少但覆盖更全*) |
|
||||
| PermissionDescriptor | 50 | **53** |
|
||||
| require_permission 调用 | ~170 | **262** |
|
||||
|
||||
## 七、测试统计
|
||||
|
||||
| 类别 | V1 | V2 | 变化 |
|
||||
|------|-----|-----|------|
|
||||
| 后端测试函数 | 772 | 待 `cargo test` | -- |
|
||||
| Web 测试文件 | 10 | **62** | +520% |
|
||||
| MP 测试文件 | 0 | **0** | 未变 |
|
||||
| E2E spec | 5 | **0** | *(待确认)* |
|
||||
|
||||
## 八、V1 问题修复验证
|
||||
|
||||
| ID | 问题 | 状态 | 验证详情 |
|
||||
|----|------|------|---------|
|
||||
| C1 | 晚间血压丢失 | **PASS** | V1 已确认修复 |
|
||||
| C2 | 告警权限拼写 | **PASS** | `health.alerts.manage` 前后端一致 |
|
||||
| H1 | 透析管理 MP | **PASS** | 7 个 MP 页面(患者端 4 + 医生端 3)+ 2 个 service |
|
||||
| H2 | 知情同意 MP | **PASS** | consents 页面 + consent service |
|
||||
| H3 | 日志补全 | **PASS** | 17 个 service 文件 / 116 处 tracing 调用(V1: 11 处) |
|
||||
| M1 | 权限声明 | **PASS** | 53 个 PermissionDescriptor(V1: 50) |
|
||||
| M3 | 体温/血氧 MP | **PASS** | BLE + 手动录入双通道映射完整 |
|
||||
| M4 | SSE 指数退避 | **PASS** | V1 已确认修复 |
|
||||
| M5 | erp-ai 集成测试 | **PASS** | V1 已确认修复 |
|
||||
| M6 | Web 前端测试 | **大幅改善** | 62 文件(V1: 10) |
|
||||
| M7 | MP 测试 | **未修复** | 仍为 0 |
|
||||
| M8 | 健康记录/诊断 MP | **PASS** | 新增页面 |
|
||||
| L1 | 孤立事件 | **PASS** | V1 已确认修复 |
|
||||
| L5 | unwrap() 风险 | **PASS** | V1 已确认修复 |
|
||||
| L12 | 编译警告 | **需关注** | 9 文件 / 18 处 `#[allow(...)]` |
|
||||
|
||||
## 九、V1 后新增迁移(19 个)
|
||||
|
||||
| 迁移文件 | 内容 |
|
||||
|----------|------|
|
||||
| m20260501_000097 | 菜单权限种子 |
|
||||
| m20260501_000098 | AI 建议表 |
|
||||
| m20260501_000099 | AI 风险阈值表 |
|
||||
| m20260501_000100 | 行动收件箱菜单种子 |
|
||||
| m20260502_000101 | 健康字典种子 |
|
||||
| m20260502_000102 | 告警阈值种子 |
|
||||
| m20260502_000103 | 随访模板菜单种子 |
|
||||
| m20260504_000104 | 生命体征日汇总表 |
|
||||
| m20260504_000105 | 患者设备增加 status |
|
||||
| m20260504_000106 | API 客户端表 |
|
||||
| m20260504_000107 | 文章标签加租户+软删除 |
|
||||
| m20260504_000108 | 小时体征加软删除 |
|
||||
| m20260504_000109 | 补充缺失外键约束 |
|
||||
| m20260504_000110 | 危急值版本字段 i32 |
|
||||
| m20260505_000111 | 护理计划表 |
|
||||
| m20260505_000112 | 班次管理表 |
|
||||
| m20260505_000113 | BLE 网关表 |
|
||||
| m20260505_000114 | 透析记录关联工作流 |
|
||||
| m20260505_000115 | 家庭成员健康代理 |
|
||||
|
||||
## 十、关键发现
|
||||
|
||||
### 正面变化
|
||||
1. **代码量大幅增长**: Rust +28% (21,501 行),Phase 0+1 新增大量功能代码
|
||||
2. **V1 问题全部修复**: 15 项中 14 项已修复/改善,仅 M7 (MP 测试) 未变
|
||||
3. **日志大幅改善**: 从 11 处 → 116 处 tracing 调用,覆盖率从 30% → 预计 >80%
|
||||
4. **权限码覆盖提升**: 从 50 → 53 个 PermissionDescriptor,262 次权限检查调用
|
||||
5. **Web 测试激增**: 从 10 → 62 文件
|
||||
|
||||
### 关注点
|
||||
1. **18 处 `#[allow(...)]` 标注**: 9 个文件中存在,部分可能是合理抑制,需 Phase 4 逐一审查
|
||||
2. **路由计数差异**: V2 统计 293 vs V1 的 328,需 Phase 2 统一对齐
|
||||
3. **MP 测试仍为 0**: 40+ 页面无自动化测试
|
||||
4. **2 个 PENDING 事件**: `patient.verified`、`patient.deceased` 未实现
|
||||
124
docs/audits/v2/01-business-value-analysis.md
Normal file
124
docs/audits/v2/01-business-value-analysis.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# HMS 功能域业务价值分析
|
||||
|
||||
> 日期: 2026-05-04 | 定位: AI 驱动的主动关怀引擎 | 首发客户: 血液透析中心
|
||||
> 核心价值: 增进患者与机构的信任羁绊
|
||||
|
||||
## 功能域分析
|
||||
|
||||
### F1 患者管理 — 血透中心价值: 高
|
||||
|
||||
患者是关怀引擎的锚点。管理建档、标签、家庭关系、医患绑定、实名认证。目标用户: 管理员+医护。慢性透析患者需长期跟踪,完整患者画像是所有干预的基础。三端覆盖较好(后端20/Web10/MP3),家庭代理和标签 CRUD 有缺口。
|
||||
|
||||
### F2 医生排班 — 血透中心价值: 中
|
||||
|
||||
管理医生工作时间、轮班计划、排班日历。目标用户: 管理员。血透中心医生数量有限,排班需求相对简单,需保证咨询时段与实际值班对齐。三端 100% 覆盖。
|
||||
|
||||
### F3 健康数据 — 血透中心价值: 高
|
||||
|
||||
体征录入(血压/心率/血糖/体温/SpO2/体重)、化验报告、日常监测。目标用户: 患者(录入)+医护(查看)。透析患者需高频监测(每周2-3次透前透后数据),是"主动关怀"的数据基石。vital_signs 与 daily_monitoring 存在字段重叠,日聚合(F20)正试图解决。
|
||||
|
||||
### F4 预约管理 — 血透中心价值: 高
|
||||
|
||||
透析治疗预约、复查预约、时间选择与智能推荐。目标用户: 患者(预约)+管理员(管理)。透析患者每周需预约2-3次治疗,预约流程顺畅度直接影响依从性和运营效率。三端 100% 覆盖。
|
||||
|
||||
### F5 随访管理 — 血透中心价值: 高
|
||||
|
||||
随访任务创建/分配/执行/记录,随访模板与台账。目标用户: 医护(执行)+管理员(配置)。随访是"主动关怀"的核心动作,定期了解患者透析间期状况是增进信任的关键触点。批量操作后端有但前端未调用。
|
||||
|
||||
### F6 咨询管理 — 血透中心价值: 高
|
||||
|
||||
患者与医生图文语音沟通,支持预设回复模板。目标用户: 患者(发起)+医护(回复)。透析患者突发状况多(低血压、瘘管异常),及时沟通是安全底线。MP 端最完善(12 API)。
|
||||
|
||||
### F7 内容管理 — 血透中心价值: 中
|
||||
|
||||
公告发布、科普文章、首页轮播配置。目标用户: 运营人员。科普内容(饮食指导、瘘管护理)可减少重复咨询,但非核心收入驱动力。Web 100%/MP 仅查看(正常)。
|
||||
|
||||
### F8 积分商城 — 血透中心价值: 中
|
||||
|
||||
积分获取规则、商品兑换、核销、订单管理。目标用户: 患者(兑换)+运营(管理)。积分体系提升患者活跃度和打卡依从性,微信支付尚未集成。
|
||||
|
||||
### F9 告警系统 — 血透中心价值: 高
|
||||
|
||||
阈值规则配置、异常指标检测、多级告警推送。目标用户: 管理员(配置)+医护(响应)。血钾过高、血压骤变等危急值需即时预警,直接关系患者安全。危急值阈值管理页缺失。
|
||||
|
||||
### F10 AI 分析 — 血透中心价值: 高
|
||||
|
||||
健康趋势分析、异常指标识别、AI 报告生成、透析风险评估。目标用户: 医护(辅助决策)+患者(报告查看)。这是"AI 驱动"定位的核心体现。AI 缓存未启用,透析风险评估端点未接入前端。
|
||||
|
||||
### F11 透析管理 — 血透中心价值: 高
|
||||
|
||||
透析记录(类型/干体重/超滤量/血流量)、透析方案管理。目标用户: 医护(记录)+患者(查看)。透析是血透中心的核心业务,完整记录是质量管理和医保结算的基础。MP 端 100%。
|
||||
|
||||
### F12 统计仪表盘 — 血透中心价值: 高
|
||||
|
||||
患者增长、咨询量、随访完成率、透析质量统计。目标用户: 管理层。中心管理者需数据支撑运营决策(床位利用率、患者流失率、透析充分性达标率)。
|
||||
|
||||
### F13 行动收件箱 — 血透中心价值: 高
|
||||
|
||||
将告警、随访任务、待办汇聚为统一行动队列。目标用户: 医护。将"被动查看"转为"主动响应",每个医护登录后即看到待办清单。存在 SQL 注入风险(SEC-01)需优先修复。
|
||||
|
||||
### F14 护理计划 — 血透中心价值: 中
|
||||
|
||||
阶段性护理目标、干预措施、评估节点。目标用户: 护士长+管理员。能标准化血透护理流程(血管通路护理、饮食管理),但后端 8 路由完全无前端 UI,是当前最大孤立模块之一。
|
||||
|
||||
### F15 班次管理 — 血透中心价值: 中
|
||||
|
||||
透析班次安排、护士交接班记录。目标用户: 管理员。血透中心通常分上午/下午/晚间三班,班次管理直接影响排床效率。后端 8 路由完全无前端 UI。
|
||||
|
||||
### F16 BLE 网关 — 血透中心价值: 中
|
||||
|
||||
蓝牙设备数据自动采集、网关注册与心跳监控。目标用户: 系统管理员(配置)+患者(无感使用)。自动采集减少患者手动录入负担。后端 9 路由无前端 UI,API Key 安全机制已就绪。
|
||||
|
||||
### F17 家庭代理 — 血透中心价值: 中
|
||||
|
||||
家属代绑就诊人、代理查看健康数据。目标用户: 患者家属。老年透析患者家属(子女)是实际决策者,扩大了"信任羁绊"覆盖面。后端 5 路由完全无前端 UI。
|
||||
|
||||
### F18 FHIR 接口 — 血透中心价值: 中
|
||||
|
||||
HL7 FHIR R4 标准化数据接口。目标用户: 外部系统(M2M)。长期来看与 HIS/LIS 互通是刚需,但短期首发客户可能暂不需要。后端 15 路由,OAuth 认证已实现。
|
||||
|
||||
### F19 OAuth 认证 — 血透中心价值: 低
|
||||
|
||||
第三方应用接入 OAuth2 Client Credentials 流程。目标用户: 系统管理员。平台级基础设施,间接支撑 F18,血透中心本身不直接感知。存在权限缺失(SEC-02)。
|
||||
|
||||
### F20 日聚合趋势 — 血透中心价值: 高
|
||||
|
||||
按日聚合生命体征数据,生成趋势图表。目标用户: 医护+患者。透析患者需观察干体重变化趋势、血压波动规律,日聚合是趋势分析的基础数据层。
|
||||
|
||||
## 评分汇总
|
||||
|
||||
| 域 | 客户价值(×4) | 使用频率(×3) | 差异化(×2) | 缺失风险(×1) | 总分 |
|
||||
|----|-------------|-------------|-----------|-------------|------|
|
||||
| F1 患者管理 | 5 | 5 | 3 | 2 | 43 |
|
||||
| F2 医生排班 | 3 | 4 | 2 | 2 | 30 |
|
||||
| F3 健康数据 | 5 | 5 | 3 | 3 | 44 |
|
||||
| F4 预约管理 | 5 | 5 | 4 | 2 | 45 |
|
||||
| F5 随访管理 | 5 | 4 | 4 | 3 | 45 |
|
||||
| F6 咨询管理 | 5 | 5 | 3 | 2 | 44 |
|
||||
| F7 内容管理 | 3 | 3 | 2 | 1 | 24 |
|
||||
| F8 积分商城 | 3 | 3 | 5 | 2 | 32 |
|
||||
| F9 告警系统 | 5 | 4 | 3 | 4 | 45 |
|
||||
| F10 AI 分析 | 5 | 3 | 5 | 3 | 43 |
|
||||
| F11 透析管理 | 5 | 5 | 4 | 3 | **48** |
|
||||
| F12 统计仪表盘 | 5 | 3 | 3 | 4 | 41 |
|
||||
| F13 行动收件箱 | 5 | 4 | 4 | 3 | 44 |
|
||||
| F14 护理计划 | 3 | 3 | 4 | 4 | 33 |
|
||||
| F15 班次管理 | 3 | 4 | 3 | 3 | 33 |
|
||||
| F16 BLE 网关 | 3 | 2 | 4 | 3 | 29 |
|
||||
| F17 家庭代理 | 3 | 2 | 3 | 3 | 27 |
|
||||
| F18 FHIR 接口 | 3 | 2 | 4 | 2 | 28 |
|
||||
| F19 OAuth 认证 | 2 | 2 | 3 | 2 | 23 |
|
||||
| F20 日聚合趋势 | 5 | 4 | 3 | 3 | 41 |
|
||||
|
||||
> 满分 50 分。权重: 客户价值×4, 使用频率×3, 差异化×2, 缺失风险×1
|
||||
|
||||
## 优先级分组
|
||||
|
||||
**P0 立即交付** (40+分, 11 个):
|
||||
F11 透析管理(48) > F4 预约(45) = F5 随访(45) = F9 告警(45) > F6 咨询(44) = F3 健康数据(44) = F13 行动收件箱(44) > F1 患者(43) = F10 AI(43) > F12 仪表盘(41) = F20 日聚合(41)
|
||||
|
||||
**P1 近期补全** (30-39分, 4 个):
|
||||
F8 积分(32) = F14 护理计划(33) = F15 班次(33) > F2 排班(30)
|
||||
|
||||
**P2 中期规划** (<30分, 5 个):
|
||||
F16 BLE(29) > F18 FHIR(28) > F17 家庭代理(27) > F7 内容(24) > F19 OAuth(23)
|
||||
106
docs/audits/v2/02-feature-inventory-refresh.md
Normal file
106
docs/audits/v2/02-feature-inventory-refresh.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# V2 审计 — 功能清单刷新与三端对齐
|
||||
|
||||
> 日期: 2026-05-04 | 方法: module.rs 路由提取 + Web/MP API 调用扫描
|
||||
|
||||
## 一、三端数字概览
|
||||
|
||||
| 指标 | V1 (4/30) | V2 (5/4) | 变化 |
|
||||
|------|-----------|----------|------|
|
||||
| 后端路由 | 328 | **302** | -26 (模块整合) |
|
||||
| Web API 调用 | 235 | **252** | +17 (AI SSE/行动收件箱/OAuth/设备) |
|
||||
| MP API 调用 | 76 | **96** | +20 (医生端/行动收件箱/同意/药物提醒/AI/透析) |
|
||||
|
||||
## 二、各模块路由分布
|
||||
|
||||
| Crate | 路由数 | 备注 |
|
||||
|-------|--------|------|
|
||||
| erp-health | **179** | 最大模块,含 FHIR/OAuth/网关 |
|
||||
| erp-plugin | 31 | 插件系统 |
|
||||
| erp-auth | 20 | 认证/用户/角色 |
|
||||
| erp-config | 16 | 字典/菜单/设置 |
|
||||
| erp-ai | 17 | AI 分析/建议/Prompt |
|
||||
| erp-workflow | 14 | 流程定义/实例/任务 |
|
||||
| erp-message | 9 | 消息/模板 |
|
||||
| erp-dialysis | 7 | 透析记录 |
|
||||
| erp-server | 9 | 健康检查/审计/上传 |
|
||||
|
||||
## 三、三端对齐矩阵
|
||||
|
||||
| 功能域 | 后端 | Web | MP | Web% | MP% |
|
||||
|--------|------|-----|-----|------|-----|
|
||||
| 认证/微信登录 | 7 | 3 | 3 | 43% | 43% |
|
||||
| 患者管理 | 20 | 10 | 3 | 50% | 15% |
|
||||
| 家庭代理 | 5 | 0 | 0 | **0%** | **0%** |
|
||||
| 医护管理 | 5 | 5 | 7 | 100% | 100% |
|
||||
| 健康数据(体征/化验/记录) | 22 | 14 | 10 | 64% | 45% |
|
||||
| 日常监测 | 5 | 4 | 2 | 80% | 40% |
|
||||
| 随访任务/记录 | 11 | 7 | 10 | 64% | 91% |
|
||||
| 随访模板 | 5 | 5 | 0 | 100% | **0%** |
|
||||
| 预约排班 | 7 | 8 | 7 | 100% | 100% |
|
||||
| 咨询管理 | 8 | 6 | 12 | 75% | 100% |
|
||||
| 文章内容 | 16 | 16 | 3 | 100% | 19% |
|
||||
| 积分商城 | 22 | 24 | 8 | 100% | 36% |
|
||||
| 线下活动 | 6 | 4 | 2 | 67% | 33% |
|
||||
| 统计仪表盘 | 13 | 9 | 3 | 69% | 23% |
|
||||
| 告警系统 | 10 | 8 | 5 | 80% | 50% |
|
||||
| 设备/读数 | 6 | 6 | 3 | 100% | 50% |
|
||||
| 行动收件箱 | 5 | 5 | 2 | 100% | 40% |
|
||||
| 知情同意 | 3 | 0 | 3 | **0%** | 100% |
|
||||
| 药物记录 | 4 | 0 | 0 | **0%** | **0%** |
|
||||
| 药物提醒 | 4 | 0 | 4 | **0%** | 100% |
|
||||
| 诊断 | 3 | 0 | 1 | **0%** | 33% |
|
||||
| **护理计划** | 8 | 0 | 0 | **0%** | **0%** |
|
||||
| **班次/交接** | 8 | 0 | 0 | **0%** | **0%** |
|
||||
| **BLE 网关** | 9 | 0 | 0 | **0%** | **0%** |
|
||||
| AI 分析 | 6 | 6 | 3 | 100% | 50% |
|
||||
| AI Prompt | 4 | 4 | 0 | 100% | 0% |
|
||||
| AI 建议 | 4 | 3 | 1 | 75% | 25% |
|
||||
| AI 用量 | 2 | 2 | 0 | 100% | 0% |
|
||||
| 透析管理 | 8 | 6 | 13 | 75% | 100% |
|
||||
| OAuth 合作方 | 5 | 5 | 0 | 100% | 0% |
|
||||
| **FHIR R4** | 15 | 0 | 0 | **0%** | **0%** |
|
||||
| 配置管理 | 16 | 26 | 0 | 100% | 0% |
|
||||
| 消息中心 | 7 | 8 | 4 | 100% | 57% |
|
||||
| 工作流 | 14 | 16 | 0 | 100% | 0% |
|
||||
| 插件系统 | 31 | 27 | 0 | 87% | 0% |
|
||||
|
||||
## 四、孤立路由(后端独有,无前端调用)
|
||||
|
||||
### 4.1 完全孤立的模块(后端已实现,前后端均无 UI)
|
||||
|
||||
| 模块 | 路由数 | 状态 |
|
||||
|------|--------|------|
|
||||
| **FHIR R4** | 15 | 外部系统接口,无内部 UI 正常 |
|
||||
| **护理计划** | 8 | 后端完整,前后端无 UI |
|
||||
| **班次/交接** | 8 | 后端完整,前后端无 UI |
|
||||
| **BLE 网关管理** | 9 | 后端完整(含上传/心跳),管理页面未接入 |
|
||||
| **家庭代理** | 5 | 后端完整,前后端无 UI |
|
||||
| **药物记录** | 4 | 后端完整,无前端 CRUD |
|
||||
| **诊断** | 3 | 后端完整,Web 无 UI |
|
||||
| **危急值阈值** | 4 | 后端完整,Web 无管理 UI |
|
||||
|
||||
### 4.2 部分孤立的路由
|
||||
|
||||
| 路由 | 说明 |
|
||||
|------|------|
|
||||
| 患者分配/移除医生 | 后端有,Web/MP 未调用 |
|
||||
| 家庭成员更新/删除 | 后端有,Web 无操作 |
|
||||
| 标签创建/编辑/删除 | Web 仅 list,无 CRUD |
|
||||
| 随访批量操作 (batch-create/assign/complete) | 后端有,前端未调用 |
|
||||
| AI 建议执行 | 后端有 execute 端点,Web 未调用 |
|
||||
| AI 透析风险评估 | 后端独立端点,未接入 |
|
||||
| 工作流任务认领/定义废弃 | 后端有,Web 未调用 |
|
||||
|
||||
## 五、关键发现
|
||||
|
||||
### 正面
|
||||
1. **MP 覆盖率显著提升**: 从 76→96 API (+26%),透析/同意/医生端全覆盖
|
||||
2. **无 Web 独有调用**: 所有 Web API 都有后端路由支撑
|
||||
3. **核心医疗流程覆盖良好**: 预约/咨询/医护/透析均达到三端 75%+ 覆盖
|
||||
|
||||
### 问题
|
||||
1. **5 个模块完全无前端 UI**: 护理计划(8)、班次(8)、BLE 网关(9)、家庭代理(5)、药物记录(4) = 34 条路由孤立
|
||||
2. **FHIR 15 条路由无内部 UI**: 正常(外部系统接口),但无管理页面
|
||||
3. **知情同意仅 MP 有**: 后端完整,Web 无管理页面
|
||||
4. **诊断仅 MP 有 33%**: 后端完整,Web 无页面
|
||||
5. **MP 管理功能缺失**: 标签管理、随访模板、AI Prompt、统计等无 MP 入口(设计正确,管理功能在 Web 端)
|
||||
377
docs/audits/v2/03-data-flow-traces.md
Normal file
377
docs/audits/v2/03-data-flow-traces.md
Normal file
@@ -0,0 +1,377 @@
|
||||
# 数据流追踪报告
|
||||
|
||||
> 审计日期: 2026-05-04 | 范围: 12 条核心数据流
|
||||
|
||||
---
|
||||
|
||||
## DF1: 体征录入 → 存储 → 告警
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `health_data_handler::create_vital_signs` — 权限校验 `health.health-data.manage`,输入消毒
|
||||
2. `health_data_service::vital_signs::create_vital_signs` — 校验患者存在,构建 ActiveModel
|
||||
3. `vital_signs::Entity::insert` — SeaORM 写入 `vital_signs` 表
|
||||
4. `health_data_service::alert::check_vital_signs_alert` — 从 DB 加载 `critical_value_threshold`,逐指标比对阈值
|
||||
5. `event_bus.publish("health_data.critical_alert")` — 发布危急值事件(含患者/医生信息)
|
||||
6. `audit_service::record` — 审计日志
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **告警触发不阻塞**: L129 `check_vital_signs_alert` 返回值被 `.await` 但未处理错误(fire-and-forget 语义),阈值配置缺失时静默跳过,无重试机制
|
||||
- **告警双路径**: 存在两条独立告警路径 — `alert.rs`(危急值事件)和 `alert_engine.rs`(规则引擎),阈值来源不同,可能产生重复告警
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[Handler: create_vital_signs] --> B[Service: 校验患者]
|
||||
B --> C[(Entity: vital_signs)]
|
||||
C --> D[check_vital_signs_alert]
|
||||
D --> E[(critical_value_threshold)]
|
||||
D --> F[EventBus: critical_alert]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DF2: BLE 设备 → 聚合 → 趋势
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `ble_gateway_handler::gateway_upload` — API Key 认证(非 JWT),接收多患者批量数据
|
||||
2. `ble_gateway_service::gateway_upload` — 校验患者-网关绑定关系
|
||||
3. `device_reading_service::batch_create_readings` — 校验患者、绑定设备、批量插入
|
||||
4. `device_readings::Entity::insert_many` — ON CONFLICT DO NOTHING 去重
|
||||
5. `sync_bp_glucose_to_vital_signs` — 双写 `vital_signs` 表(仅血压/血糖)
|
||||
6. `upsert_hourly_aggregates` — 按 (device_type, hour) 分组聚合写入 `vital_signs_hourly`
|
||||
7. `event_bus.publish("device.readings.synced")` — 发布设备同步事件
|
||||
8. `vital_signs_daily_service::aggregate_daily` — 定时从 hourly → daily 聚合
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **双写无事务保护**: L124 `sync_bp_glucose_to_vital_signs` 错误仅 warn 不阻塞主流程,可能导致 `vital_signs` 与 `device_readings` 数据不一致
|
||||
- **去重计数不准**: L252 `ON CONFLICT DO NOTHING` 返回提交总数而非实际插入数,`duplicates` 字段语义不准确
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[Gateway: API Key 认证] --> B[校验绑定关系]
|
||||
B --> C[(device_readings)]
|
||||
C --> D[双写 vital_signs]
|
||||
C --> E[聚合 hourly]
|
||||
E --> F[(vital_signs_daily)]
|
||||
C --> G[EventBus: synced]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DF3: AI 分析 SSE → 建议记录 → 行动分发
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `erp-ai/handler::stream_trends` — 权限校验,获取趋势数据,脱敏
|
||||
2. `analysis.stream_analyze` — 调用 LLM(Claude),返回 SSE 流 + analysis_id
|
||||
3. `build_sse_stream` — 逐 chunk 推送 SSE event:chunk,完成后 event:done
|
||||
4. `analysis.complete_analysis` — 标记分析完成,存储完整内容
|
||||
5. `post_process::post_process_analysis` — 解析双通道输出(文本+结构化)
|
||||
6. `SuggestionService::create_suggestions` — 创建 `ai_suggestion` 记录
|
||||
7. `event_bus.publish("ai.analysis.completed")` — 发布分析完成事件
|
||||
8. `action_inbox_service::list_action_items` — UNION 查询 ai_suggestion + alerts + followup
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **自动分析使用 Uuid::nil()**: `auto_analysis.rs` L108 `system_user_id = Uuid::nil()`,audit trail 中操作人为零值 UUID,无法追溯
|
||||
- **post_process 失败静默**: L66 建议创建失败仅 warn,分析仍标记 completed
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[SSE Handler: stream_trends] --> B[LLM Stream]
|
||||
B --> C[complete_analysis]
|
||||
C --> D[post_process: 解析双通道]
|
||||
D --> E[(ai_suggestion)]
|
||||
D --> F[EventBus: analysis.completed]
|
||||
F --> G[ActionInbox: UNION 查询]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DF4: 透析记录 → KDIGO 风险评分 → 告警
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `dialysis_handler::create_dialysis_record` — 权限校验 `health.dialysis.manage`
|
||||
2. `dialysis_service::create_dialysis_record` — PII 加密(symptoms, complication_notes),写入
|
||||
3. `dialysis_record::Entity::insert` — SeaORM 写入 `dialysis_record` 表
|
||||
4. `event_bus.publish("dialysis.record.created")` — 发布透析记录创建事件
|
||||
5. `erp-ai/handler::assess_dialysis_risk` — 接收 `DialysisLabInput`(Kt/V, eGFR 等)
|
||||
6. `DialysisRiskScorer::assess` — KDIGO CKD 分期(基于 eGFR)+ 本地规则引擎评分
|
||||
7. `LocalRulesEngine` — 评估 Kt/V、血磷、血钾、血红蛋白等规则,返回 risk_level + suggestions
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **透析创建与风险评分解耦**: 风险评分为独立 HTTP 端点,创建透析记录后不会自动触发 KDIGO 评分,需前端手动调用
|
||||
- **事件未被消费**: `dialysis.record.created` 事件已发布但无确认的 subscriber 自动触发风险评估
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[Handler: create_dialysis_record] --> B[PII 加密]
|
||||
B --> C[(dialysis_record)]
|
||||
C --> D[EventBus: record.created]
|
||||
E[手动调用 assess_dialysis_risk] --> F[KDIGO 分期]
|
||||
F --> G[LocalRulesEngine]
|
||||
G --> H[RiskAssessment]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DF5: 告警触发 → 降噪 → 推送
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `alert_engine::evaluate_rules` — 加载 `alert_rules`(按 device_type 过滤活跃规则)
|
||||
2. 规则评估: `single_threshold` / `consecutive` / `trend`(基于 `vital_signs_hourly`)
|
||||
3. `alert_noise_reducer::apply_noise_reduction` — 两级降噪:
|
||||
- `check_patient_escalation` — 30min 内 3 次低级告警 → 升级严重度
|
||||
- `check_system_aggregation` — 5min 内同患者重复 → 抑制通知(critical 除外)
|
||||
4. `alerts::Entity::insert` — 写入告警记录(含升级后严重度)
|
||||
5. `event_bus.publish("alert.triggered")` — 发布告警事件(含 notify_roles, suppressed 标记)
|
||||
6. `erp-message/sse_handler::message_stream` — SSE 推送:
|
||||
- `alert.triggered` → SSE event: `alert`(校验管床医生关系)
|
||||
- 30s 心跳保活 + Last-Event-ID 断点续传
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **聚合窗口无滑动**: `check_system_aggregation` 每次插入后都查询最近 5min 内所有告警,高并发下可能导致 N+1 查询
|
||||
- **SSE 无背压控制**: `sse_handler` 使用 unbounded channel,告警风暴时可能导致内存压力
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[alert_engine: 规则匹配] --> B[降噪: 患者升级]
|
||||
B --> C[降噪: 系统聚合]
|
||||
C --> D[(alerts 表)]
|
||||
D --> E[EventBus: alert.triggered]
|
||||
E --> F[SSE: 管床医生过滤]
|
||||
F --> G[前端推送]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DF6: 护理计划 → 项目 → 预后
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `care_plan_handler::create_care_plan` — 权限校验 `health.care-plan.manage`
|
||||
2. `care_plan_service::create_care_plan` — 校验患者、计划类型,写入
|
||||
3. `care_plan::Entity::insert` — 写入 `care_plan` 表(status=draft)
|
||||
4. `care_plan_item::Entity::insert` — 写入护理项目(排序、类型、频次)
|
||||
5. `care_plan_service::create_care_plan_outcome` — 写入预后评估记录
|
||||
6. `care_plan_outcome::Entity::insert` — 写入 `care_plan_outcome` 表(评分、达成状态)
|
||||
7. `event_bus.publish("care_plan.status_changed")` — 状态变更事件
|
||||
8. `event_bus.publish("care_plan.outcome_updated")` — 预后更新事件
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **plan → item → outcome 无事务包裹**: 三张表写入分散在不同函数调用中,中间失败可能导致孤立记录
|
||||
- **status 流转无状态机保护**: `care_plan.status` 为自由字符串,未使用枚举约束,可写入非法状态
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[Handler: create_care_plan] --> B[校验患者+类型]
|
||||
B --> C[(care_plan)]
|
||||
C --> D[(care_plan_item)]
|
||||
D --> E[(care_plan_outcome)]
|
||||
E --> F[EventBus: status_changed]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 汇总
|
||||
|
||||
| 数据流 | 关键风险 | 严重度 |
|
||||
|--------|---------|--------|
|
||||
| DF1 | 告警双路径可能重复触发 | 中 |
|
||||
| DF2 | 双写无事务保护 | 高 |
|
||||
| DF3 | 自动分析 operator 为零值 UUID | 低 |
|
||||
| DF4 | 透析创建与 KDIGO 评分未自动串联 | 高 |
|
||||
| DF5 | SSE 无背压、聚合查询 N+1 | 中 |
|
||||
| DF6 | 三表写入无事务、状态无枚举约束 | 高 |
|
||||
| DF7 | 前端无健康摘要页面、概念混淆 | 中 |
|
||||
| DF8 | $everything 无分页、血压 ID 重复、缺 Bundle link | 高 |
|
||||
| DF9 | allowed_patient_ids 越权、JWT 弱 fallback | 高 |
|
||||
| DF10 | 签到无事件发布、连续天数计算脆弱 | 低 |
|
||||
| DF11 | 前后对比功能未实现、再分析无幂等 | 高 |
|
||||
| DF12 | 串行处理、降采样效率低、双写失败静默 | 中 |
|
||||
|
||||
---
|
||||
|
||||
## DF7: 家庭代理查看 → 同意验证 → 健康摘要
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `family_proxy_handler::list_my_family_patients` — 查询已授权访问的家庭患者
|
||||
2. `family_proxy_service::check_access` — 验证 consent + access_level
|
||||
3. `family_proxy_handler::get_family_health_summary` — 返回脱敏健康摘要
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **前端无健康摘要页面**: 后端 `get_family_health_summary` 已实现但前端无调用
|
||||
- **概念混淆**: MP family 页面调用 `listPatients`(患者管理 API)而非 `list_my_family_patients`(家庭代理 API)
|
||||
- **link_user 无入口**: 家庭成员绑定用户流程在小程序中无入口
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[MP 就诊人管理] --> B{Consent 验证}
|
||||
B -->|granted| C[family_proxy_service]
|
||||
C --> D[脱敏健康摘要]
|
||||
B -->|denied| E[403 拒绝]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DF8: FHIR 资源查询 → 转换器 → 标准 JSON
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `oauth_auth_middleware` — Bearer Token + scope 验证
|
||||
2. `fhir/handler.rs` — 8 种资源类型路由分发
|
||||
3. `fhir/converter.rs` — 内部 Entity → FHIR R4 资源映射
|
||||
4. `fhir/types.rs` — FHIR 资源类型定义
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **$everything 无分页限制**: Observations 限 200 条,但 Devices/Encounters 无限,大数据量可能 OOM
|
||||
- **日期搜索不完整**: 仅支持 `gt`/`lt` 前缀,不支持 FHIR 标准的 `eq`/`ge`/`le`
|
||||
- **Bundle 缺 link 字段**: 不符合 FHIR R4 规范
|
||||
- **血压 observation ID 重复**: 拆分收缩压/舒张压时 ID 重复
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[外部 HIS/LIS] --> B[OAuth Bearer Token]
|
||||
B --> C[FHIR Handler]
|
||||
C --> D[Converter 转换]
|
||||
D --> E[FHIR R4 Bundle JSON]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DF9: OAuth 授权 → 令牌 → API 调用
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `oauth/service.rs::create_client` — 管理员创建 client (Argon2 哈希 secret)
|
||||
2. `POST /oauth/token` — Client Credentials Grant
|
||||
3. `oauth/service.rs::verify_client` — Argon2 验证 + scope 校验
|
||||
4. `JWT 签发` — 含 tenant_id + scope + allowed_patient_ids
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **[高危] allowed_patient_ids 未在查询时强制执行**: 第三方应用可能越权访问非授权患者数据
|
||||
- **[中危] JWT Secret 硬编码 fallback**: `"dev-secret-key"` 生产环境可能被误用
|
||||
- **[中危] 速率限制仅存储未执行**: `rate_limit_per_minute` 存在但无 middleware
|
||||
- 仅支持 Client Credentials,无 Authorization Code/PKCE
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[管理员创建 Client] --> B[第三方 POST /oauth/token]
|
||||
B --> C[Argon2 验证]
|
||||
C --> D[JWT 签发]
|
||||
D --> E[FHIR API 调用]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DF10: 积分签到 → 事务 → 余额更新
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `points_handler::daily_checkin` — 权限校验
|
||||
2. `points_service::daily_checkin` — 事务内: 签到记录 + 积分规则 + 流水 + 余额 CAS 更新 + 阶梯奖励
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **无事件发布/通知推送**: 签到成功后不发布 DomainEvent
|
||||
- **连续天数计算脆弱**: 仅查前一天记录,DB 写入失败导致连续天数断裂且无法恢复
|
||||
- **阶梯奖励 CAS 冲突**: 代码已通过重新查询规避
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[MP 签到] --> B[事务开始]
|
||||
B --> C[签到记录]
|
||||
C --> D[积分流水]
|
||||
D --> E[余额 CAS 更新]
|
||||
E --> F[阶梯奖励]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DF11: 随访完成 → 再分析触发 → 前后对比
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `follow_up_service::complete_task` — 事务(PII 加密+记录+状态更新)
|
||||
2. `EventBus::publish(FOLLOW_UP_COMPLETED)` — 发布完成事件
|
||||
3. `事件消费` — 反查关联 AI 建议 → 发布 `ai.reanalysis.requested`
|
||||
4. `reanalysis.rs` — **仅日志,对比功能未实现**
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **[功能缺失] 前后对比未实现**: `reanalysis.rs` 注释写明"后续在 comparison.rs 中实现完整对比逻辑"
|
||||
- **baseline_snapshot 无写入入口**: 代码读取了该字段但未找到首次 AI 分析时的写入逻辑
|
||||
- **[中危] 再分析触发无幂等保护**: 同一事件重复消费可能多次触发 AI 分析
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[护士完成随访] --> B[FOLLOW_UP_COMPLETED]
|
||||
B --> C[反查 AI 建议]
|
||||
C --> D[ai.reanalysis.requested]
|
||||
D --> E{reanalysis.rs}
|
||||
E -->|现状| F[仅日志/TODO]
|
||||
E -->|目标| G[前后对比报告]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DF12: BLE 网关批量上传 → 多患者批量处理
|
||||
|
||||
### 调用链
|
||||
|
||||
1. `POST /health/gateway/upload` + API Key → `gateway_auth_middleware`(SHA-256 验证)
|
||||
2. `ble_gateway_service::process_gateway_upload` — 逐患者 for 循环
|
||||
3. `device_reading_service::batch_create_readings` — 验证+批量插入+双写+降采样+事件
|
||||
|
||||
### 发现的问题
|
||||
|
||||
- **串行处理多患者**: for 循环逐个处理,延迟为所有患者处理时间之和
|
||||
- **降采样效率低**: 查出全量 hourly 记录再内存匹配,未按时间范围过滤
|
||||
- **[中危] 双写 vital_signs 失败静默忽略**: 仅 warn 日志,可能导致数据不一致
|
||||
- 心跳端点无审计日志
|
||||
|
||||
### Mermaid
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[BLE 网关 POST] --> B[API Key 验证]
|
||||
B --> C[for 患者循环]
|
||||
C --> D[batch_create_readings]
|
||||
D --> E[insert_many]
|
||||
D --> F[双写 vital_signs]
|
||||
D --> G[降采样 hourly]
|
||||
```
|
||||
122
docs/audits/v2/04-backend-integrity.md
Normal file
122
docs/audits/v2/04-backend-integrity.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# HMS 后端完整性审计
|
||||
|
||||
> 审计范围: `crates/erp-health/src/`
|
||||
> 审计日期: 2026-05-04
|
||||
|
||||
---
|
||||
|
||||
## 1. Handler → Service 覆盖率
|
||||
|
||||
Handler 目录共 29 个业务文件(不含 mod.rs)。逐一比对 service/ 目录:
|
||||
|
||||
| Handler 文件 | 对应 Service | 状态 |
|
||||
|---|---|---|
|
||||
| action_inbox_handler.rs | action_inbox_service.rs | OK |
|
||||
| alert_handler.rs | alert_service.rs | OK |
|
||||
| alert_rule_handler.rs | alert_rule_service.rs | OK |
|
||||
| appointment_handler.rs | appointment_service.rs | OK |
|
||||
| article_category_handler.rs | article_category_service.rs | OK |
|
||||
| article_handler.rs | article_service.rs | OK |
|
||||
| article_tag_handler.rs | article_tag_service.rs | OK |
|
||||
| ble_gateway_handler.rs | ble_gateway_service.rs | OK |
|
||||
| care_plan_handler.rs | care_plan_service.rs | OK |
|
||||
| consent_handler.rs | consent_service.rs | OK |
|
||||
| consultation_handler.rs | consultation_service.rs | OK |
|
||||
| critical_alert_handler.rs | critical_alert_service.rs | OK |
|
||||
| critical_value_threshold_handler.rs | critical_value_threshold_service.rs | OK |
|
||||
| daily_monitoring_handler.rs | daily_monitoring_service.rs | OK |
|
||||
| device_handler.rs | device_service.rs | OK |
|
||||
| device_reading_handler.rs | device_reading_service.rs | OK |
|
||||
| diagnosis_handler.rs | diagnosis_service.rs | OK |
|
||||
| doctor_handler.rs | doctor_service.rs | OK |
|
||||
| family_proxy_handler.rs | family_proxy_service.rs | OK |
|
||||
| follow_up_handler.rs | follow_up_service.rs | OK |
|
||||
| follow_up_template_handler.rs | follow_up_template_service.rs | OK |
|
||||
| health_data_handler.rs | health_data_service/ | OK |
|
||||
| medication_record_handler.rs | medication_record_service.rs | OK |
|
||||
| medication_reminder_handler.rs | medication_reminder_service.rs | OK |
|
||||
| patient_handler.rs | patient_service/ | OK |
|
||||
| points_handler.rs | points_service/ | OK |
|
||||
| shift_handler.rs | shift_service.rs | OK |
|
||||
| stats_handler.rs | stats_service/ | OK |
|
||||
| vital_signs_daily_handler.rs | vital_signs_daily_service.rs | OK |
|
||||
|
||||
**缺失: 0** — 所有 handler 均有对应 service。
|
||||
|
||||
> 注: FHIR handler 位于独立模块 `src/fhir/handler.rs`,不经过 service 层,直接调用
|
||||
> `fhir/converter.rs` 转换后查询。此为合理架构,不视为缺失。
|
||||
|
||||
---
|
||||
|
||||
## 2. 冗余代码统计
|
||||
|
||||
| 指标 | 数量 | 详情 |
|
||||
|---|---|---|
|
||||
| `#[allow(dead_code)]` | **4** | action_inbox_service.rs (3), stats_service/health.rs (1) |
|
||||
| `#[allow(unused...)]` | **0** | — |
|
||||
| `todo!()` | **0** | — |
|
||||
| `unimplemented!()` | **0** | — |
|
||||
| `TODO` / `FIXME` / `HACK` 注释 | **1** | `src/event.rs:51` — TODO: 患者认证和死亡记录流程待后续迭代 |
|
||||
|
||||
**结论**: 冗余代码极少,代码库健康。建议清理 4 处 `dead_code` 标注。
|
||||
|
||||
---
|
||||
|
||||
## 3. unwrap() 风险分析
|
||||
|
||||
service/ 目录共 16 处 `.unwrap()`,按上下文分类:
|
||||
|
||||
### 生产代码中的 unwrap (高风险)
|
||||
|
||||
| 文件 | 行号 | 代码 | 风险 |
|
||||
|---|---|---|---|
|
||||
| action_inbox_service.rs | L306 | `user_id.unwrap()` | **高** — SQL 注入 + panic 风险 |
|
||||
| vital_signs_daily_service.rs | L14, L92 | `date.and_hms_opt(0,0,0).unwrap()` | **低** — 固定参数不会失败,但应改用 `expect()` |
|
||||
| vital_signs_daily_service.rs | L15, L93 | `date.and_hms_opt(23,59,59).unwrap()` | **低** — 同上 |
|
||||
| vital_signs_daily_service.rs | L115 | `.partial_cmp(b).unwrap()` | **中** — NaN 时 panic |
|
||||
|
||||
### 测试代码中的 unwrap (可接受)
|
||||
|
||||
| 文件 | 数量 |
|
||||
|---|---|
|
||||
| alert_service.rs | 3 处 |
|
||||
| trend_stats.rs | 6 处 |
|
||||
|
||||
**建议优先修复**:
|
||||
1. `action_inbox_service.rs:306` — `user_id.unwrap()` 同时存在 SQL 注入风险
|
||||
(直接拼接 SQL 字符串),应改用参数化查询 + `ok_or(AppError)` 模式
|
||||
2. `vital_signs_daily_service.rs:115` — 浮点比较改用 `unwrap_or(Ordering::Equal)`
|
||||
|
||||
---
|
||||
|
||||
## 4. DTO 覆盖检查
|
||||
|
||||
针对 5 个新增模块逐一检查:
|
||||
|
||||
| 模块 | Handler 位置 | DTO 文件 | 状态 |
|
||||
|---|---|---|---|
|
||||
| care_plan | handler/care_plan_handler.rs | dto/care_plan_dto.rs | **有** |
|
||||
| shift | handler/shift_handler.rs | dto/shift_dto.rs | **有** |
|
||||
| ble_gateway | handler/ble_gateway_handler.rs | dto/ble_gateway_dto.rs | **有** |
|
||||
| action_inbox | handler/action_inbox_handler.rs | 内嵌于 service (ActionItem 等 12 个结构体) | **无独立 DTO** |
|
||||
| fhir | fhir/handler.rs + fhir/types.rs | fhir/types.rs | **有** (模块内自带) |
|
||||
|
||||
**说明**:
|
||||
- `action_inbox` 的 DTO 类型 (ActionItem, ThreadResponse, ActionInboxQuery 等)
|
||||
定义在 `action_inbox_service.rs` 中而非独立 dto 文件。建议抽取到
|
||||
`dto/action_inbox_dto.rs` 以保持一致性。
|
||||
- `fhir` 模块在 `fhir/types.rs` 中定义了自己的 FHIR 资源类型,无需在 dto/ 目录
|
||||
重复定义。
|
||||
|
||||
---
|
||||
|
||||
## 汇总
|
||||
|
||||
| 检查项 | 结果 | 严重度 |
|
||||
|---|---|---|
|
||||
| Handler→Service 覆盖 | 29/29 完整 | — |
|
||||
| 冗余代码 | 4 dead_code + 1 TODO | 低 |
|
||||
| unwrap 风险 | 5 处生产代码 | action_inbox **高**, 其余低 |
|
||||
| DTO 覆盖 | 5/5 模块均已有定义 | action_inbox 建议抽取 |
|
||||
|
||||
**最高优先级修复**: `action_inbox_service.rs:306` 的 `unwrap()` + SQL 拼接问题。
|
||||
127
docs/audits/v2/05-security-performance.md
Normal file
127
docs/audits/v2/05-security-performance.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# V2 审计 — 安全合规与性能审计
|
||||
|
||||
> 日期: 2026-05-04
|
||||
|
||||
## 一、安全审计
|
||||
|
||||
### S1: SQL 注入防护 — 存在高危漏洞
|
||||
|
||||
| 编号 | 严重度 | 问题 | 位置 |
|
||||
|------|--------|------|------|
|
||||
| **SEC-01** | **高** | `patient_id`/`user_id` 通过 `format!` 拼接进 SQL | `action_inbox_service.rs:272-306` |
|
||||
| SEC-01a | 低 | 迁移种子 SQL 使用 `format!` | 迁移文件(硬编码 UUID,风险极低) |
|
||||
| -- | 安全 | `erp-plugin` 动态表操作 | `sanitize_identifier()` 40+ 处调用,覆盖完整 |
|
||||
|
||||
**SEC-01 详情**:
|
||||
```rust
|
||||
// action_inbox_service.rs 第 272-306 行
|
||||
let patient_filter = match &query.patient_id {
|
||||
Some(pid) => format!("AND patient_id = '{}'", pid), // 直接拼接!
|
||||
None => String::new(),
|
||||
};
|
||||
let assigned_filter = format!("AND f.assigned_to = '{}'", user_id.unwrap()); // 直接拼接!
|
||||
```
|
||||
|
||||
`tenant_id` 已正确使用 `$1` 参数化,但 `patient_id` 和 `user_id` 未参数化。虽然来源是已认证用户的上下文(非直接用户输入),但仍违反安全规范。
|
||||
|
||||
**修复**: 改为 `Statement::from_sql_and_values` 参数化绑定。
|
||||
|
||||
### S2: PII 加密覆盖 — 合规
|
||||
|
||||
AES-256-GCM + 随机 nonce + v1 前缀 + Zeroizing 密钥。
|
||||
|
||||
| Entity | 加密字段 |
|
||||
|--------|---------|
|
||||
| patient | id_number, phone, address, emergency_contact, emergency_phone |
|
||||
| family_member | phone |
|
||||
| doctor_profile | license_number |
|
||||
| consultation_message | content |
|
||||
| follow_up_record | result, plan, medication_notes |
|
||||
| diagnosis | note, value |
|
||||
| lab_report | report_content, conclusion |
|
||||
| medication_record | note, value |
|
||||
|
||||
**结论**: 所有 PII 字段均已加密。解密使用 `unwrap_or` 降级兼容旧数据。
|
||||
|
||||
### S3: API Key 安全 (BLE 网关) — 合格
|
||||
|
||||
- 存储: SHA-256 哈希 + 前 8 位前缀双因子
|
||||
- 生成: `OsRng` 32 字节随机密钥
|
||||
- 传输: `Authorization: Gateway <key>` 或 `X-Gateway-Key` 头
|
||||
- **不足**: 代码层未强制 HTTPS,需在反向代理层配置 TLS
|
||||
|
||||
### S4: OAuth 安全 — 部分合规
|
||||
|
||||
| 检查项 | 状态 |
|
||||
|--------|------|
|
||||
| scope 验证 | 合规 — 白名单校验 |
|
||||
| client_secret 存储 | 合规 — Argon2 哈希 |
|
||||
| 速率限制 | 已建模,未强制执行 |
|
||||
| PKCE | 不支持(仅 Client Credentials) |
|
||||
| redirect_uri | 不适用 |
|
||||
|
||||
### S5: 多租户隔离 — 合规(有一处增强建议)
|
||||
|
||||
- 应用层: 所有 handler 带 `ctx.tenant_id` 过滤
|
||||
- 数据库层: PostgreSQL RLS 在所有含 tenant_id 表上启用
|
||||
- SSE: 验证 `event.tenant_id != tenant_id` 跳过非本租户事件
|
||||
- **不足**: FHIR `allowed_patient_ids` 在 JWT claims 中携带但未在查询层强制执行
|
||||
|
||||
### S6: 权限码一致性 — 存在缺失
|
||||
|
||||
| 编号 | 严重度 | 问题 |
|
||||
|------|--------|------|
|
||||
| **SEC-02** | **中** | OAuth 管理 handler(5 个端点)未调用 `require_permission()` |
|
||||
|
||||
所有其他 53 个 PermissionDescriptor 声明的权限码均有对应 `require_permission` 调用。
|
||||
|
||||
### S7: XSS 防护 — 合规
|
||||
|
||||
Web 和 MP 中均未发现 `dangerouslySetInnerHTML` 或 `innerHTML` 使用。
|
||||
|
||||
### S8: SSE 认证 — 合规
|
||||
|
||||
- AI SSE: JSON POST + `TenantContext` + `require_permission`
|
||||
- 消息 SSE: JWT `?token=xxx` query param 回退 + tenant_id 验证
|
||||
|
||||
## 二、性能审计
|
||||
|
||||
### P1: N+1 查询 — 低风险
|
||||
|
||||
未发现典型 N+1 模式。告警引擎 `for rule in rules` 循环中有额外 DB 查询,但规则数量通常个位数。
|
||||
|
||||
### P2: 分页覆盖率 — 高
|
||||
|
||||
- 使用 `PaginationParams` 的 handler: 11 个文件
|
||||
- 自定义分页: alert, action_inbox, patient
|
||||
- 无分页: doctors, devices, tags, categories, consents, rules, templates, thresholds(通常数据量小)
|
||||
|
||||
### P3: AI 缓存 — 未启用
|
||||
|
||||
`AnalysisService::find_cached()` 方法存在但仅用于测试。生产流程未调用。`ai_usage.is_cache_hit` 字段已预留。
|
||||
|
||||
| 编号 | 严重度 | 问题 |
|
||||
|------|--------|------|
|
||||
| **PERF-01** | **中** | AI 分析缓存功能存在但未启用 |
|
||||
|
||||
### P4: 索引覆盖率 — 合规
|
||||
|
||||
最近 19 个迁移新增 22 个索引,覆盖所有新表。所有新表均含 `tenant_id` 索引。
|
||||
|
||||
### P5: 批量操作 — 高效
|
||||
|
||||
- 设备数据: `insert_many` + `ON CONFLICT DO NOTHING`
|
||||
- 随访: `batch_create/assign/complete`
|
||||
- 插件: `batch_delete/update` 使用 `IN (...)`
|
||||
|
||||
## 三、问题汇总
|
||||
|
||||
| 编号 | 严重度 | 类型 | 问题 | 位置 |
|
||||
|------|--------|------|------|------|
|
||||
| SEC-01 | **高** | 注入 | SQL `format!` 拼接 patient_id/user_id | action_inbox_service.rs:272-306 |
|
||||
| SEC-02 | **中** | 权限 | OAuth handler 缺少 require_permission | oauth/handler.rs (5 端点) |
|
||||
| SEC-03 | **中** | 越权 | FHIR allowed_patient_ids 未在查询层执行 | fhir/handler.rs |
|
||||
| SEC-04 | **低** | 配置 | JWT secret dev fallback 硬编码 | oauth/middleware.rs:67 |
|
||||
| SEC-05 | **低** | 限流 | rate_limit_per_minute 已建模未执行 | oauth/service.rs |
|
||||
| PERF-01 | **中** | 缓存 | AI 分析缓存未启用 | erp-ai/service/analysis.rs |
|
||||
| PERF-02 | **低** | 分页 | 部分列表端点缺分页 | 各 handler |
|
||||
50
docs/audits/v2/06-gap-patterns-refresh.md
Normal file
50
docs/audits/v2/06-gap-patterns-refresh.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Phase 6: 差距模式重验
|
||||
|
||||
审计日期: 2026-05-04
|
||||
|
||||
## 1. 写了没接(后端有实现,前端无调用)
|
||||
|
||||
| 模块 | 后端 | Web 前端 | MP 前端 | 状态 |
|
||||
|------|------|----------|---------|------|
|
||||
| 护理计划 | handler + service 完整 | **无 API 文件**,仅 NurseWorkbench/ConsultationDetail 提及"shift"字样(非调用) | **无** | FAIL |
|
||||
| 班次管理 | shift_handler + shift_service | **无 API 文件,无调用** | **无** | FAIL |
|
||||
| BLE 网关 | ble_gateway_handler + ble_gateway_service | **无 API 文件** | DataBuffer.ts 仅 BLE 数据层引用 | FAIL(外部系统调用除外) |
|
||||
| 家庭代理 | family_proxy_handler + family_proxy_service | **无 API 文件** | **无** | FAIL |
|
||||
| 药物记录 | medication_record_handler + medication_record_service | **无 API 文件** | 仅有 medication-reminder(提醒),无记录 CRUD | FAIL |
|
||||
|
||||
**结论**: 5 个模块后端均已实现,但 Web 和 MP 均无前端调用入口。护理计划 outcome 的 CRUD(create/update/delete)虽有后端路由,但前端无法触发。
|
||||
|
||||
## 2. 接了没传
|
||||
|
||||
| 检查项 | 状态 |
|
||||
|--------|------|
|
||||
| MP 体温/血氧字段映射 | PASS(已确认) |
|
||||
| MP 晚间血压 | PASS(已确认) |
|
||||
| 透析表单字段完整性 | **PASS** — dialysis.ts 包含完整字段(体重、血压、心率、超滤量等),CreateDialysisRecordReq 与后端一致 |
|
||||
| 知情同意 | **无 Web 前端**,MP 有 consent 服务 + 页面 |
|
||||
| 诊断 | **无 Web 前端**,MP 有 diagnoses 页面 + health-record 服务 |
|
||||
|
||||
## 3. 传了没存
|
||||
|
||||
| 检查项 | 状态 |
|
||||
|--------|------|
|
||||
| 护理计划 outcome current 值更新 | 后端 `update_care_plan_outcome` 支持传入 `current_value`,**但无前端入口触发** |
|
||||
| AI 建议 execute 端点 | Web `suggestionApi` 仅有 list/approve/getComparison,**无 execute 调用**;MP `listPendingSuggestions` 也无 execute |
|
||||
|
||||
## 4. 存了没用
|
||||
|
||||
| 检查项 | 状态 |
|
||||
|--------|------|
|
||||
| 事件消费者覆盖率 | event.rs 中定义 31 个事件常量,注册 23 个消费者(consumer_id 唯一),覆盖主要业务流程。**未覆盖**: ARTICLE_PUBLISHED/REJECTED、DOCTOR_ONLINE_STATUS_CHANGED、DAILY_MONITORING_CREATED、CARE_PLAN_*(4个)、CARE_ACTION_PERFORMED(共 8 个事件无消费者) |
|
||||
| AI 缓存 find_cached | **不存在**,整个 crate 中无此函数 |
|
||||
| vital_signs_daily 查询 | Web 有 `deviceReadings.ts` 中的 `/health/vital-signs/daily` 查询端点;MP **无查询入口** |
|
||||
|
||||
## 5. 双系统不同步
|
||||
|
||||
| 功能 | Web | MP | 差距 |
|
||||
|------|-----|-----|------|
|
||||
| 透析管理 | dialysis.ts API + DialysisManageList 页面(CRUD+审核) | doctor/dialysis + pkg-profile/dialysis-*(创建/详情/列表/记录) | **基本对等** |
|
||||
| 知情同意 | **无** | consent 服务 + consents 页面 | Web 缺失 |
|
||||
| 健康记录/诊断 | **无** | diagnoses 页面 + health-record 服务 | Web 缺失 |
|
||||
| AI 建议 | suggestions.ts(list/approve/comparison)+ AiAnalysisList/AiSuggestionTab | ai-analysis.ts(list + listPendingSuggestions) | MP 无 approve/execute,Web 无 execute |
|
||||
| Action Inbox | actionInbox.ts + ActionInbox 页面 | action-inbox.ts(list + thread) | **基本对等** |
|
||||
54
docs/audits/v2/07-observability.md
Normal file
54
docs/audits/v2/07-observability.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Phase 7: 日志与可观测性
|
||||
|
||||
审计日期: 2026-05-04
|
||||
|
||||
## 1. Service 层 tracing 总览
|
||||
|
||||
`crates/erp-health/src/service/` 中 tracing::info/warn/error 总计 **116 次**,分布在 17 个文件中。
|
||||
|
||||
分布明细(按文件):
|
||||
- lab_report (health_data_service): 16
|
||||
- action_inbox_service: 14
|
||||
- follow_up_service: 13
|
||||
- vital_signs (health_data_service): 12
|
||||
- health_record (health_data_service): 12
|
||||
- consultation_service: 10
|
||||
- relation (patient_service): 8
|
||||
- crud (patient_service): 8
|
||||
- tag (patient_service): 4
|
||||
- seed: 4
|
||||
- points_service/event: 2
|
||||
- appointment_service: 2
|
||||
- family_proxy_service: 3
|
||||
- alert (health_data_service): 3
|
||||
- critical_alert_service: 3
|
||||
- alert_noise_reducer: 1
|
||||
- device_reading_service: 1
|
||||
|
||||
## 2. 新增 service 文件 tracing 覆盖
|
||||
|
||||
| 文件 | tracing 次数 | 状态 |
|
||||
|------|-------------|------|
|
||||
| action_inbox_service.rs | 14 | OK |
|
||||
| care_plan_service.rs | **0** | **缺失** |
|
||||
| shift_service.rs | **0** | **缺失** |
|
||||
| ble_gateway_service.rs | **0** | **缺失** |
|
||||
| family_proxy_service.rs | 3 | OK |
|
||||
| vital_signs_daily_service.rs | **0** | **缺失** |
|
||||
|
||||
**4/6 新增 service 无任何 tracing 日志**。care_plan、shift、ble_gateway、vital_signs_daily 完全没有可观测性覆盖。
|
||||
|
||||
## 3. 新增错误类型
|
||||
|
||||
### OAuth Error
|
||||
文件: `crates/erp-health/src/oauth/error.rs`
|
||||
枚举 `OAuthError` 包含 7 个变体: InvalidClient, ClientInactive, InvalidScope, UnsupportedGrantType, RateLimitExceeded, ClientNotFound, DbError, HashError, JwtError。完整实现了 `From<OAuthError> -> AppError` 和 `From<DbErr> -> OAuthError`。
|
||||
|
||||
### FHIR Error
|
||||
**不存在**。整个 erp-health crate 中无 FHIR 相关错误类型定义。
|
||||
|
||||
## 4. 建议
|
||||
|
||||
1. 为 care_plan_service、shift_service、ble_gateway_service、vital_signs_daily_service 补充关键操作的 tracing::info/error
|
||||
2. 考虑引入 FHIR 错误类型(如需对接 FHIR 标准)
|
||||
3. 建议在 service 层关键入口统一添加 tracing span
|
||||
57
docs/audits/v2/08-test-coverage-refresh.md
Normal file
57
docs/audits/v2/08-test-coverage-refresh.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Phase 8: 测试覆盖率刷新
|
||||
|
||||
审计日期: 2026-05-04
|
||||
|
||||
## 1. Web 测试文件统计
|
||||
|
||||
`apps/web/src` 中 `*.test.*` 文件共 **59 个**,覆盖:
|
||||
- API 测试: 17 个(health api、auth、users、roles、orgs、dictionaries、config-modules、messages、workflow、auditLogs、pluginData、plugins)
|
||||
- Store 测试: 5 个(auth、health、app、message、workbenchStore、plugin)
|
||||
- 页面测试: 22 个(PatientList、AlertList、DoctorList、AppointmentList 等)
|
||||
- 工具/钩子测试: 4 个(useThemeMode、useDebouncedValue、exprEvaluator、renderWithProviders)
|
||||
- 常量测试: 1 个(health.test.ts)
|
||||
|
||||
## 2. 新增功能测试覆盖
|
||||
|
||||
| 模块 | 测试文件 | 状态 |
|
||||
|------|---------|------|
|
||||
| care_plan | **无** | **缺失** |
|
||||
| shift | **无** | **缺失** |
|
||||
| ble_gateway | **无** | **缺失** |
|
||||
| action_inbox | dashboard.test.ts 中间接覆盖 | 部分覆盖 |
|
||||
| family_proxy | **无** | **缺失** |
|
||||
| oauth | OAuthClientList.test.tsx | OK |
|
||||
| fhir | OAuthClientList.test.tsx(同上,OAuth 页面) | 部分覆盖 |
|
||||
| dialysis | DialysisManageList.test.tsx | OK |
|
||||
| AI 分析 | AiAnalysisList.test.tsx | OK |
|
||||
|
||||
**5/7 新增模块无专属测试文件**: care_plan、shift、ble_gateway、family_proxy、fhir 无独立测试。
|
||||
|
||||
## 3. MP 测试状态
|
||||
|
||||
`apps/miniprogram/__tests__/` 中仅 **4 个测试文件**,全部为 BLE 相关:
|
||||
- BLEManager.test.ts
|
||||
- DataBuffer.test.ts
|
||||
- DataSyncScheduler.test.ts
|
||||
- GenericBleAdapter.test.ts
|
||||
|
||||
**新增业务功能(dialysis、consent、diagnosis、action-inbox、AI suggestion)无任何测试文件。**
|
||||
|
||||
确认 MP 测试覆盖: 业务层 **0**,仅 BLE 基础设施层有测试。
|
||||
|
||||
## 4. 后端测试补充
|
||||
|
||||
`crates/erp-health/src/event.rs` 包含 **40+ 个单元测试**,覆盖:
|
||||
- 事件类型常量校验(命名规范、唯一性、值匹配)
|
||||
- 消费者前缀覆盖验证(13 个前缀覆盖测试)
|
||||
- Payload 契约测试(10+ 个场景)
|
||||
- EventBus 过滤订阅行为测试
|
||||
- 消费者幂等 ID 唯一性
|
||||
|
||||
后端事件系统测试覆盖良好,但 **前端新增模块测试严重不足**。
|
||||
|
||||
## 5. 建议
|
||||
|
||||
1. 优先为 care_plan、shift、ble_gateway、family_proxy 补充 API 层测试
|
||||
2. MP 补充 dialysis/consent/diagnosis 服务层单元测试
|
||||
3. 考虑为新增页面添加组件渲染测试
|
||||
87
docs/audits/v2/10-ux-consistency.md
Normal file
87
docs/audits/v2/10-ux-consistency.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# UX 一致性审计(Web vs 小程序)
|
||||
|
||||
> 审计范围:`apps/web` vs `apps/miniprogram`,基于代码审查
|
||||
|
||||
## 1. 日期格式化
|
||||
|
||||
| 维度 | Web | 小程序 | 一致性 |
|
||||
|------|-----|--------|--------|
|
||||
| 库 | `dayjs` v1.11(含 relativeTime 插件、zh-cn locale) | **无第三方库**,原生 `Date` + `toLocaleDateString('zh-CN')` | **不一致** |
|
||||
| 日期格式 | `YYYY-MM-DD` / `YYYY-MM-DD HH:mm` / `fromNow()` | 每个页面独立实现 `formatDate()`,输出不统一 | **不一致** |
|
||||
| 空值处理 | 统一返回 `'--'` | 无统一空值处理 | **不一致** |
|
||||
|
||||
**问题**:MP 端有 6+ 处独立的 `formatDate` 实现(orders/events/daily-monitoring/doctor-report/followup 等),格式各异。Web 端通过 `utils/format.ts` 统一。
|
||||
|
||||
## 2. 数字格式化
|
||||
|
||||
| 维度 | Web | 小程序 |
|
||||
|------|-----|--------|
|
||||
| 方式 | `.toFixed(1)` / `.toFixed(2)` 散布在组件中 | TrendChart 中 `val.toFixed(1)` |
|
||||
| 统一工具 | **无** | **无** |
|
||||
|
||||
**问题**:两端均无统一的数字格式化工具。体重/血压等健康数值没有统一的精度标准(如保留 1 位还是 2 位小数)。
|
||||
|
||||
## 3. 状态标签
|
||||
|
||||
| 状态 | Web(Ant Tag) | MP(CSS class) | 文案一致? |
|
||||
|------|---------------|-----------------|-----------|
|
||||
| pending | `gold` "待确认" | `$wrn`(琥珀) "待确认" | **是** |
|
||||
| confirmed | `blue` "已确认" | `$acc`(鼠尾草绿) "已确认" | **色不同** |
|
||||
| completed | `green` "已完成" | `$pri`(赤土橙) "已完成" | **色不同** |
|
||||
| cancelled | `default` "已取消" | `$tx3`(灰) "已取消" | **是** |
|
||||
|
||||
**问题**:confirmed 和 completed 的语义色映射不一致。Web 用蓝/绿,MP 用绿/橙。MP 端无统一 StatusTag 组件,预约页和咨询页各自定义 `STATUS_MAP`。
|
||||
|
||||
## 4. 空状态
|
||||
|
||||
| 维度 | Web | 小程序 |
|
||||
|------|-----|--------|
|
||||
| 组件 | Ant Design `<Empty>` | 自研 `<EmptyState>` 组件 |
|
||||
| 文案 | "暂无数据"/"暂无消息"/"暂无待办" 等 10+ 种 | "暂无预约"/"暂无报告" 等 |
|
||||
| 图标 | Ant 内置简单图标 | Emoji(📭) |
|
||||
| 行动按钮 | 部分有 | 支持可选 `actionText` + `onAction` |
|
||||
|
||||
**结论**:结构基本一致,但图标风格不统一(Ant 图标 vs Emoji)。
|
||||
|
||||
## 5. 加载状态
|
||||
|
||||
| 维度 | Web | 小程序 |
|
||||
|------|-----|--------|
|
||||
| 组件 | Ant `<Spin>` | 自研 `<Loading>` 组件 |
|
||||
| 样式 | Ant 旋转圆环 + 可选文字 | 自定义 spinner + "加载中..." |
|
||||
| 全局 | Suspense fallback 用 Spin | 无全局加载 |
|
||||
|
||||
**结论**:基本一致,均为旋转动画 + 文字。
|
||||
|
||||
## 6. 错误提示
|
||||
|
||||
| 场景 | Web | 小程序 |
|
||||
|------|-----|--------|
|
||||
| 403 | `antMessage.error('权限不足')` | 无 403 专用处理 |
|
||||
| 404 | 静默(组件自行处理) | `<ErrorState text='未找到'>` |
|
||||
| 500 | `antMessage.error('服务器异常')` | 抛出 `'请求失败'` |
|
||||
| 运行时崩溃 | `<ErrorBoundary>` → Ant `Result` 页面 | `<ErrorBoundary>` → 自定义页面(emoji + 文字) |
|
||||
|
||||
**问题**:MP 端 `request.ts` 无 HTTP 状态码分支处理,所有非成功统一 `throw new Error(body.message)`。
|
||||
|
||||
## 7. 适老化(MP 端)
|
||||
|
||||
MP 设计系统 `variables.scss` 已定义老年友好参数:
|
||||
|
||||
- `$touch-min: 48px` — 满足 WCAG 最小触控
|
||||
- `$btn-primary-h: 56px` — 主按钮足够大
|
||||
- `$font-min: 22px` — 最小字号(约 11pt)
|
||||
|
||||
**实际检测**:部分页面存在 20px 以下字号(如 `WeekCalendar` 20px、`appointment` 20px),**低于 $font-min 阈值**。约 15 处 20-22px 的字号处于边界线。
|
||||
|
||||
**建议**:全局 audit 所有 < 22px 字号,确保不低于设计系统最低值。
|
||||
|
||||
---
|
||||
|
||||
## 优先修复建议
|
||||
|
||||
1. **P0** — MP 端引入 dayjs 或抽取统一 `formatDate` 工具,消除 6+ 处重复实现
|
||||
2. **P1** — 统一状态标签色值:confirmed(completed) 应两端语义一致
|
||||
3. **P1** — MP `request.ts` 增加 403/500 分支处理
|
||||
4. **P2** — 抽取统一数字格式化工具(精度标准:体重 1 位、血压 0 位、血糖 1 位)
|
||||
5. **P2** — MP 端将 < 22px 字号提升至 22px 以上
|
||||
98
docs/audits/v2/11-tech-debt.md
Normal file
98
docs/audits/v2/11-tech-debt.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# 技术债务清单
|
||||
|
||||
> 审计日期:2026-05-04 | 范围:`crates/*` + `apps/*`
|
||||
|
||||
## 1. `#[allow(dead_code)]` / `#[allow(unused` 抑制清单(17 处)
|
||||
|
||||
| 文件 | 行号 | 说明 |
|
||||
|------|------|------|
|
||||
| `erp-ai/service/reanalysis.rs` | :14 | FromQueryResult 映射字段 |
|
||||
| `erp-ai/provider/claude.rs` | :55,:66,:72,:74 | serde 反序列化字段(4 处) |
|
||||
| `erp-auth/service/wechat_service.rs` | :43 | WeChat 服务字段 |
|
||||
| `erp-plugin/host.rs` | :42,:44 | 插件宿主字段(2 处) |
|
||||
| `erp-plugin/data_service.rs` | :462,:775,:1173,:1536 | FromQueryResult chk/id/check_result 字段(4 处) |
|
||||
| `erp-server/middleware/rate_limit.rs` | :27 | 限流结构体字段 |
|
||||
| `erp-server/handlers/analytics.rs` | :11 | 客户端上报字段,待接入 |
|
||||
| `erp-health/service/action_inbox_service.rs` | :119,:131,:140 | FromQueryResult 映射字段(3 处) |
|
||||
| `erp-health/service/stats_service/health.rs` | :295 | FromQueryResult total 字段 |
|
||||
|
||||
**根因**:大量来自 SeaORM `FromQueryResult` 宏,字段必须声明但当前未读取。建议在 DTO 转换层使用 `_` 前缀或 `#[serde(skip)]`。
|
||||
|
||||
## 2. TODO / FIXME / HACK 注释(5 处)
|
||||
|
||||
| 文件 | 内容 |
|
||||
|------|------|
|
||||
| `erp-auth/handler/wechat_handler.rs:45` | TODO: 多租户微信登录需要设计租户解析策略 |
|
||||
| `erp-auth/handler/wechat_handler.rs:76` | TODO: 多租户微信登录需要设计租户解析策略(重复) |
|
||||
| `erp-plugin/data_service.rs:1075` | TODO: 未来版本添加 Redis 缓存层 |
|
||||
| `erp-health/event.rs:51` | TODO: 患者认证和死亡记录流程尚未实现 |
|
||||
| `web/pages/workflow/PendingTasks.tsx:208` | TODO: 替换为 UserSelect 用户搜索选择组件 |
|
||||
| `web/pages/health/components/ActionDetailDrawer.tsx:78` | TODO: 调用实际 API 执行操作 |
|
||||
|
||||
**风险**:wechat_handler 多租户策略未定,影响 SaaS 化路线。ActionDetailDrawer TODO 说明功能未接通。
|
||||
|
||||
## 3. 硬编码检测
|
||||
|
||||
### 3.1 `localhost` / `127.0.0.1`(14 处,排除 lock 文件)
|
||||
|
||||
| 文件 | 硬编码值 | 风险 |
|
||||
|------|---------|------|
|
||||
| `apps/web/vite.config.ts` | `localhost:3000` | 开发代理,可接受 |
|
||||
| `apps/web/playwright.config.ts` | `localhost:5174` | E2E,可接受 |
|
||||
| `apps/miniprogram/config/index.ts` | `localhost:3000` | **MP 构建默认值** |
|
||||
| `apps/miniprogram/src/services/request.ts` | `localhost:3000` | **MP 运行时 fallback** |
|
||||
| `apps/miniprogram/e2e/helpers/api-client.ts` | `localhost:3000` | E2E |
|
||||
| `apps/miniprogram/e2e/check-readiness.ts` | `localhost:3000` | E2E |
|
||||
| `apps/web/e2e/check-readiness.ts` | `localhost:3000` + `localhost:5174` | E2E |
|
||||
| `apps/web/e2e/fixtures/api-client.ts` | `localhost:3000` | E2E |
|
||||
| `apps/web/e2e/auth.fixture.ts` | `localhost:3000` | **无 env fallback,纯硬编码** |
|
||||
| `apps/web/e2e/fixtures/auth.fixture.ts` | `localhost:3000` | E2E |
|
||||
| `integration-tests/test_workflow_module.rs` | `localhost:3000` | 集成测试 |
|
||||
| `integration-tests/test_common.rs` | `localhost:3000` | 集成测试 |
|
||||
| `integration-tests/test_auth_module.rs` | `localhost:3000` | 集成测试 |
|
||||
| `erp-server/tests/integration/test_db.rs` | `localhost:5432` + 明文密码 | **安全风险** |
|
||||
| `erp-core/test_helpers.rs` | `localhost:5432` + 明文密码 | **安全风险** |
|
||||
|
||||
### 3.2 硬编码端口号
|
||||
|
||||
`3000`(API)、`5174`(Web dev)、`5432`(PostgreSQL) — 均为开发/测试用途,无生产风险。但 `test_db.rs` 中 `postgres:123123@localhost` 明文密码应移至 env。
|
||||
|
||||
## 4. 主要依赖版本
|
||||
|
||||
### 后端(Cargo.toml workspace)
|
||||
|
||||
| 依赖 | 版本 | 备注 |
|
||||
|------|------|------|
|
||||
| axum | 0.8 | 最新 stable |
|
||||
| sea-orm | 1.1 | 最新 |
|
||||
| tokio | 1 | LTS |
|
||||
| serde / serde_json | 1 / 1 | stable |
|
||||
| chrono | 0.4 | stable |
|
||||
| thiserror / anyhow | 2 / 1 | thiserror v2 |
|
||||
| utoipa | 5 | 最新 |
|
||||
| redis | 0.27 | — |
|
||||
| reqwest | 0.12 | — |
|
||||
|
||||
### 前端(apps/web/package.json)
|
||||
|
||||
| 依赖 | 版本 | 备注 |
|
||||
|------|------|------|
|
||||
| react | ^19.2 | React 19 |
|
||||
| antd | ^6.3 | Ant Design 6 |
|
||||
| react-router-dom | ^7.14 | React Router 7 |
|
||||
| dayjs | ^1.11 | — |
|
||||
| zustand | ^5.0 | — |
|
||||
| typescript | ~6.0 | TS 6 |
|
||||
| vite | ^8.0 | Vite 8 |
|
||||
|
||||
**结论**:依赖版本均较新,无重大过时风险。
|
||||
|
||||
---
|
||||
|
||||
## 优先修复建议
|
||||
|
||||
1. **P0** — `test_db.rs` / `test_helpers.rs` 明文数据库密码移至环境变量
|
||||
2. **P1** — `web/e2e/auth.fixture.ts` 硬编码 API 地址应加 env fallback
|
||||
3. **P1** — 清理 `wechat_handler.rs` 重复 TODO,明确多租户方案
|
||||
4. **P2** — 统一 SeaORM 查询结果的字段抑制策略(`_` 前缀或 helper 宏)
|
||||
5. **P2** — `ActionDetailDrawer` TODO 接通实际 API
|
||||
329
docs/audits/v2/12-expert-review.md
Normal file
329
docs/audits/v2/12-expert-review.md
Normal file
@@ -0,0 +1,329 @@
|
||||
# V2 审计 — 多角色专家评审
|
||||
|
||||
> 日期: 2026-05-04 | 方法: 5 角色专家审视,按 10 维度评分
|
||||
|
||||
## 一、评审概述
|
||||
|
||||
本报告由 5 个专家角色分别审视 HMS 系统的 20 个功能域,按统一评分框架打分。每个角色关注不同维度,最终汇总为系统级评价。
|
||||
|
||||
### 评审角色
|
||||
|
||||
| 角色 | 关注维度 | 权重 |
|
||||
|------|---------|------|
|
||||
| 产品经理 | D1 目标 + D3 连通 + D10 UX | 25% |
|
||||
| 技术架构师 | D2 代码 + D4 数据流 + D8 性能 | 25% |
|
||||
| 安全专家 | D5 安全 + D6 错误处理 | 20% |
|
||||
| DevOps 工程师 | D7 日志 + D8 性能 + D9 测试 | 15% |
|
||||
| 医疗领域专家 | D1 目标 + D4 数据流 + D10 UX | 15% |
|
||||
|
||||
### 评分方法
|
||||
|
||||
- 每个角色对每个功能域给出 0-100 分
|
||||
- 系统总分 = 各角色加权平均
|
||||
- 评级: A(90+) / B(80-89) / C(70-79) / D(60-69) / F(<60)
|
||||
|
||||
---
|
||||
|
||||
## 二、系统级总评
|
||||
|
||||
| 角色 | 评分 | 评级 |
|
||||
|------|------|------|
|
||||
| 产品经理 | 78 | C |
|
||||
| 技术架构师 | 70 | C |
|
||||
| 安全专家 | 65 | D |
|
||||
| DevOps 工程师 | 68 | D |
|
||||
| 医疗领域专家 | 75 | C |
|
||||
| **加权总分** | **72** | **C** |
|
||||
|
||||
> V1 审计未做专家评审,无法对比。72 分反映"后端完整但前端未接入、安全有漏洞、测试覆盖不足"的现状。
|
||||
|
||||
---
|
||||
|
||||
## 三、产品经理评审(78/C)
|
||||
|
||||
### 3.1 功能完整性 vs 客户需求
|
||||
|
||||
**已交付的核心价值链**(覆盖血透中心主要工作流):
|
||||
- 透析治疗全流程:预约→透析记录→KDIGO 风险评估(后端完整,前端部分接入)
|
||||
- 健康监测闭环:体征录入→阈值告警→SSE 推送→行动收件箱
|
||||
- 患者触达:小程序体征录入/查看/咨询/随访完成
|
||||
- AI 辅助决策:趋势分析 SSE + 建议系统(后端完整)
|
||||
|
||||
**未交付的关键体验**:
|
||||
- 护理计划/班次/BLE 网关/家庭代理 — 4 个模块 34 条路由完全无 UI,无法交付给客户
|
||||
- AI 前后对比功能 — 关怀闭环的核心价值,目前仅日志
|
||||
- MP 适老化不足 — 15 处字号低于 22px 阈值,老年患者体验差
|
||||
|
||||
### 3.2 MVP 边界评估
|
||||
|
||||
| 功能 | MVP 必须 | 当前状态 | 缺口 |
|
||||
|------|---------|---------|------|
|
||||
| 透析全流程 | 是 | 85% | 风险评分未自动串联 |
|
||||
| 健康监测 | 是 | 90% | 危急值阈值管理页缺失 |
|
||||
| 告警推送 | 是 | 80% | 双路径可能重复 |
|
||||
| 护理计划 | 否(P1) | 50%(仅后端) | 全部前端 |
|
||||
| 家庭代理 | 否(P2) | 50%(仅后端) | 全部前端 |
|
||||
| AI 报告 | 是 | 70% | 前后对比缺失 |
|
||||
|
||||
### 3.3 按域评分
|
||||
|
||||
| 域 | 分数 | 说明 |
|
||||
|----|------|------|
|
||||
| F1-F6 核心医疗 | 85 | 目标清晰,三端覆盖较好 |
|
||||
| F7-F8 内容/积分 | 75 | 非核心但完善 |
|
||||
| F9 告警 | 80 | 功能完整,UX 可优化 |
|
||||
| F10 AI | 70 | 后端强,前端弱,对比缺失 |
|
||||
| F11 透析 | 88 | MP 100% 覆盖,流程顺畅 |
|
||||
| F12 仪表盘 | 75 | 统计维度够但展示偏简 |
|
||||
| F13 行动收件箱 | 78 | SQL 注入风险影响交付 |
|
||||
| F14-F17 孤立模块 | 30 | 后端完整但无法交付 |
|
||||
| F18-F19 FHIR/OAuth | 55 | 基础设施,非 MVP 必需 |
|
||||
| F20 日聚合 | 72 | 数据层完整,展示层不足 |
|
||||
|
||||
---
|
||||
|
||||
## 四、技术架构师评审(70/C)
|
||||
|
||||
### 4.1 架构优势
|
||||
|
||||
1. **模块边界清晰** — 18 crate 严格通过 EventBus + trait 通信,无跨 crate 直接依赖
|
||||
2. **SeaORM Entity 统一标准** — 所有实体含 tenant_id/version/软删除/审计字段
|
||||
3. **事件驱动** — 51 个事件类型,outbox 模式保证可靠投递
|
||||
4. **PII 加密完备** — AES-256-GCM + HMAC 盲索引,覆盖所有敏感字段
|
||||
5. **服务拆分合理** — health_data_service 拆为 vital_signs/alert/daily_monitoring 等子模块
|
||||
|
||||
### 4.2 架构风险
|
||||
|
||||
| 风险 | 严重度 | 说明 |
|
||||
|------|--------|------|
|
||||
| SQL 注入 | **CRITICAL** | action_inbox_service.rs:272-306 format! 拼接 |
|
||||
| BLE 双写无事务 | **HIGH** | vital_signs 与 device_readings 可能不一致 |
|
||||
| 护理计划无事务 | **HIGH** | 三表写入无包裹,中间失败致孤立记录 |
|
||||
| SSE unbounded | MEDIUM | 告警风暴时内存压力 |
|
||||
| 串行处理多患者 | MEDIUM | BLE 网关 for 循环,延迟线性增长 |
|
||||
| 护理计划状态无枚举 | LOW | 自由字符串可写入非法状态 |
|
||||
|
||||
### 4.3 微服务拆分准备度
|
||||
|
||||
| 维度 | 准备度 | 说明 |
|
||||
|------|--------|------|
|
||||
| 模块独立性 | 90% | EventBus 解耦良好 |
|
||||
| 数据库拆分 | 70% | 共享 PostgreSQL,需 schema 分离 |
|
||||
| 认证独立 | 85% | JWT + middleware 已解耦 |
|
||||
| API 网关 | 40% | 无统一网关层 |
|
||||
| 服务发现 | 0% | 单体架构,未规划 |
|
||||
|
||||
### 4.4 按域评分
|
||||
|
||||
| 域 | 分数 | 说明 |
|
||||
|----|------|------|
|
||||
| F1-F6 核心医疗 | 78 | 代码结构好,数据流有缺口 |
|
||||
| F9 告警 | 72 | 双路径复杂度高 |
|
||||
| F10 AI | 68 | 缓存未启用,前后对比缺失 |
|
||||
| F13 行动收件箱 | 55 | SQL 注入拉低 |
|
||||
| F14-F17 孤立模块 | 40 | 代码存在但架构断裂 |
|
||||
| F18 FHIR | 50 | allowed_patient_ids 越权 |
|
||||
| F19 OAuth | 45 | 权限缺失 + JWT fallback |
|
||||
|
||||
---
|
||||
|
||||
## 五、安全专家评审(65/D)
|
||||
|
||||
### 5.1 安全合规状态
|
||||
|
||||
| 检查项 | 状态 | 说明 |
|
||||
|--------|------|------|
|
||||
| SQL 注入防护 | **FAIL** | action_inbox_service.rs format! 拼接 patient_id/user_id |
|
||||
| PII 加密 | **PASS** | AES-256-GCM,8 个实体全覆盖 |
|
||||
| 多租户隔离 | **PASS** | 应用层 tenant_id + PostgreSQL RLS |
|
||||
| 权限码完整性 | **WARN** | 53 个 Descriptor 声明,OAuth 5 端点缺失 |
|
||||
| API Key 安全 | **PASS** | SHA-256 哈希 + OsRng 随机生成 |
|
||||
| XSS 防护 | **PASS** | 未发现 dangerouslySetInnerHTML |
|
||||
| SSE 认证 | **PASS** | JWT query param + tenant_id 验证 |
|
||||
| JWT Secret | **WARN** | 硬编码 fallback "dev-secret-key" |
|
||||
| FHIR 越权 | **FAIL** | allowed_patient_ids 未在查询层执行 |
|
||||
| 速率限制 | **WARN** | 已建模未执行 |
|
||||
|
||||
### 5.2 合规风险评估
|
||||
|
||||
**《个人信息保护法》合规**:
|
||||
- PII 加密: 合规(AES-256-GCM)
|
||||
- 数据最小化: 基本合规(脱敏查看支持)
|
||||
- 第三方数据共享: 风险(FHIR allowed_patient_ids 未强制执行)
|
||||
- 审计日志: 合规(140+ 处审计记录)
|
||||
|
||||
**《健康医疗数据安全指南》合规**:
|
||||
- 数据分类分级: 部分合规(加密字段覆盖全,但分类标签缺失)
|
||||
- 数据出境: 不适用(私有部署)
|
||||
- 应急响应: 不合规(无安全事件自动告警机制)
|
||||
|
||||
### 5.3 按域评分
|
||||
|
||||
| 域 | 分数 | 关键问题 |
|
||||
|----|------|---------|
|
||||
| F13 行动收件箱 | 40 | SQL 注入(SEC-01) |
|
||||
| F18 FHIR | 50 | allowed_patient_ids 越权(SEC-03) |
|
||||
| F19 OAuth | 45 | 权限缺失(SEC-02)+ JWT fallback(SEC-04) |
|
||||
| F1-F6 核心医疗 | 85 | 权限+PII 完善 |
|
||||
| F9 告警 | 75 | SSE 认证 OK,无特殊风险 |
|
||||
| F16 BLE 网关 | 70 | API Key 安全 OK,HTTPS 需反向代理 |
|
||||
|
||||
---
|
||||
|
||||
## 六、DevOps 工程师评审(68/D)
|
||||
|
||||
### 6.1 可观测性评估
|
||||
|
||||
| 维度 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| tracing 覆盖 | **70%** | 17 个 service 文件 116 处 tracing,4/6 新增 service 零覆盖 |
|
||||
| 审计日志 | **85%** | 140+ 处,覆盖所有关键操作 |
|
||||
| 错误监控 | **60%** | AppError 统一响应,但无外部告警(Sentry/Datadog) |
|
||||
| 性能指标 | **30%** | 无 Prometheus/Grafana 集成 |
|
||||
| 分布式追踪 | **0%** | 无 OpenTelemetry |
|
||||
|
||||
### 6.2 部署复杂度
|
||||
|
||||
| 组件 | 复杂度 | 说明 |
|
||||
|------|--------|------|
|
||||
| 后端服务 | 中 | 单 Axum 进程,cargo run 即可 |
|
||||
| 数据库 | 低 | PostgreSQL + SeaORM 自动迁移 |
|
||||
| 前端 Web | 低 | Vite SPA,pnpm build |
|
||||
| 小程序 | 中 | Taro 编译 + 微信审核 |
|
||||
| 插件系统 | 高 | WASM 编译 + 热加载 |
|
||||
| 基础设施 | 中 | Docker Compose 一键启动 |
|
||||
|
||||
### 6.3 测试覆盖评估
|
||||
|
||||
| 层 | 覆盖率 | 说明 |
|
||||
|----|--------|------|
|
||||
| 后端单元+集成 | **80%+** | 772 测试函数,97.5% 通过 |
|
||||
| Web 前端 | **15%** | 62 文件,但断言深度未知 |
|
||||
| MP 小程序 | **0%** | 40+ 页面零测试 |
|
||||
| E2E | **5%** | 仅 5 个 Playwright spec |
|
||||
| 新增模块 | **0%** | care_plan/shift/ble_gateway/family_proxy 零测试 |
|
||||
|
||||
### 6.4 按域评分
|
||||
|
||||
| 域 | 分数 | 说明 |
|
||||
|----|------|------|
|
||||
| F1-F6 核心医疗 | 72 | 后端测试好,前端弱 |
|
||||
| F14-F17 新增模块 | 30 | 零测试+零日志 |
|
||||
| F10 AI | 55 | 集成测试有,E2E 无 |
|
||||
| F18 FHIR | 25 | 零测试 |
|
||||
| F19 OAuth | 30 | 零测试 |
|
||||
|
||||
---
|
||||
|
||||
## 七、医疗领域专家评审(75/C)
|
||||
|
||||
### 7.1 临床工作流合理性
|
||||
|
||||
**透析全流程**(核心工作流):
|
||||
- 预约→透析记录→干体重/超滤量/血流量记录 → 合理
|
||||
- KDIGO 风险评分 → 有价值,但未自动串联 → 效率低
|
||||
- 透析间期监测(体征录入)→ 合理,MP 支持好
|
||||
|
||||
**随访工作流**:
|
||||
- 随访任务创建→分配→执行→记录 → 标准化流程,合理
|
||||
- AI 建议关联随访 → 设计好,但前后对比未实现,闭环断裂
|
||||
- 批量随访操作后端有但前端未调用 → 限制效率
|
||||
|
||||
**护理工作流**:
|
||||
- 护理计划→项目→预后 → 概念正确
|
||||
- 班次→交接班 → 血透中心刚需
|
||||
- 但两个模块完全无 UI → 无法使用
|
||||
|
||||
### 7.2 FHIR 标准合规性
|
||||
|
||||
| R4 要求 | 状态 | 说明 |
|
||||
|---------|------|------|
|
||||
| 资源类型覆盖 | **60%** | Patient/Observation/Encounter/Device,缺少 Condition/MedicationRequest |
|
||||
| Bundle 结构 | **70%** | 缺 link 字段 |
|
||||
| 搜索参数 | **50%** | 仅支持 gt/lt,缺 eq/ge/le |
|
||||
| $everything 操作 | **40%** | 无分页限制,血压 ID 重复 |
|
||||
| OAuth2 保护 | **60%** | Client Credentials OK,缺 Authorization Code |
|
||||
|
||||
### 7.3 患者安全评估
|
||||
|
||||
| 风险 | 严重度 | 说明 |
|
||||
|------|--------|------|
|
||||
| 告警延迟/丢失 | 中 | SSE 无背压,告警风暴可能丢失 |
|
||||
| 体征数据不一致 | 高 | BLE 双写无事务,可能影响临床决策 |
|
||||
| 危急值阈值管理 | 中 | 后端有阈值配置,但 Web 无管理页 |
|
||||
| 适老化不足 | 中 | 15 处字号低于 22px,老年患者操作困难 |
|
||||
|
||||
### 7.4 按域评分
|
||||
|
||||
| 域 | 分数 | 说明 |
|
||||
|----|------|------|
|
||||
| F11 透析 | 85 | 流程完整,MP 覆盖好 |
|
||||
| F4 预约 | 88 | 三端 100%,血透刚需 |
|
||||
| F5 随访 | 82 | 流程合理,对比功能缺失 |
|
||||
| F3 健康数据 | 78 | 数据完整,BLE 有风险 |
|
||||
| F14 护理计划 | 35 | 概念好但无法使用 |
|
||||
| F18 FHIR | 40 | R4 合规不足 |
|
||||
|
||||
---
|
||||
|
||||
## 八、综合结论与 Top 5 必修项
|
||||
|
||||
### 8.1 各角色共识
|
||||
|
||||
5 个专家角色一致认同以下结构性问题:
|
||||
|
||||
1. **安全基础不牢** — SQL 注入 + FHIR 越权 + OAuth 权限缺失,不修复不能上线
|
||||
2. **5 个模块孤立** — 后端投入产出为零(34 条路由无 UI),需明确交付计划
|
||||
3. **测试覆盖严重不足** — MP 零测试 + 新增模块零测试,回归风险极高
|
||||
4. **AI 关怀闭环断裂** — 前后对比未实现,"AI 驱动主动关怀"定位不成立
|
||||
5. **可观测性缺口** — 4/6 新增 service 零 tracing,生产排障困难
|
||||
|
||||
### 8.2 Top 5 必修项(Phase 2 前必须完成)
|
||||
|
||||
| # | 问题 | 角色共识度 | 工作量 |
|
||||
|---|------|-----------|--------|
|
||||
| 1 | **C1: SQL 注入修复** — action_inbox_service.rs 参数化查询 | 5/5 | 2h |
|
||||
| 2 | **C2: FHIR allowed_patient_ids 强制执行** — 查询层过滤 | 4/5 | 4h |
|
||||
| 3 | **H5: OAuth handler require_permission** — 5 端点权限 | 4/5 | 1h |
|
||||
| 4 | **M3: JWT Secret 移除硬编码 fallback** — 启动时校验 | 4/5 | 1h |
|
||||
| 5 | **H2: AI 前后对比功能实现** — 关怀闭环核心 | 4/5 | 8h |
|
||||
|
||||
**总工作量: ~16h**
|
||||
|
||||
### 8.3 Phase 2 前置条件评估
|
||||
|
||||
| 条件 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| P0 安全修复完成 | **未开始** | C1/C2/H5/M3 四项 |
|
||||
| AI 关怀闭环通 | **未开始** | H2 前后对比 |
|
||||
| 核心模块有测试 | **部分** | 后端 80%,前端/MP 不足 |
|
||||
| 日志覆盖 80%+ | **未达标** | 4/6 新 service 零 tracing |
|
||||
|
||||
**结论**: Phase 2(患者体验重构)可规划,但需先完成 P0 安全修复(~8h)和 AI 闭环(~8h)。安全基础不牢则生产部署风险不可接受。
|
||||
|
||||
---
|
||||
|
||||
## 九、专家评审按域评分汇总
|
||||
|
||||
| 功能域 | 产品 | 架构 | 安全 | DevOps | 医疗 | 加权均 |
|
||||
|--------|------|------|------|--------|------|--------|
|
||||
| F1 患者 | 85 | 78 | 85 | 72 | 80 | **81** |
|
||||
| F2 医生 | 82 | 80 | 85 | 70 | 78 | **80** |
|
||||
| F3 健康数据 | 80 | 75 | 85 | 68 | 78 | **78** |
|
||||
| F4 预约 | 88 | 82 | 85 | 75 | 88 | **85** |
|
||||
| F5 随访 | 82 | 78 | 80 | 72 | 82 | **80** |
|
||||
| F6 咨询 | 85 | 80 | 85 | 72 | 80 | **81** |
|
||||
| F7 内容 | 75 | 72 | 80 | 65 | 70 | **73** |
|
||||
| F8 积分 | 72 | 70 | 80 | 60 | 65 | **70** |
|
||||
| F9 告警 | 80 | 72 | 75 | 68 | 78 | **76** |
|
||||
| F10 AI | 70 | 68 | 78 | 55 | 72 | **69** |
|
||||
| F11 透析 | 88 | 78 | 80 | 75 | 85 | **82** |
|
||||
| F12 仪表盘 | 75 | 72 | 78 | 65 | 70 | **73** |
|
||||
| F13 行动收件箱 | 78 | 55 | 40 | 68 | 75 | **61** |
|
||||
| F14 护理计划 | 30 | 40 | 78 | 30 | 35 | **41** |
|
||||
| F15 班次 | 30 | 40 | 78 | 30 | 35 | **41** |
|
||||
| F16 BLE 网关 | 30 | 45 | 70 | 25 | 30 | **41** |
|
||||
| F17 家庭代理 | 30 | 40 | 78 | 30 | 35 | **41** |
|
||||
| F18 FHIR | 55 | 50 | 50 | 25 | 40 | **46** |
|
||||
| F19 OAuth | 55 | 45 | 45 | 30 | 40 | **45** |
|
||||
| F20 日聚合 | 72 | 65 | 80 | 55 | 70 | **69** |
|
||||
180
docs/audits/v2/13-final-report.md
Normal file
180
docs/audits/v2/13-final-report.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# HMS V2 系统性功能审计 — 最终报告
|
||||
|
||||
> 审计日期: 2026-05-04 | V1 基线: 83% (2026-04-30) | Git HEAD: 95fa09c | 提交: 623
|
||||
|
||||
## 一、总体评分
|
||||
|
||||
| 指标 | V1 | V2 | 变化 |
|
||||
|------|-----|-----|------|
|
||||
| **系统完成度** | 83% | **85%** | +2% |
|
||||
| 后端代码行数 | ~77k | 98,501 | +28% |
|
||||
| 后端路由 | 328 | 302 | 整合优化 |
|
||||
| Web API | 235 | 252 | +7% |
|
||||
| MP API | 76 | 96 | +26% |
|
||||
| 事件类型 | 25 | 51 | +104% |
|
||||
| Web 测试文件 | 10 | 62 | +520% |
|
||||
|
||||
> 评分说明:完成度从 83% 提升至 85%。虽然 V1 的 15 个问题中 14 个已修复,但新增代码引入了新问题(SQL 注入、孤立模块),两者抵消。
|
||||
|
||||
## 二、V2 审计发现总览
|
||||
|
||||
### CRITICAL(2 个)
|
||||
|
||||
| # | 问题 | 位置 | 影响 |
|
||||
|---|------|------|------|
|
||||
| C1 | **SQL 注入**: `patient_id`/`user_id` 通过 `format!` 拼接 SQL | `action_inbox_service.rs:272-306` | 数据泄露/篡改风险 |
|
||||
| C2 | **FHIR 越权**: `allowed_patient_ids` 未在查询层强制执行 | `fhir/handler.rs` | 第三方应用可访问非授权患者数据 |
|
||||
|
||||
### HIGH(6 个)
|
||||
|
||||
| # | 问题 | 位置 | 影响 |
|
||||
|---|------|------|------|
|
||||
| H1 | 5 个模块 34 条路由完全孤立(护理计划/班次/BLE网关/家庭代理/药物记录) | 前端无 UI | Phase 1 产出未交付 |
|
||||
| H2 | AI 前后对比功能未实现(reanalysis.rs 仅日志) | `erp-ai/src/service/reanalysis.rs` | 关怀闭环断链 |
|
||||
| H3 | BLE 双写 vital_signs 无事务保护,失败静默忽略 | `device_reading_service.rs` | 数据不一致 |
|
||||
| H4 | 透析创建与 KDIGO 风险评分未自动串联 | 事件无 subscriber | 人工触发,效率低 |
|
||||
| H5 | OAuth handler 5 个端点缺少 `require_permission` | `oauth/handler.rs` | 权限绕过风险 |
|
||||
| H6 | MP 测试 0 个(40+ 页面全靠手工) | `apps/miniprogram/` | 回归风险极高 |
|
||||
|
||||
### MEDIUM(8 个)
|
||||
|
||||
| # | 问题 | 位置 |
|
||||
|---|------|------|
|
||||
| M1 | AI 分析缓存功能存在但未启用 | `erp-ai/service/analysis.rs` |
|
||||
| M2 | SSE 无背压保护(unbounded channel) | 告警推送 |
|
||||
| M3 | JWT Secret 硬编码 fallback `"dev-secret-key"` | `oauth/middleware.rs:67` |
|
||||
| M4 | 新增 service 4/6 无 tracing 日志 | care_plan/shift/ble_gateway/vital_signs_daily |
|
||||
| M5 | 告警双路径可能重复触发 | alert.rs + alert_engine.rs |
|
||||
| M6 | MP 日期格式化 6+ 处独立实现,无统一封装 | MP utils |
|
||||
| M7 | MP 错误提示无 403/500 分支,统一"请求失败" | MP request.ts |
|
||||
| M8 | MP 存在约 15 处 20px 字号低于适老阈值 22px | MP 多处 |
|
||||
|
||||
### LOW(5 个)
|
||||
|
||||
| # | 问题 | 位置 |
|
||||
|---|------|------|
|
||||
| L1 | 速率限制已建模未执行 | `oauth/service.rs` |
|
||||
| L2 | 测试文件含明文数据库密码 | `test_db.rs` |
|
||||
| L3 | E2E 测试 fixture 硬编码 localhost 无 fallback | `web/e2e/auth.fixture.ts` |
|
||||
| L4 | action_inbox DTO 内嵌 service,未抽取独立文件 | `action_inbox_service.rs` |
|
||||
| L5 | FHIR Bundle 缺 link 字段,不符合 R4 规范 | `fhir/converter.rs` |
|
||||
|
||||
## 三、功能域评分(20 域 × 10 维度)
|
||||
|
||||
| 功能域 | D1目标 | D2代码 | D3连通 | D4数据流 | D5安全 | D6错误 | D7日志 | D8性能 | D9测试 | D10 UX | 加权分 |
|
||||
|--------|-------|-------|-------|---------|-------|-------|-------|-------|-------|--------|--------|
|
||||
| F1 患者 | 90 | 100 | 70 | 85 | 95 | 90 | 85 | 90 | 70 | 75 | **85** |
|
||||
| F2 医生 | 80 | 100 | 100 | 90 | 95 | 90 | 85 | 90 | 70 | 85 | **89** |
|
||||
| F3 健康数据 | 95 | 100 | 75 | 80 | 95 | 85 | 80 | 85 | 75 | 70 | **83** |
|
||||
| F4 预约 | 95 | 100 | 100 | 95 | 95 | 90 | 85 | 90 | 80 | 90 | **93** |
|
||||
| F5 随访 | 95 | 100 | 80 | 85 | 90 | 90 | 80 | 85 | 75 | 75 | **85** |
|
||||
| F6 咨询 | 90 | 100 | 95 | 90 | 95 | 90 | 85 | 90 | 70 | 85 | **89** |
|
||||
| F7 内容 | 70 | 100 | 90 | 85 | 90 | 90 | 80 | 85 | 65 | 80 | **84** |
|
||||
| F8 积分 | 75 | 100 | 85 | 80 | 90 | 85 | 75 | 80 | 70 | 75 | **82** |
|
||||
| F9 告警 | 95 | 100 | 85 | 80 | 85 | 85 | 80 | 75 | 70 | 75 | **83** |
|
||||
| F10 AI | 90 | 100 | 75 | 70 | 90 | 80 | 70 | 60 | 65 | 60 | **76** |
|
||||
| F11 透析 | 95 | 100 | 90 | 80 | 90 | 85 | 75 | 85 | 70 | 80 | **85** |
|
||||
| F12 仪表盘 | 85 | 100 | 75 | 80 | 90 | 85 | 75 | 80 | 65 | 75 | **81** |
|
||||
| F13 行动收件箱 | 95 | 100 | 85 | 70 | **50** | 80 | 75 | 80 | 65 | 75 | **78** |
|
||||
| F14 护理计划 | 80 | 100 | **0** | **0** | 90 | 80 | **0** | 85 | **0** | **0** | **44** |
|
||||
| F15 班次 | 75 | 100 | **0** | **0** | 90 | 80 | **0** | 85 | **0** | **0** | **41** |
|
||||
| F16 BLE 网关 | 75 | 100 | **0** | 60 | 85 | 80 | **0** | 70 | **0** | **0** | **40** |
|
||||
| F17 家庭代理 | 75 | 100 | **0** | 60 | 90 | 80 | **0** | 85 | **0** | **0** | **41** |
|
||||
| F18 FHIR | 70 | 100 | **0** | 65 | **60** | 75 | **0** | 60 | **0** | **0** | **35** |
|
||||
| F19 OAuth | 60 | 100 | 50 | 70 | **55** | 75 | **0** | 80 | **0** | **0** | **42** |
|
||||
| F20 日聚合 | 85 | 100 | 50 | 75 | 90 | 80 | **0** | 85 | **0** | **0** | **52** |
|
||||
|
||||
> D2 代码存在性: 所有域均为 100%(后端代码完整)
|
||||
> D3 连通性: 5 个域为 0%(后端已实现但完全无前端接入)
|
||||
> D9 测试: 8 个域为 0%(新增模块无测试)
|
||||
|
||||
## 四、V1 问题修复确认
|
||||
|
||||
| ID | V1 问题 | V2 状态 |
|
||||
|----|--------|---------|
|
||||
| C1 | 晚间血压丢失 | ✅ 已修复 |
|
||||
| C2 | 告警权限拼写 | ✅ 已修复 |
|
||||
| H1 | 透析 MP 无入口 | ✅ 已修复(7 个 MP 页面) |
|
||||
| H2 | 知情同意 MP 无入口 | ✅ 已修复 |
|
||||
| H3 | 日志 30% | ✅ 已修复(116 处 tracing) |
|
||||
| M1 | 权限声明 47% | ✅ 已修复(53 个 Descriptor) |
|
||||
| M3 | 体温/血氧 MP | ✅ 已修复 |
|
||||
| M4 | SSE 指数退避 | ✅ 已修复 |
|
||||
| M5 | erp-ai 集成测试 | ✅ 已修复 |
|
||||
| M6 | Web 测试极低 | ✅ 大幅改善(10→62 文件) |
|
||||
| M7 | MP 测试 | ❌ 未修复(仍为 0) |
|
||||
| M8 | 健康记录/诊断 MP | ✅ 已修复 |
|
||||
| L1 | 孤立事件 | ✅ 已修复 |
|
||||
| L5 | unwrap() 风险 | ✅ 已修复 |
|
||||
| L12 | 40 编译警告 | ⚠️ 需关注(18 处 allow 标注) |
|
||||
|
||||
**修复率: 13/15 (87%)**。仅 M7(MP 测试)和 L12(allow 标注)未完全解决。
|
||||
|
||||
## 五、修复优先级排序
|
||||
|
||||
### P0 — 必须在 Phase 2 前修复(阻塞交付)
|
||||
|
||||
| 优先级 | 问题 | 工作量 | 原因 |
|
||||
|--------|------|--------|------|
|
||||
| 1 | **C1: SQL 注入修复** | 2h | 安全漏洞,数据泄露风险 |
|
||||
| 2 | **C2: FHIR allowed_patient_ids 强制执行** | 4h | 越权访问风险 |
|
||||
| 3 | **H5: OAuth handler 添加 require_permission** | 1h | 权限绕过风险 |
|
||||
| 4 | **M3: 移除 JWT Secret 硬编码 fallback** | 1h | 生产安全 |
|
||||
|
||||
### P1 — Phase 2 期间修复
|
||||
|
||||
| 优先级 | 问题 | 工作量 | 原因 |
|
||||
|--------|------|--------|------|
|
||||
| 5 | H2: AI 前后对比功能实现 | 8h | 关怀闭环核心 |
|
||||
| 6 | H4: 透析→KDIGO 自动串联 | 4h | 自动化风险预警 |
|
||||
| 7 | H3: BLE 双写事务保护 | 4h | 数据一致性 |
|
||||
| 8 | M4: 新增 service tracing 补全 | 4h | 可观测性 |
|
||||
| 9 | M1: AI 缓存启用 | 2h | 性能/成本优化 |
|
||||
|
||||
### P2 — 中期补全
|
||||
|
||||
| 优先级 | 问题 | 工作量 | 原因 |
|
||||
|--------|------|--------|------|
|
||||
| 10 | H1: 孤立模块前端 UI 接入(按业务优先级) | 40h+ | Phase 2 范围 |
|
||||
| 11 | H6: MP 测试框架搭建 | 16h | 回归保障 |
|
||||
| 12 | M6/M7: MP 日期/错误统一封装 | 8h | UX 一致性 |
|
||||
| 13 | M8: 适老化字号修复 | 4h | 老年友好 |
|
||||
| 14 | M5: 告警去重机制 | 4h | 告警风暴保护 |
|
||||
|
||||
## 六、关键建议
|
||||
|
||||
### 6.1 架构建议
|
||||
|
||||
1. **统一前端 API 层**: MP 端日期/错误处理需统一封装,避免 6+ 处独立实现
|
||||
2. **事件消费者补全**: 8 个事件无消费者,care_plan 相关事件全部悬空
|
||||
3. **DTO 规范化**: action_inbox DTO 内嵌 service,应抽取独立文件
|
||||
|
||||
### 6.2 测试建议
|
||||
|
||||
1. **MP 测试框架**: 最高优先级搭建 Taro 测试环境(Vitest + React Testing Library)
|
||||
2. **新增模块测试**: care_plan/shift/ble_gateway/family_proxy 四个模块 0 测试
|
||||
3. **Web 测试质量**: 62 文件需评估断言覆盖率和 mock 质量
|
||||
|
||||
### 6.3 Phase 2 前置条件
|
||||
|
||||
Phase 2(患者体验重构)可启动,但需先完成 P0 修复项(C1/C2/H5/M3)。理由:
|
||||
- P0 均为安全问题,不修复则在生产环境存在数据泄露/越权风险
|
||||
- Phase 2 涉及老年患者 UI 重设计,安全基础必须先行
|
||||
|
||||
## 七、报告索引
|
||||
|
||||
| # | 文件 | 行数 | 内容 |
|
||||
|---|------|------|------|
|
||||
| 1 | `00-baseline-refresh.md` | 150 | 基线数字 + V1 对比 |
|
||||
| 2 | `01-business-value-analysis.md` | 200 | 20 功能域业务画像 |
|
||||
| 3 | `02-feature-inventory-refresh.md` | 120 | 三端对齐矩阵 |
|
||||
| 4 | `03-data-flow-traces.md` | 320 | 12 条数据流 + Mermaid 图 |
|
||||
| 5 | `04-backend-integrity.md` | 122 | 后端完整性 |
|
||||
| 6 | `05-security-performance.md` | 130 | 安全合规 + 性能 |
|
||||
| 7 | `06-gap-patterns-refresh.md` | 100 | 差距模式重验 |
|
||||
| 8 | `07-observability.md` | 60 | 日志/错误/可观测性 |
|
||||
| 9 | `08-test-coverage-refresh.md` | 70 | 测试覆盖率 |
|
||||
| 10 | `10-ux-consistency.md` | 87 | UX 一致性 |
|
||||
| 11 | `11-tech-debt.md` | 98 | 技术债务 |
|
||||
| 12 | `12-expert-review.md` | 待定 | 多角色评审 |
|
||||
| 13 | `13-final-report.md` | 本文件 | 综合报告 |
|
||||
Reference in New Issue
Block a user