Files
hms/docs/audits/05-gap-patterns.md
iven d712ad78c3 docs: 审计报告(8 份) + 讨论记录(4 份)
审计报告: 基线快照/功能清单/后端完整性/事件系统/参数配置/
差距模式/错误处理/测试覆盖/审计总结报告
讨论记录: 设备管线/端到端测试/三端审计/工作台重构
2026-05-03 19:32:15 +08:00

9.6 KiB
Raw Permalink Blame History

HMS 功能审计 — Phase 5: 五种差距模式识别

日期: 2026-04-30 | 审计范围: 全系统差距模式分析

总览

基于 Phase 0-4 的审计数据,系统性检测五种常见差距模式。


1. 模式 1"写了没接" — 后端路由无前端调用者

检测方法

集合差运算:backend_routes - web_api_calls - mp_api_calls

发现

路由 模块 说明 严重性
POST /health/patients/{id}/trends/generate erp-health 趋势报告生成,无前端调用。可能为后台定时任务触发 LOW
POST /ai/analyze/vital-signs erp-ai SSE 端点Web 和小程序均无 UI 调用 MEDIUM
POST /ai/analyze/lab-report erp-ai 同上 MEDIUM
POST /ai/analyze/health-trend erp-ai 同上 MEDIUM
POST /ai/analyze/health-summary erp-ai 同上 MEDIUM

AI 分析 SSE 端点说明4 个 AI 分析端点通过 SSE 流式返回结果。前端未调用是因为 AI 分析功能可能仅通过 API 工具(如 Swagger UI直接测试。这些端点的后端实现完整含权限检查 ai.analysis.manage),但缺少前端管理界面的触发入口。

趋势生成说明POST .../trends/generate 可能设计为后台任务调用(如定时生成趋势报告),而非前端直接触发。

统计

类别 数量
孤立后端路由(无任何前端调用) 5
其中 AI SSE 端点 4
其中后台任务路由 1

2. 模式 2"接了没传" — 前端调用但参数传递不完整

检测方法

搜索前端 API 调用中空参数传递、缺失 header、字段遗漏。

发现

2.1 小程序 vital_signs 字段遗漏6 个)

已在 Phase 4 §4.3 详细分析。核心问题:indicator_type 模型无法传递晚间血压、体温、血氧等字段。

2.2 小程序 X-Patient-Id / X-Tenant-Id Header

小程序通过 request.ts 拦截器统一注入 X-Patient-IdX-Tenant-Id header。经检查

  • 所有患者端 API 调用均通过 request.ts 封装header 注入正常
  • 医护端 API 调用使用独立的 doctorRequest 实例header 注入机制一致

2.3 后端 DTO 字段前端未传递(低风险)

端点 后端 DTO 字段 前端行为 风险
POST /vital-signs blood_sugar_type 小程序不传,后端默认 NULL LOW
POST /vital-signs source 小程序不传,后端默认 "manual" LOW
POST /device-readings/batch raw_data 前端传递完整 JSON

统计

类别 数量
前端字段遗漏HIGH 2晚间血压
前端字段遗漏MEDIUM 2体温、血氧
前端字段遗漏LOW 2血糖类型、来源
Header 注入问题 0

3. 模式 3"传了没存" — 数据传递但未完整持久化

检测方法

追踪 4 条关键写入路径小程序体征录入、Web 创建预约、BLE 设备同步、每日签到。

路径 1小程序体征录入

inputVitalSign() → POST /health/patients/{id}/vital-signs
  → health_data_handler::create_vital_signs()
  → health_data_service::create_vital_signs()
  → INSERT vital_signs

结果 晨间血压/心率/体重/血糖/饮水量/尿量正常写入。 晚间血压/体温/血氧未写入(前端未传)。

路径 2Web 创建预约

AppointmentList → POST /health/appointments
  → appointment_handler::create_appointment()
  → appointment_service::create_appointment()
  → CAS 原子检查 slot_available → INSERT appointment

结果 完整。含 CAS 并发控制、乐观锁、事务保证。

路径 3BLE 设备同步

BLE scan → uploadReadings() → POST /health/patients/{id}/device-readings/batch
  → device_reading_handler::batch_create()
  → device_reading_service::sync_readings()
  → INSERT device_readings + UPSERT vital_signs_hourly

结果 完整。批量插入 + 小时聚合 + 事件发布。

路径 4每日签到

checkin() → POST /health/points/checkin
  → points_handler::daily_checkin()
  → points_service::daily_checkin()
  → INSERT/UPDATE points_checkin + INSERT points_transaction

结果 完整。幂等检查(同日不可重复签到)+ 事务保证 + 事件发布。

统计

路径 结果
体征录入 部分数据丢失(晚间血压等)
创建预约 完整
BLE 同步 完整
每日签到 完整

