Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
个人健康记录 (PHR) 应用与 FHIR
教程:基于 FHIR R4 的互联 PHR 的后端 — 来自个人、实验室、文件和设备的数据,时间线,可共享的 IPS,同意。已测试代码。
个人健康记录 (PHR) 应用会保存一个人的健康信息 — 结果、测量值、诊断、药物、文档 — 形成一个由个人控制的记录,这些信息从多个来源收集而来,而不是仅来自一家医院。 困难之处不在于界面设计:而在于以可用形式从实验室、诊所和设备获取数据,跟踪每项数据的来源,并允许个人在不失去控制权的情况下共享记录。本教程将使用 Anpheros TypeScript SDK 构建基于 HL7 FHIR R4 的 PHR 后端;下方代码已在本地平台实例上使用沙盒密钥运行。
关联式、独立式和互联式 PHR
| 类型 | 数据存储位置 | 局限性 |
|---|---|---|
| 关联式(医院的患者门户) | 提供者的 EHR | 仅显示该提供者的数据;当用户更换医生时会发生变化 |
| 独立式(独立应用程序或笔记本) | 应用程序自己的数据库 | 用户手动输入所有内容;数据很少离开应用程序 |
| 互联式 | 标准化记录,应用程序、实验室和诊所可在用户同意下读取和写入 | 需要底层有标准、同意和来源追溯 |
互联式 PHR 是今天值得构建的。它也是政策发展方向:在美国,经认证的 EHR 必须向患者提供基于 FHIR 的 API 访问其数据的权限(US Core),而在欧盟,欧洲健康数据空间(European Health Data Space)赋予人们访问其电子健康数据并与他们选择的提供者共享的权利,该计划将从 2029 年开始分阶段实施。
PHR 数据来源
- 个人: 家庭测量数据、症状、用药情况、已知的健康状况。将其标记为患者报告。
- 实验室报告: 大多数人收到的是 PDF 文件;一些实验室可以发送 HL7 v2 或 CSV 格式。每个结果都应成为一个编码的 Observation(实验室结果 API)。
- 文档: 出院信、影像报告、处方。将原始文件保持不变,与结构化数据一起存放。
- 设备和可穿戴设备: 来自 Apple Health 或 Health Connect 的每日步数、心率、睡眠、血压(FHIR 中的可穿戴设备数据)。
- 提供者: 在美国,通过 SMART on FHIR 访问医院和保险公司的患者访问 FHIR API;在其他地区,主要是文档和摘要,例如 International Patient Summary。
每个来源都写入同一个记录。保持其可信度的关键在于,每条记录都应记录其编写者以及来自哪个系统(医疗数据溯源)。
架构
person ──► your PHR app (mobile / web) ──► your backend ──► Anpheros: one FHIR R4 record per person
│ ├─ Observations, Conditions, Medications, Documents…
lab report, PDF, device data ───────────────┘ ├─ Provenance on every write
├─ access log the person can see
other apps, doctors, AI assistants ◄── consent (OAuth) ───────┴─ $summary (IPS) to share
您的后端持有项目密钥(沙盒环境中的sk_test_…,切勿在应用中存储)。您的应用通过您自己的身份验证系统为用户登录,并与您的后端通信;后端将每个用户映射到一个患者记录。
步骤详解
安装 SDK (npm install @anpheros/sdk) 并从 仪表板 获取免费沙盒密钥。示例使用双结果 HL7 v2 血脂检查 (lipid-panel.hl7) 和任意 PDF (report.pdf)。
import { readFile } from 'node:fs/promises';
import { Anpheros, apiKey } from '@anpheros/sdk';
const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) });
// 1. One record per person who signs up in your PHR app
const jane = await anpheros.patients.create({ given: 'Jane', family: 'Doe', birth_date: '1984-07-19', gender: 'female' });
// 2. Something the person measured at home
await anpheros.observations.create(jane.id, {
code: '85354-9', category: 'vital-signs', effective_at: '2026-10-01T08:30:00-05:00', author_type: 'patient',
components: [{ code: '8480-6', value: 128, unit: 'mm[Hg]' }, { code: '8462-4', value: 82, unit: 'mm[Hg]' }],
});
// 3. A diagnosis and a medication the person reports
await anpheros.conditions.create(jane.id, { code: 'E11.9', system: 'http://hl7.org/fhir/sid/icd-10',
display: 'Type 2 diabetes mellitus without complications', clinical_status: 'active', onset: '2021-03-15', author_type: 'patient' });
await anpheros.medications.create(jane.id, { code: 'A10BA02', display: 'Metformin 500 mg', status: 'active',
dosage: '500 mg twice a day', start: '2021-03-20', author_type: 'patient' });
// 4. A lab report the person received, as the lab sent it (HL7 v2)
const lab = await anpheros.labs.importHl7(jane.id, await readFile('lipid-panel.hl7', 'utf8'), { sourceSystem: 'springfield-lis' });
// 5. A PDF they want to keep with the record
const doc = await anpheros.documents.upload(jane.id,
{ title: 'Chest X-ray report', kind: 'imaging_report', content_type: 'application/pdf', date: '2026-10-03' },
await readFile('report.pdf'));
// 6. One timeline for the home screen
const timeline = await anpheros.timeline.list(jane.id, { limit: 10 });
// 7. A summary to share with a new doctor: the International Patient Summary
const ips = await anpheros.fhir.summary(jane.id);
// 8. Who else can read this record (empty until the person consents to another app)
const grants = await anpheros.grants.of(jane.id);
从该运行中打印:
lab: created 2, unmapped []
document: final
timeline: 2026-10-03 document Chest X-ray report
2026-10-02 observation Cholesterol in HDL [Mass/volume] in Serum or Plasma
2026-10-02 observation Cholesterol [Mass/volume] in Serum or Plasma
2026-10-01 observation Blood pressure panel
2021-03-20 medication Metformin 500 mg
2021-03-15 condition Type 2 diabetes mellitus without complications
IPS: Allergies, Medications, Problems, Results, Vital signs
grants: 0
以上所有内容均存储为 FHIR R4 — Patient、Observation、Condition、MedicationStatement、DocumentReference — 因此可以使用任何 FHIR 客户端 (GET /fhir/R4/Patient/{id}/$everything) 读取相同的记录,并将其完整地移至其他位置。SDK 中的 /v1 调用是相同资源的简化视图;Medical data API 列出了它们。
在不失控的情况下共享
PHR 的存在就是为了在用户可控的前提下进行共享:
- 与医生共享: 国际患者摘要(
$summary)是一个为临床医生设计的 FHIR 文档——包含病情、用药、过敏、检查结果等信息——您的应用程序可以显示、打印或发送。 FHIR 平台 介绍了$summary和$everything。 - 与其他应用程序共享: 其他应用程序通过 OAuth 2.1 和 SMART on FHIR 请求授权;用户可以选择共享哪些数据(例如仅实验室结果)以及共享多长时间,并可以随时撤销。 如何使用 SMART on FHIR 实现患者授权 详细介绍了这一过程。
- 与 AI 助手共享:
POST /v1/context为模型构建了一个有预算、有来源标记的记录摘要,并且读取操作会记录在访问日志中(如何构建 AI 医疗应用程序)。 - 透明度: 任何应用程序的每一次读取和写入操作都会按应用程序进行记录,用户可以查看日志和当前有效的授权。
家庭
许多 PHR 由一个人为多个家庭成员(孩子、伴侣、年迈的父母)管理。为每个人创建单独的记录,并将其链接到监护人,而不是将所有人的数据混杂在一个记录中。然后,同意是按记录授予的。患者病历 描述了模型。
自己构建什么,不构建什么
您构建用户体验:入门引导、结果解释方式、提醒、图表、用户阅读的语言。Anpheros 提供记录、标准格式、同意、来源、访问日志以及实验室、文档和摘要操作。
Anpheros 今天不为 PHR 做什么:它不会代表用户登录医院患者门户或美国患者访问 API(您的应用程序可以使用 SMART on FHIR 客户端来实现这一点并写入接收到的内容),它不会通过 API 读取 PDF 报告,也不会提供医疗建议。Anpheros 自有的 PHR 应用 Anpheros Daily 是基于相同的 API 构建的。
常见问题解答
什么是个人健康记录 (PHR)?
个人健康记录 (PHR) 是由个人自己维护和控制的健康信息记录,这些信息汇集了多个来源——个人录入、实验室、诊所、设备——而不是由单一提供商保管。
PHR 和 EHR 有什么区别?
EHR 由医疗组织维护,涵盖其提供商记录的内容。PHR 由个人维护,可以整合来自其所有提供商和设备的数据。绑定的 PHR (tethered PHR) 是一个查看单一提供商 EHR 的窗口;连接的 PHR (connected PHR) 使用标准将多个来源整合在一起。
PHR 是否应该使用 FHIR?
如果数据将来要与医生、其他应用程序或 AI 助手共享,那么是的:FHIR R4 提供了其他系统已经理解的、经过编码和版本化的资源,并且它是美国患者访问 API 和欧洲患者摘要的格式。
PHR 应用如何从医院获取数据?
在美国,通过经过认证的 EHR 和许多保险公司公开的 FHIR 患者访问 API,使用 SMART on FHIR 允许个人授权应用程序。在其他地方,主要是通过文档和摘要,导入并与结构化数据一起存储。
PHR 应用应将 API 密钥保存在何处?
保存在您的服务器上。项目密钥可以读取您的项目创建的每一条记录,因此绝不能将其包含在移动或 Web 应用中;应用程序与您的后端通信,而其他人的应用程序则使用 OAuth 并获得个人的同意。
相关
- 构建医疗健康应用:通用指南
- 患者病历:病历内容及访问权限
- 数字化病历基础设施
- FHIR 中的可穿戴设备数据:Apple Health、Health Connect 和 Samsung Health
- 检验结果 API
- SDK
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card