Files
hms/docs/superpowers/specs/2026-05-04-iot-fhir-platform-ecosystem-design.md
iven 2afe3a8848 docs: IoT 设备采集 + FHIR 开放平台生态设计规格
发散式探讨产出:BLE 适配器 + 设备网关混合架构,HL7 FHIR R4 输出,
OAuth2 合作伙伴认证,渐进演进 V1-V3 路线图。

Spec review 发现大量已有基础设施(device_readings/alert_engine/SSE/BLE),
设计已据此修正为"增强现有 + 新增 FHIR 层"策略。
2026-05-04 01:08:01 +08:00

45 KiB
Raw Permalink Blame History

HMS IoT 设备采集 + FHIR 开放平台设计规格

日期: 2026-05-04 | 类型: 设计规格 | 状态: Draft

如何使用本文档: §1-2 是全景架构所有人应读。§3-6 是各层详细设计按需阅读。§7-8 是实施路线和变更清单,执行时参考。


1. 背景与目标

1.1 业务背景

HMS 平台当前已实现体征数据的手动录入和危急值阈值告警。但慢病患者(高血压、糖尿病、肾病)的健康数据采集严重依赖患者主动录入,依从性差、数据稀疏、无法捕捉短时波动。

健康手环(小米手环、华为手环)的普及率为 24 小时被动采集提供了硬件基础。心率、血氧、步数、睡眠等数据可连续产生,通过小程序 BLE 同步到 HMS。居家医疗设备蓝牙血压计、血糖仪进一步覆盖慢病管理的核心指标。体检中心专业设备生化分析仪、心电图机则提供最权威的医疗级数据。

HMS 从"数据采集平台"升级为"健康数据枢纽":设备数据流入,通过 FHIR 标准接口流出第三方系统HIS/LIS/体检系统)可消费标准化数据。

1.2 目标用户与场景

用户 场景 价值
慢病患者 佩戴手环/使用蓝牙设备,小程序自动同步数据 免去手动录入,持续监测
主管医生 Web 端实时看板查看患者体征趋势和告警 及时发现异常,干预更早
护士站 接收高危告警推送 快速响应危急情况
体检中心 出具报告时参考连续监测数据 + 专业设备直连 报告更全面,数据自动入库
合作方系统 通过 FHIR API 拉取/推送标准化健康数据 无需适配 HMS 私有接口

1.3 成功指标

指标 基线 V1 目标 V2 目标
体征数据日均采集量 ~10 条/患者(手动) > 500 条/患者(设备) > 1000 条/患者
设备接入数 0 2 款(手环 + 血压计) 6+ 款(含网关)
告警延迟(采集→通知) 分钟级(轮询) < 30 秒SSE < 10 秒
FHIR API 响应时间 N/A < 200ms (P95) < 150ms (P95)
合作方接入 0 1 家(验证) 3-5 家

1.4 范围边界

做:

  • BLE 设备采集(穿戴 + 居家医疗)— DeviceAdapter 统一抽象
  • 专业设备接入扩展点 — DeviceGateway traitV2 实现)
  • 后端设备数据摄入 API批量提交 + 降采样)
  • 告警规则引擎(单次阈值 + 连续超标 + 趋势恶化)
  • SSE 推送扩展(体征聚合更新 + 告警通知)
  • FHIR R4 只读 API — 10 个资源端点
  • OAuth2 Client Credentials 合作伙伴认证
  • 数据分区与降采样策略

不做(本设计不覆盖):

  • ICU 级实时监控(亚秒级,需要专用系统)
  • AI 驱动的异常检测erp-ai 模块职责,本设计只提供数据输入)
  • FHIR 写入 APIV2a 范围)
  • Webhook 事件推送V2b 范围)
  • 设备厂商自助接入 SDKV2c 范围)
  • 多实例部署的事件总线演进(单实例足够)

2. 整体架构与演进路线

2.1 全景数据流

