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

244 lines
9.6 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 功能审计 — 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-Id``X-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/expired`3 个) — 积分操作已完成
- 其余 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%(透析/知情同意完全缺失,体征映射丢失) |