4. 模式 4"存了没用" — 数据持久化但未被消费

检测方法

检查写入了但从未被读取或展示的数据。

发现

4.1 事件无消费者14 个)

已在 Phase 3 §4.2 详细分析。14 个事件被发布到 EventBus 但没有业务消费者:

  • patient.updated — 信息性事件,更新已直接处理
  • consultation.*3 个) — 会话管理已在 service 内直接处理
  • article.published/rejected — 状态已更新
  • points.earned/exchanged/expired3 个) — 积分操作已完成
  • 其余 5 个同类型

评估:这些事件通过 SSE 推送到前端,用于实时通知,不完全是"没用"。但没有专门的后端消费者处理后续业务逻辑。

4.2 数据库字段未读取

字段 写入场景 读取场景 状态
raw_data device_readings BLE 同步时写入 无专门查询 MEDIUM
revoke_reason consent 撤回知情同意时写入 列表查询返回 ✓ 已用
model_config ai_prompt 创建/更新 Prompt 时写入 分析时读取 model/temperature/max_tokens ✓ 已用
article_revision article_revision 文章编辑时写入 GET .../revisions 端点返回 ✓ 已用

raw_data 字段说明device_readings.raw_data 存储 BLE 设备原始 JSONB 数据。当前无专门的读取/分析页面。价值在于数据溯源和异常排查,但在 UI 层面无入口。

4.3 entity 字段从未构造

Phase 2 发现 RefRow struct 从未构造(编译器警告),属于重构残留。

统计

类别 数量 影响
无消费者事件 14 LOWSSE 推送 + 审计追踪仍有价值)
未读取数据库字段 1raw_data MEDIUM数据溯源需要但无 UI 入口)
死代码 struct 1RefRow LOW编译器警告重构残留

5. 模式 5"双系统不同步" — Web 与小程序实现差异

检测方法

对比共享功能在 Web 和小程序的实现差异,区分"角色分叉(正常)"和"实现缺陷"。

5.1 角色分叉(正常差异)

功能 Web管理端 小程序(患者/医护端) 差异类型
积分管理 规则 CRUD + 商品管理 + 订单核销 签到 + 兑换 + 查看订单 角色分叉 ✓
文章管理 CMS 全流程(创建/编辑/审核/发布) 只读列表(仅 published 角色分叉 ✓
告警管理 规则配置 + 仪表盘 + 处置 查看自身告警 + 处理 角色分叉 ✓
设备管理 列表 + 解绑 BLE 扫描 + 同步 平台差异 ✓
预约管理 全 CRUD + 排班配置 创建/查看/取消预约 角色分叉 ✓
医生管理 档案 CRUD + 排班管理 查看排班日历 角色分叉 ✓

5.2 实现缺陷(需修复)

功能 Web 小程序 差异类型 优先级
体征录入 结构化表单(所有字段独立输入) indicator_type 映射(丢失晚间血压/体温/血氧) 数据模型差异 P1
咨询消息 列表 + 详情 + 导出 列表 + 详情(无导出) 功能缺失 P3
透析管理 完整 CRUD + 审阅 无任何入口 功能缺失 P1
知情同意 完整 CRUD 无任何入口 功能缺失 P1
健康记录 完整 CRUD 无任何入口 功能缺失 P2
诊断记录 完整 CRUD 无任何入口 功能缺失 P2
药物管理 完整 CRUD 有页面但 API 调用不明确 待验证 P2
权限码拼写 health.alerts.manage(正确) —(前端用 health.alert.manage 拼写错误 P1

5.3 透析管理 — 最大差距

透析是唯一一个后端完整实现但小程序完全空白的功能域:

  • 后端12 个路由(记录 CRUD + 处方 CRUD + 审阅 + 统计)
  • Web完整管理界面DialysisManageList
  • 小程序0 个 API 调用、0 个页面

影响:透析患者无法在移动端查看自己的透析记录和处方,医护无法在小程序端录入透析数据。

统计

差异类型 数量
角色分叉(正常) 6
数据模型差异 1
功能缺失P1 3透析/知情同意/体征映射)
功能缺失P2 3健康记录/诊断/药物)
功能缺失P3 1咨询导出
拼写错误 1

6. 差距模式汇总评分

模式 严重程度 发现数 评分
模式 1: 写了没接 LOW-MEDIUM 5 95%(仅 AI SSE 和趋势生成孤立)
模式 2: 接了没传 HIGH-LOW 6 75%(晚间血压数据丢失是关键缺陷)
模式 3: 传了没存 LOW 1 95%(仅体征部分字段未传导致未存)
模式 4: 存了没用 LOW 16 85%(大部分事件有 SSE 消费者raw_data 待利用)
模式 5: 双系统不同步 HIGH-LOW 9 65%(透析/知情同意完全缺失,体征映射丢失)