┌─────────────────────────────────────────────────────────────────┐
│                        设备层 (Device Layer)                     │
│                                                                 │
│  消费穿戴          居家医疗           专业设备                    │
│  ┌───────┐        ┌──────────┐      ┌──────────────┐            │
│  │小米手环│        │蓝牙血压计 │      │生化分析仪    │            │
│  │华为手环│        │蓝牙血糖仪 │      │心电图机     │            │
│  │Apple   │        │蓝牙体温计 │      │超声设备     │            │
│  │Watch   │        │智能体脂秤 │      │DICOM 设备   │            │
│  └───┬────┘        └────┬─────┘      └──────┬───────┘            │
│      │                  │                    │                    │
│  ────┴────  BLE GATT ───┴────                │ HL7/DICOM/TCP     │
│      │                  │                    │                    │
│  ┌───┴──────────────────┴──┐      ┌─────────┴──────────┐        │
│  │   DeviceAdapter trait   │      │  DeviceGateway trait │        │
│  │   (V1 实现, 小程序端)    │      │  (V2, 插件/网关)     │        │
│  └───────────┬─────────────┘      └──────────┬───────────┘        │
│              │                               │                    │
├──────────────┼───────────────────────────────┼────────────────────┤
│              │         摄入层 (Ingestion)      │                    │
│                                                                 │
│  ┌───────────┴───────────────────────────────┴───────────┐        │
│  │  统一摄入 API                                          │        │
│  │  POST /api/v1/health/device/readings (批量)             │        │
│  │  POST /api/v1/health/device/gateway/{type} (网关)      │        │
│  │                                                        │        │
│  │  校验 → 降采样 → 存储 → 事件发布                         │        │
│  └───────────────────────────┬────────────────────────────┘        │
│                              │                                    │
├──────────────────────────────┼────────────────────────────────────┤
│                              │     数据层 (Storage)                │
│                                                                 │
│  ┌───────────┐  ┌──────────┐  ┌───────────┐  ┌───────────────┐  │
│  │device_    │  │device_   │  │vital_     │  │health_        │  │
│  │readings   │  │gateways  │  │signs      │  │alerts         │  │
│  │(高频原始) │  │(网关注册)│  │(手动+降采样)│ │(规则触发)     │  │
│  └───────────┘  └──────────┘  └───────────┘  └───────────────┘  │
│                                                                 │
├─────────────────────────────────────────────────────────────────┤
│                     输出层 (Output)                              │
│                                                                 │
│  V1: API 拉取              V2: 事件推送                         │
│  ┌─────────────────┐      ┌──────────────────┐                  │
│  │ FHIR API         │      │ Webhook 推送      │                  │
│  │ /fhir/Patient    │      │ 事件订阅管理      │                  │
│  │ /fhir/Observation│      │ 幂等投递+重试     │                  │
│  │ /fhir/Device     │      │ Dead letter 处理  │                  │
│  │ /fhir/Diagnostic │      │                   │                  │
│  └────────┬────────┘      └────────┬──────────┘                  │
│           │                         │                            │
│  ─────────┴───── 合作伙伴 API ─────┴─────────                    │
│           │                         │                            │
│  ┌────────┴──────┐        ┌────────┴──────────┐                 │
│  │HIS/LIS 系统   │        │体检中心系统         │                 │
│  │电子病历       │        │健康管理机构         │                 │
│  └───────────────┘        └───────────────────┘                 │
└─────────────────────────────────────────────────────────────────┘

2.2 现有功能基线

以下功能已存在于代码库中,本 spec 不重复设计,只标注需要的增强:

已有功能 位置 状态
device_readings 表 + Entity erp-health/entity/device_readings.rs 生产就绪,含分区
批量摄入 API + 服务 erp-health/service/device_reading_service.rs 生产就绪,含去重/校验/小时聚合
patient_devices 设备绑定 erp-health/entity/patient_devices.rs 基础功能完成,缺少状态追踪
vital_signs_hourly 小时聚合 erp-health/entity/vital_signs_hourly.rs 生产就绪
alert_rules 告警规则 erp-health/entity/alert_rules.rs 生产就绪
alert_engine 告警引擎 erp-health/service/alert_engine.rs 3 种规则类型已实现
EventBus 事件 erp-health/event.rs device.readings.synced + alert.triggered 已发布
SSE 推送 erp-message/handler/sse_handler.rs 已推送 vital_update + alert 事件
BLE 适配器框架 小程序 services/ble/ TypeScript DeviceAdapter 接口 + 3 个适配器
设备类型校验 erp-health/service/validation.rs 8 种 device_type

2.3 模块划分与职责

模块 位置 职责 状态
BLE 采集层 小程序 services/ble/ 设备发现、连接、数据读取 已存在
DeviceAdapter 小程序 services/ble/adapters/ 统一接口,屏蔽 BLE 差异 已存在TypeScript
摄入 API erp-health handler 批量接收、校验、存储 已存在
降采样 Pipeline erp-health service 小时聚合已实现 已存在,需新增日聚合
告警引擎 erp-health service 3 种规则评估 已存在
SSE 推送 erp-message handler vital_update + alert 推送 已存在,需增强重连
FHIR API erp-health handler (新路由组) FHIR R4 资源查询 新增
合作伙伴认证 erp-auth OAuth2 Client Credentials 新增
DeviceGateway erp-health trait 非 BLE 设备接入扩展点 新增V2

2.3 演进阶段

阶段 时间 内容 里程碑
V1 8-12 周 BLE 适配器 + 摄入 API + 降采样 + 告警引擎 + FHIR 只读 API + OAuth2 手环数据全链路跑通1 家合作方验证
V2a 4-6 周 居家医疗设备适配 ×3 + FHIR 写入 API 血压/血糖/体温数据自动采集
V2b 6-8 周 DeviceGateway + HL7/DICOM 适配 + Webhook 推送 体检中心设备接入
V3 持续 设备厂商自助接入(插件 SDK+ 数据市场 + AI 分析增强 平台生态自运转

2.5 与现有 HMS 架构的集成点

集成点 现有 本设计扩展
EventBus device.readings.synced + alert.triggered 已实现 不需要新增事件类型
SSE Handler 已推送 vital_update + alert + message 增强Last-Event-ID 重连 + 心跳
device_readings 表 已有分区表 + 批量摄入 + 去重 不变更,复用现有
vital_signs_hourly 已有小时聚合 不变更,复用现有
vital_signs_daily 不存在 新增:日聚合表 + background task
patient_devices 基础设备绑定 增强status/firmware/metadata 列
alert_engine 3 种规则类型 + cooldown 增强:患者级升级 + 系统级聚合降噪
认证系统 JWT + RBAC 新增OAuth2 Client Credentials合作伙伴专用
WASM 插件 erp-plugin 运行时 V2 复用为设备网关扩展点

2.5 架构决策原则

为什么 BLE 适配器 + 设备网关混合而非统一抽象?

BLE 穿戴和居家医疗设备本质上是同一协议族(蓝牙 GATT统一 DeviceAdapter 自然合理。专业设备的数据模型HL7 OBX/PID/OBR与体征读数时间序列根本不同强行统一会变成"最低公分母"。分开处理是正确的关注点分离。HMS 已有 WASM 插件系统,设备网关可复用插件架构作为扩展点。

为什么 FHIR 而非自定义 JSON API

FHIR 是国际医疗互操作标准HIS/LIS/EMR 系统广泛支持。选择 FHIR 意味着 HMS 从一开始就为与现有医疗系统对接做好了准备,合作方不需要学习 HMS 私有接口。V1 只做 6 个核心资源的只读 API复杂度可控。

为什么合作伙伴专属而非完全开放?

医疗数据的敏感性要求严格的访问控制。合作伙伴模式确保只有经过审核的机构才能接入,配合多层隔离(租户/资源/患者范围/频率限制)降低数据泄露风险。


3. 数据模型与 FHIR 映射

3.1 现有表(不修改)

以下表已存在于代码库中,本设计不做结构性变更:

表名 关键列 说明
device_readings id, tenant_id, patient_id, device_id(VARCHAR), device_type, metric, raw_value(JSON), measured_at 高频原始数据,含分区
patient_devices id, tenant_id, patient_id, device_id(VARCHAR), device_model, device_type, bound_at, last_sync_at 设备绑定
vital_signs_hourly id, tenant_id, patient_id, device_type, hour_start, min_val, max_val, avg_val, sample_count 小时聚合
alert_rules id, tenant_id, name, device_type, condition_type, condition_params(JSON), severity, is_active, cooldown_minutes 告警规则
alerts id, tenant_id, patient_id, rule_id, device_type, severity, status, ... 告警实例

3.2 需增强的表

patient_devices — 增加设备状态追踪

新增列(迁移):

列名 类型 说明
status VARCHAR(20) DEFAULT 'active' active / inactive / disconnected
firmware_version VARCHAR(100) 固件版本
manufacturer VARCHAR(200) 厂商
connection_type VARCHAR(50) DEFAULT 'ble' ble / ble_gateway / serial / tcp / hl7
metadata JSONB 设备特有配置

3.3 新增表

vital_signs_daily — 日聚合(新增)

列名 类型 约束 说明
id UUID v7 PK
tenant_id UUID NOT NULL
patient_id UUID FK → patients, NOT NULL
device_type VARCHAR(50) NOT NULL 与现有 device_type 一致
date_bucket DATE NOT NULL 日期
min_val NUMERIC(12,4) 最小值
max_val NUMERIC(12,4) 最大值
avg_val NUMERIC(12,4) NOT NULL 平均值
sample_count INTEGER NOT NULL 样本数
percentile_95 NUMERIC(12,4) 95 百分位
created_at TIMESTAMPTZ NOT NULL
updated_at TIMESTAMPTZ NOT NULL
version INTEGER NOT NULL DEFAULT 1

UNIQUE: (tenant_id, patient_id, device_type, date_bucket)

api_clients — 合作方 API 客户端(新增)

列名 类型 约束 说明
id UUID v7 PK
tenant_id UUID NOT NULL 所属租户
client_id VARCHAR(128) UNIQUE NOT NULL OAuth2 client_id
client_secret_hash VARCHAR(256) NOT NULL Argon2 哈希
client_name VARCHAR(200) NOT NULL 合作方名称
scopes JSONB NOT NULL 允许的 FHIR 资源范围
allowed_patient_ids JSONB 可访问的患者 ID 白名单null = 全部)
rate_limit_per_minute INTEGER NOT NULL DEFAULT 60 限流
is_active BOOLEAN NOT NULL DEFAULT true
token_lifetime_seconds INTEGER NOT NULL DEFAULT 3600 token 有效期
created_at TIMESTAMPTZ NOT NULL
updated_at TIMESTAMPTZ NOT NULL
created_by UUID
updated_by UUID
deleted_at TIMESTAMPTZ
version INTEGER NOT NULL DEFAULT 1

3.2 FHIR Resource 映射

HMS 实体 FHIR R4 Resource 说明
Patient Patient 患者基本信息
Doctor Practitioner 医护人员
Department Organization 科室/组织
Appointment Appointment 预约
VitalSign Observation 体征数据(手动录入)
DeviceReading Observation 设备采集数据
Device Device 设备注册信息
HealthAlert Flag 告警
LabReport DiagnosticReport 化验报告
Consultation Encounter 咨询记录
FollowUpTask Task 随访任务

3.3 LOINC 编码映射

ReadingType LOINC Code Display
HeartRate 8867-4 Heart rate
SpO2 2708-6 Oxygen saturation in Arterial blood
BloodPressureSystolic 8480-6 Systolic blood pressure
BloodPressureDiastolic 8462-4 Diastolic blood pressure
BloodGlucose 2339-0 Glucose in Blood
Temperature 8310-5 Body temperature
Weight 29463-7 Body weight
BodyFat 41982-0 Body fat percentage
Steps 55423-8 Number of steps in 24 hours
RespiratoryRate 9279-1 Respiratory rate

3.4 降采样策略

数据年龄 存储策略 查询来源
0-24h 原始数据 device_readings 实时看板、详情页
1-30 天 小时聚合 device_reading_hourly 趋势图、日报
30+ 天 日聚合 device_reading_daily 月报、长期趋势
保留原始数据 可配置(默认 90 天后归档到冷存储) 审计、科研需要时恢复

数据量估算1000 活跃患者,手环每 5 分钟采集 4 种指标):

指标 日数据量 月数据量
原始读数 ~115 万条 ~3,450 万条
小时聚合 ~2,880 条 ~8.6 万条
日聚合 ~4,000 条 ~12 万条

降采样后存储压力降低 400 倍,查询长期趋势从扫描千万行降到扫描几百行。


4. DeviceAdapter 与 DeviceGateway 接口设计

4.1 现有 BLE 适配器架构(已实现)

BLE 设备的适配器模式运行在小程序端TypeScript,已有完整实现:

// 已有接口 — services/ble/types.ts
interface DeviceAdapter {
  name: string;
  supportedModels: string[];
  serviceUUIDs: string[];
  notifyCharacteristics: BLECharacteristic[];
  readCharacteristics: BLECharacteristic[];
  parseNotification(data: ArrayBuffer): NormalizedReading[];
  parseReadResponse(data: ArrayBuffer): NormalizedReading[];
}

type DeviceType = 'heart_rate' | 'blood_oxygen' | 'steps' | 'sleep'
                | 'temperature' | 'stress' | 'blood_pressure' | 'blood_glucose';

interface NormalizedReading {
  device_type: DeviceType;
  values: Record<string, number | string>;
  metric?: string;
  measured_at: string;
}

已实现的适配器:

  • XiaomiBandAdapter.ts — 小米手环(心率/血氧/步数/睡眠)
  • BloodPressureAdapter.ts — 蓝牙血压计8 个型号,含欧姆龙/AND/iHealth
  • GlucoseMeterAdapter.ts — 蓝牙血糖仪

已有的 BLEManager 功能:

  • 适配器注册 + 按设备名自动匹配
  • BLE 扫描 + 连接管理
  • 数据同步 + 本地缓冲(最大 2000 条)
  • 可配置:扫描超时、每次同步最大条数、重试次数

4.2 BLE 适配器扩展V1 增强)

V1 需要新增的适配器和功能:

新增内容 说明
HuaweiBandAdapter.ts 华为手环Band 7/8/9
GenericBleAdapter.ts 通用 BLE 适配器(标准 Health Thermometer Profile
DataSyncScheduler.ts 定时同步调度(每天至少 1 次自动同步)
BLEManager 离线增强 DataBuffer 持久化到 Storage网络恢复后自动提交

4.3 现有 device_type 与 FHIR 映射

现有系统使用 device_type 字段8 种),与 FHIR Observation 的 LOINC 编码映射:

device_type现有 FHIR Observation code LOINC
heart_rate Heart rate 8867-4
blood_oxygen Oxygen saturation 2708-6
blood_pressure Blood pressure panel 85354-9含收缩压 8480-6 + 舒张压 8462-4
blood_glucose Glucose in Blood 2339-0
temperature Body temperature 8310-5
steps Steps 55423-8
sleep Sleep duration 93832-4
stress Stress level 自定义(无标准 LOINC

设计决策:保持现有 device_type 而非引入 ReadingType

现有系统用一个 device_type(如 blood_pressure+ JSONB raw_value(含收缩压/舒张压)的模式存储多值数据。这比拆分为多行(每行一个 reading_type + 标量 value更高效。FHIR 转换层负责将 blood_pressure 的 JSONB 拆分为独立的 Systolic/Diastolic Observation。不在数据层做拆分。

4.4 同步流程(已实现,不需变更)

1. 用户打开小程序 → BLEManager 检查已配对设备
2. 扫描 → AdapterRegistry.matchAdapter() 匹配适配器
3. 适配器连接设备 → parseNotification/parseReadResponse
4. NormalizedReading[] → 本地缓冲ble_pending_readings
5. 批量提交 → POST /api/v1/health/device/readings
6. 后端 batch_create_readings() → 去重 → 存储 → 小时聚合 → 事件发布
7. EventBus → alert_engine.evaluate_rules() → 告警触发 → SSE 推送
8. 同步完成 → 更新 patient_devices.last_sync_at

4.3 同步流程

1. 用户打开小程序 → DataSyncScheduler 检查同步计划
2. BleManager 扫描已配对设备 → AdapterRegistry 匹配适配器
3. 适配器连接设备 → read_history(since_last_sync)
4. 批量读取的 RawDeviceReading[] → DataBuffer 暂存
5. 网络可用时批量提交 → POST /api/v1/health/device/readings
6. 后端校验 → 存储 → 降采样触发 → 告警评估 → 事件发布
7. 同步完成 → 更新 last_synced_at → 显示同步结果给用户

4.5 DeviceGateway TraitV2 扩展点,新增)

专业医疗设备的接入抽象,运行在后端Rust

/// 网关接收的标准化医疗数据
struct GatewayObservation {
    device_id: String,
    patient_id: Option<String>,
    observation_type: String,        // HL7 OBX-3 或 DICOM tag
    value: serde_json::Value,
    unit: Option<String>,
    observed_at: DateTime<Utc>,
    performer: Option<String>,
    metadata: serde_json::Value,
}

/// 设备网关 trait — 处理非 BLE 协议
#[async_trait]
trait DeviceGateway: Send + Sync {
    fn gateway_id(&self) -> &str;
    fn protocol(&self) -> GatewayProtocol;
    async fn start_listening(&self, config: GatewayConfig) -> Result<()>;
    async fn stop_listening(&self) -> Result<()>;
    async fn parse_message(&self, raw: &[u8]) -> Result<Vec<GatewayObservation>>;
}

enum GatewayProtocol {
    Hl7V2,
    Hl7Fhir,
    Dicom,
    SerialRs232,
    TcpRaw,
}

4.6 网关插件化接入流程

第三方设备厂商接入流程:

1. 实现 DeviceGateway trait或使用通用 HL7/DICOM 网关)
2. 打包为 WASM 插件(复用 erp-plugin 基础设施)
3. 租户管理员在设备管理页面启用该网关插件
4. 配置连接参数TCP 端口 / serial 设备路径 / FHIR endpoint
5. 网关开始接收数据 → 自动解析 → 写入 device_readings

5. FHIR API 输出层

5.1 API 路由设计

FHIR API 独立于 HMS 内部 API使用独立的认证中间件和路由前缀。

注意: FHIR 使用 /fhir/R4/ 路由前缀而非 HMS 标准的 /api/v1/。这是 FHIR 合规性要求 — FHIR 标准规定服务器使用标准 URL 路径,合作方系统期望标准的 FHIR 端点。此豁免仅适用于 FHIR 路由组,不影响内部 API。

/fhir/R4/                    — FHIR R4 标准 endpoint
├── /metadata                 — CapabilityStatement服务器能力声明
├── /Patient                  — 患者资源 CRUD
│   ├── GET    /              — 搜索_id, name, identifier, birthdate
│   ├── GET    /{id}          — 读取单个
│   └── GET    /{id}/$everything — 患者全景数据
├── /Observation              — 观测数据(体征 + 设备读数)
│   ├── GET    /              — 搜索patient, category, code, date, device
│   ├── GET    /{id}          — 读取单个
│   └── GET    /$lastn        — 患者最近 N 次观测
├── /Device                   — 设备资源
│   ├── GET    /              — 搜索
│   ├── GET    /{id}          — 读取
│   └── POST   /              — 注册新设备V2a
├── /DiagnosticReport         — 化验/诊断报告
│   ├── GET    /              — 搜索
│   └── GET    /{id}          — 读取
├── /Encounter                — 咨询/就诊记录
│   ├── GET    /              — 搜索
│   └── GET    /{id}          — 读取
├── /Appointment              — 预约
│   ├── GET    /              — 搜索
│   ├── POST   /              — 创建V2a
│   └── PATCH  /{id}          — 更新V2a
├── /Practitioner             — 医护人员
│   ├── GET    /              — 搜索
│   └── GET    /{id}          — 读取
└── /Task                     — 随访任务
    ├── GET    /              — 搜索
    └── GET    /{id}          — 读取

5.2 HMS → FHIR Observation 转换示例

以设备采集的心率数据为例:

// HMS device_readings 记录
{
  "id": "01901abc-def0-7000-8000-000000000001",
  "tenant_id": "t001",
  "device_id": "dev-xiaomi-8",
  "patient_id": "p-12345",
  "reading_type": "heart_rate",
  "value": 78.0,
  "unit": "bpm",
  "measured_at": "2026-05-04T14:30:00Z",
  "quality_indicator": "raw",
  "source": "ble_sync"
}

// ↓ 转换为 FHIR Observation ↓

{
  "resourceType": "Observation",
  "id": "01901abc-def0-7000-8000-000000000001",
  "status": "final",
  "category": [{
    "coding": [{
      "system": "http://terminology.hl7.org/CodeSystem/observation-category",
      "code": "vital-signs",
      "display": "Vital Signs"
    }]
  }],
  "code": {
    "coding": [{
      "system": "http://loinc.org",
      "code": "8867-4",
      "display": "Heart rate"
    }]
  },
  "subject": {
    "reference": "Patient/p-12345"
  },
  "device": {
    "reference": "Device/dev-xiaomi-8"
  },
  "effectiveDateTime": "2026-05-04T14:30:00Z",
  "valueQuantity": {
    "value": 78.0,
    "unit": "beats/minute",
    "system": "http://unitsofmeasure.org",
    "code": "/min"
  },
  "meta": {
    "source": "hms-device-ble",
    "lastUpdated": "2026-05-04T14:30:01Z"
  }
}

5.3 合作伙伴认证OAuth2 Client Credentials

认证流程:

1. 合作方在 HMS 管理后台注册
   → 获得 client_id + client_secret
   → 配置允许的 FHIR 资源范围和患者数据范围

2. 合作方请求令牌
   POST /oauth/token
   Body: grant_type=client_credentials&client_id=xxx&client_secret=xxx
         &scope=fhir/Patient.read+Observation.read
   → 返回 access_token (JWT, 1小时有效)

3. 合作方调用 FHIR API
   GET /fhir/R4/Observation?patient=p-12345&category=vital-signs&date=gt2026-05-01
   Header: Authorization: Bearer <access_token>

4. HMS 验证
   → JWT 签名验证
   → tenant_id 匹配(合作方只能访问所属租户数据)
   → scope 验证(只允许已授权的资源操作)
   → 患者 ID 范围验证(合作方只能访问授权的患者列表)

5.4 数据隔离矩阵

维度 隔离方式 说明
租户 JWT tenant_id 合作方只能访问所属租户数据
资源类型 OAuth scope Patient.read / Observation.read
患者范围 白名单/黑名单 合作方可访问的患者 ID 列表
时间窗口 可选限制 数据只开放最近 N 天
频率 限流 每合作方每分钟最大请求数

5.5 $everything 操作

患者全景数据一次请求获取,用于 HIS 系统拉取完整健康档案、体检中心出报告参考、转诊数据导出:

GET /fhir/R4/Patient/{id}/$everything

返回 Bundle包含
├── Patient 本身
├── 所有 Observation体征 + 设备读数,支持 _count 分页)
├── 所有 DiagnosticReport化验报告
├── 所有 Encounter就诊记录
├── 所有 Appointment预约
├── 所有 Task随访任务
└── 关联的 Device 列表

6. 告警引擎与实时监控

6.1 现有告警引擎(已实现)

alert_engine.rs 已实现完整的规则评估流程:

  • 加载租户+设备类型的活跃规则
  • 批量查询近期告警实现 cooldown
  • 批量查询 vital_signs_hourly 近 168 小时数据
  • 3 种评估器:single_threshold(阈值)、consecutive(连续超标)、trend(趋势恶化)
  • 血压/血糖特殊处理(从 JSONB raw_value 提取收缩压/舒张压)
  • 告警创建 + alert.triggered 事件发布
  • 事件消费者发送站内通知

本设计不做重复实现。 以下 §6.2-6.5 仅描述增强内容

6.2 告警降噪增强

现有引擎已有 cooldown 机制。V1 增加两级降噪:

层级 现有 增强
规则级 cooldown_minutes 已实现 无需变更
患者级 新增:同一患者连续低级别告警 → 自动升级为高级别
系统级 新增5 分钟内同一设备的多个告警合并为一条通知
device_readings 写入
        │
        ▼
  规则加载器(从 device_alert_rules 缓存)
        │
        ▼
  ┌─────────────────────────────────────────┐
  │           规则评估器                      │
  │                                         │
  │  ┌─────────┐ ┌──────────┐ ┌─────────┐  │
  │  │单次阈值  │ │连续超标   │ │趋势恶化  │  │
  │  │评估器   │ │评估器     │ │评估器    │  │
  │  └────┬────┘ └─────┬────┘ └────┬────┘  │
  │       │            │           │        │
  │       └────────────┴───────────┘        │
  │                    │                    │
  │              告警触发?                  │
  │              Yes ↓                      │
  └──────────────────┼─────────────────────┘
                     │
                     ▼
              生成 HealthAlert
                     │
              EventBus 发布
              device.alert.triggered
                     │
          ┌──────────┼──────────┐
          ▼          ▼          ▼
     SSE 推送    消息通知    行动收件箱
     (医生Web)   (护士站)    (待办聚合)

6.2 规则类型

类型 1单次阈值Threshold

{
  "rule_name": "心动过速预警",
  "reading_type": "heart_rate",
  "rule_type": "threshold",
  "condition": {
    "operator": "gt",
    "value": 120,
    "unit": "bpm"
  },
  "severity": "high",
  "cooldown_minutes": 30
}

类型 2连续超标Consecutive

{
  "rule_name": "高血压持续预警",
  "reading_type": "blood_pressure_systolic",
  "rule_type": "consecutive",
  "condition": {
    "operator": "gt",
    "value": 140,
    "consecutive_count": 3,
    "within_minutes": 60
  },
  "severity": "critical",
  "cooldown_minutes": 120
}

类型 3趋势恶化Trend

{
  "rule_name": "血糖恶化趋势",
  "reading_type": "blood_glucose",
  "rule_type": "trend",
  "condition": {
    "baseline_window_days": 7,
    "change_threshold_percent": 20,
    "direction": "up",
    "min_samples": 5
  },
  "severity": "medium",
  "cooldown_minutes": 1440
}

6.3 实时看板(医生 Web 端)

┌─────────────────────────────────────────────────────────────────┐
│ 实时体征监控台                                       [自动刷新] │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  告警摘要栏                                                      │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐           │
│  │ 危急  2  │ │ 高危  5  │ │ 中等  12 │ │ 低危  3  │           │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘           │
│                                                                 │
│  患者列表(按告警优先级排序)                                      │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │ 🔴 张三 | 心率 135bpm ↑ | 血压 158/95 | 最近同步 2分钟前   │  │
│  │ 🟠 李四 | 血糖 285mg/dL | 趋势: 7天+35%  | 15分钟前       │  │
│  │ 🟡 王五 | SpO2 93% ↓    | 心率 98bpm    | 30分钟前        │  │
│  │    赵六 | 心率 72bpm 正常 | 步数 3,200   | 1小时前         │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  患者详情(点击展开)                                              │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │ 张三 | 男 58岁 | 高血压+糖尿病 | 设备: 小米手环8           │  │
│  │                                                           │  │
│  │ 心率趋势 (24h):                    血压趋势 (7天):         │  │
│  │ ┌─────────────────────┐          ┌─────────────────────┐  │  │
│  │ │  ╱╲    ╱╲   ╱╲╱╲   │          │ ╱╲                  │  │  │
│  │ │   ╲╱╱ ╲     ╲  │          │╱  ╲╱╱  ╱╲╱╱  ╱╲     │  │  │
│  │ │╱         ╲╱       ╲│          │        ╲╱     ╲     │  │  │
│  │ └─────────────────────┘          └─────────────────────┘  │  │
│  │                                                           │  │
│  │ 最近告警:                                                  │  │
│  │ 14:32 心率 135bpm → 触发心动过速预警 (高危)                  │  │
│  │ 14:15 收缩压 158mmHg → 连续第3次超标 (危急)                │  │
│  │                                                           │  │
│  │ [查看完整数据] [AI 分析] [发起咨询] [调整告警阈值]            │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘

6.4 SSE 推送(已实现,需增强)

现有 sse_handler.rs 已实现三种事件推送:

SSE 事件 触发源 过滤方式
message message.sent 按收件人 user_id
alert alert.triggered 按医患关系
vital_update device.readings.synced 按医患关系

V1 需增强的内容:

增强 说明
Last-Event-ID 支持 SSE 重连时从断点续传
心跳机制 定期 ping 保持连接活跃
订阅范围 医生可选择性订阅特定患者的更新

6.5 告警降噪机制

高频设备数据容易产生告警疲劳,三级降噪:

层级 机制 说明
规则级 cooldown 窗口 同一患者同一规则在冷却期内不重复触发
患者级 告警升级 同一患者连续低级别告警 → 自动升级为高级别
系统级 告警聚合 5 分钟内同一设备的多个告警合并为一条通知
示例:
10:00  心率 > 100  → 中等告警(单独通知)
10:05  心率 > 105  → 中等告警(冷却期内,不通知)
10:10  心率 > 110  → 连续3次超标 → 升级为高危告警(通知)
10:15  SpO2 < 95%  → 中等告警 → 与心率告警聚合为 1 条通知

7. 演进路线与风险分析

7.1 V1 详细周计划12 周)

W1-2基础设施 + 数据层

  • devices / device_readings / device_reading_hourly / device_reading_daily 表迁移
  • ReadingType 枚举 + LOINC 映射常量
  • 摄入 API handlerPOST /api/v1/health/device/readings
  • 降采样 background task小时/日聚合)
  • EventBus 新增事件类型

W3-4小程序 BLE 采集层

  • BleManager + AdapterRegistry
  • XiaomiBandAdapter第一个适配器
  • DataSyncScheduler + DataBuffer
  • 设备管理页面(绑定/解绑/同步状态)
  • E2E 测试:手环 → 小程序 → 后端 → 数据库

W5-6告警引擎

  • device_alert_rules 表 + CRUD API
  • 三种规则评估器threshold / consecutive / trend
  • 告警降噪cooldown + 升级 + 聚合)
  • SSE 推送扩展
  • 规则引擎单元测试 + 集成测试

W7-8告警看板 + 第二个适配器

  • 实时体征监控台页面Web
  • OmronBpAdapter血压计验证适配器扩展性
  • 患者体征趋势图(复用 ECharts
  • 看板页面测试

W9-10FHIR 只读 API

  • /fhir/R4/ 路由组 + 独立认证中间件
  • HMS → FHIR 转换层Patient / Observation / Device
  • 搜索参数支持patient, category, code, date
  • $everything 操作
  • FHIR 一致性测试

W11-12合作伙伴认证 + 集成测试

  • OAuth2 Client Credentials 实现
  • 数据隔离矩阵(租户/资源/患者范围/频率)
  • API 限流 + 审计日志
  • 合作方管理页面(注册/密钥/权限配置)
  • 全链路集成测试 + 性能测试

7.2 V2 扩展路线

阶段 时间 内容 前置条件
V2a 4-6 周 居家设备适配器 ×3 + FHIR 写入 API V1 完成
V2b 6-8 周 DeviceGateway + HL7 适配 + Webhook 推送 V2a 完成
V2c 4-6 周 合作方自助接入 + 设备厂商插件 SDK V2b 完成

7.3 与 Q2 路线图的协同

当前 Q2 路线图W1-8已排满技术债清理和 AI 前端补全。建议策略:

策略 说明 影响
顺延(推荐) Q2 专注技术债 + AI 前端Q37-9 月)启动 IoT V1 不影响 Q2 计划IoT 交付推迟到 Q3 末
并行 Q2 W5-8 开始 IoT 基础设施(表迁移 + 摄入 APIQ3 做前端和 FHIR 前后端分离交付,风险可控
替换 用 IoT V1 替换 Q2 的实时体征管线计划(两者本质相同) 最紧凑,但需重新评估测试覆盖目标

7.4 风险矩阵

风险 概率 影响 缓解措施
BLE 协议碎片化 — 不同厂商 BLE Service UUID 不同 V1 只支持 2 款设备AdapterRegistry 抽象层隔离差异
FHIR 合规性 — 自实现 FHIR server 可能不完全符合规范 V1 只做 read-only 6 个资源,后续评估引入 fhir-sdk crate
高频数据写入性能 — 日增 115 万条原始读数 降采样 + 分区索引 + 批量写入PostgreSQL 单表可承受千万级
小程序 BLE 兼容性 — 微信 BLE API 在不同手机行为不一致 真机测试矩阵DataBuffer 离线兜底
合作伙伴数据安全 — 医疗数据通过 API 暴露给第三方 极高 多层隔离(租户+scope+患者白名单+限流+审计日志)
告警疲劳 — 高频数据导致过多告警 三级降噪 + cooldown + 告警升级 + 可配置阈值

8. 与现有模块的变更清单

8.1 erp-health 变更

变更 类型 状态 说明
device_readings Entity + 摄入服务 已有 完整的批量摄入+去重+校验
vital_signs_hourly 聚合 已有 小时聚合完整
alert_rules + alert_engine 已有 3 种规则类型完整
EventBus 事件发布+消费 已有 device.readings.synced + alert.triggered
patient_devices 增强迁移 迁移 增强 增加 status/firmware_version/metadata 列
vital_signs_daily Entity + 迁移 迁移 新增 日聚合表
fhir 子模块 模块 新增 FHIR R4 路由组 + HMS→FHIR 转换层
日聚合 background task 代码 新增 从小时数据聚合为日数据
告警降噪增强 代码 增强 患者级升级 + 系统级聚合

8.2 erp-core 变更

变更 类型 状态 说明
事件类型 已有 device.readings.synced + alert.triggered 已定义
无新增事件 现有事件足够

8.3 erp-auth 变更

变更 类型 状态 说明
api_clients 表 + 迁移 迁移 新增 合作方 client_id/secret_hash/scope
OAuth2 Client Credentials 流程 功能 新增 合作伙伴专用认证,与现有 JWT 中间件并行
FHIR 路由认证中间件 代码 新增 从 Bearer token 提取 api_client 上下文
client_secret 使用 Argon2 哈希 安全 新增 与现有用户密码哈希策略一致

8.4 erp-server 变更

变更 类型 状态 说明
/fhir/R4/* 路由组 代码 新增 挂载 FHIR API使用独立认证中间件
/oauth/token endpoint 代码 新增 OAuth2 token 签发
日聚合 background task 注册 代码 新增 复用现有 tasks 框架

8.5 erp-message 变更

变更 类型 状态 说明
SSE handler 已有 已推送 vital_update + alert 事件
Last-Event-ID 重连支持 增强 增强 SSE 断线续传
心跳机制 增强 增强 保持连接活跃

8.6 小程序变更

变更 类型 状态 说明
BLE 采集框架 + 3 个适配器 已有 XiaomiBand/BloodPressure/GlucoseMeter
HuaweiBandAdapter.ts 适配器 新增 华为手环支持
GenericBleAdapter.ts 适配器 新增 通用 BLE 设备
DataSyncScheduler.ts 服务 新增 定时自动同步调度
DataBuffer 持久化增强 增强 增强 离线缓冲持久化到 Storage
设备管理页面 页面 增强 增加设备状态/同步历史展示

8.7 Web 前端变更

变更 类型 状态 说明
实时体征监控台页面 页面 新增 告警摘要 + 患者列表 + 趋势图
设备管理页面 页面 新增 设备列表/状态/同步历史
告警规则配置页面 页面 新增 规则 CRUD + 启用/禁用
合作方管理页面(管理后台) 页面 新增 注册/密钥/权限/审计
SSE 事件监听增强 代码 增强 vital_update 事件已在监听,增加 Last-Event-ID