mcpField
F
fasten-ehr-integration

fasten-ehr-integration

github.com/stanfordspezi开发2614 次安装5 周前更新
代码仓库

关于 fasten-ehr-integration

fasten-ehr-integration 是面向开发者的分步技能,指导通过 Fasten Connect 将数字健康应用连接到患者授权的 EHR 数据。它涵盖经过验证的只读 FHIR 导入,并要求记录隐私与架构决策。

主要功能

  1. 01指导配置 Fasten Connect
  2. 02导入患者授权的 FHIR 数据
  3. 03通过 Webhook 下载导出文件
  4. 04逐阶段验证集成
  5. 05生成隐私与架构简报

适用场景

  1. 01将患者记录导入健康应用
  2. 02使用 EHR 沙盒测试集成

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/stanfordspezi/spezivibe --skill fasten-ehr-integration

安装后在 Claude Code 中输入/fasten-ehr-integration确认已加载。

详细介绍

Fasten EHR 集成

引导用户通过 Fasten Connect 将应用连接到真实的电子健康记录(EHR)数据,逐步完成从开发者账户到可正常运行且经过测试的集成:将患者的 FHIR 记录下载到应用自己的存储中,并保存一份隐私与架构决策摘要(docs/planning/ehr-connection-brief.md)。在这种架构中,健康数据最终会存储在用户的应用中,因此责任也由用户承担——隐私指导流程未完成前,切勿发布此集成。

适用场景

当用户希望:

  • 让患者将自己的医疗记录导入数字健康应用
  • 无需针对每个医疗系统单独集成,即可获取真实的 FHIR 数据(病症、药物、化验结果、文档)
  • 在正式上线前,基于逼真的 EHR 沙盒进行原型开发

以下情况不要使用此技能:

  • 应用必须向 EHR 写入数据,或由临床医生在 EHR 内启动应用——这属于 SMART on FHIR / 供应商市场的范畴
  • 数据源是可穿戴设备或 HealthKit——请使用 health-data-model-planning
  • 合成 FHIR 数据已足够——Fasten 发布了一个示例 EHI 导出(Epic 沙盒,JSONL),而 Synthea 或公共 SMART 沙盒无需任何账户

背景

Fasten Connect 是一个基于患者同意的记录聚合服务。应用无需逐个集成 EHR 供应商和医疗系统,只需嵌入一个小组件,由患者自行授权访问:

Patient ──logs into their own patient portal──▶ Provider EHR
   │                                                │
   ▼                                                ▼
Your app ◀──FHIR records (webhook + download)── Fasten Connect
  1. 应用嵌入 Fasten 的 Stitch 小组件。患者查找自己的医疗系统,并登录自己的患者门户(例如 MyChart)。凭据只会发送给医疗服务提供方,不会发送给应用。
  2. 授权后的连接会以 org_connection_id 的形式返回,由后端存储——这是持久的同意凭证。
  3. 后端请求批量 EHI 导出。Fasten 检索记录,并将其打包为 NDJSON/JSONL 格式的 FHIR 资源(每行一个资源;主要 EHR 患者访问 API 实际使用的是 R4)。
  4. Fasten 通过 webhook 向后端发送下载链接通知;后端下载文件。Fasten 会在 24 小时后从其存储中删除导出文件——在此流程中,应用中的副本将成为唯一副本。

这是由消费者主导的数据交换:患者行使 HIPAA 赋予的访问权,并指示将记录发送到应用。此流程为只读,不会向 EHR 回写数据。Fasten 还支持通过 TEFCA Individual Access Services 实现的身份验证流程,使用身份核验(CLEAR / ID.me)代替门户登录;其 API 接口相同。

规划优先流程

如果此技能在规划阶段运行——即应用尚不存在时(build-an-app 编排器会执行此操作)——步骤 2–7 中的验证关卡暂时无法执行。在这种模式下:尽可能完成步骤 1,完整走完“数据隐私”部分,并生成包含 Current mode: not started 的输出摘要。开发者账户和步骤 2–7 将在计划为此集成安排的实现里程碑中稍后完成——届时请再次使用此技能,完成全部流程及验证关卡。

工作方式

你是一位专业的集成指导人员。请逐步操作,确认每个阶段都能正常运行后再继续——此集成的核心是异步、由 webhook 驱动的流程,最后再统一调试远比逐步验证每个环节困难。不要一开始就抛出一堆问题。遇到令人意外的情况时,请对照官方文档进行核实——API 细节可能发生变化,应以文档为准。

步骤 1:了解应用

针对无法从项目中推断的信息,向用户询问:

  1. “你的后端技术栈是什么?它能接收公共 HTTPS 请求吗,还是我们在本地开发?”
  2. “下载的记录会存放在哪里——本地磁盘、数据库,还是云存储桶?哪些人应该能查看这些记录?”
  3. “先用沙箱,还是你已经可以使用实时模式?”
答案影响范围
后端技术栈和可访问性所有 Fasten API 调用和私钥都在服务器端;Webhook 投递需要公共 URL 或本地开发备用方案(步骤 5)
记录的存储位置“数据隐私”部分中的隐私讨论——存储、加密、访问和删除
测试模式还是实时模式测试密钥可访问约 24 个沙箱(FooClinic、Epic、Cerner、付款方沙箱);实时密钥可访问真实医疗系统

始终从测试模式开始。除可访问的医疗系统不同外,流程与实时模式完全相同。

**继续前请确认:**你已了解后端、存储位置,并且将从测试模式开始。


步骤 2:开发者账户和密钥

让用户自行完成这些操作——这是他们的账户,你绝不能接触他们的凭据:

  1. 在 Fasten Connect 开发者门户注册。
  2. 复制测试模式密钥对:公开 ID(public_test_…)和私钥(private_test_…)。私钥只显示一次——请立即保存。
  3. 门户要求提供重定向 URL——Fasten 在成功连接后重定向到的 URL,它也会通过查询参数接收连接参数。在标准 Stitch 弹出窗口/模态框流程中,结果还会通过组件事件在页面内传递,因此大多数集成会根据这些事件执行操作;应用的基础 URL 是合适的填写值。(重定向模式和移动设备深层链接流程会直接使用该 URL——如果应用采用这类流程,请参阅文档。)

然后配置项目:

  • 将两个密钥都放入服务器端环境配置(例如 .env.local),并确保文件已加入 gitignore。请给值加上引号——私钥可能包含特殊 shell 字符,环境文件解析器或 dotenv-expand 可能会错误处理这些字符。
  • 公开 ID 本来就是公开的(它会嵌入客户端组件)。私钥绝不能传到客户端:不得使用 NEXT_PUBLIC_/EXPO_PUBLIC_ 风格的前缀,不得包含在客户端构建包或移动应用二进制文件中。

API 使用 HTTP Basic 认证,认证地址为 https://api.connect.fastenhealth.com/v1——公开 ID 作为用户名,私钥作为密码。测试模式和实时模式使用相同的基础 URL;由密钥选择模式。

**继续前请验证:**使用任意经过认证的 GET 请求对密钥进行冒烟测试(例如,使用虚构 ID 调用导出状态端点):401 表示密钥错误或格式被破坏;404/JSON 错误表示认证成功。这可以提前两步发现引号配置错误,避免问题之后才暴露。


步骤 3:嵌入 Connect 组件

在患者需要连接医疗服务提供方的位置添加 Stitch v4 组件。Web 组件(适用于任何框架):

<link rel="stylesheet" href="https://cdn.fastenhealth.com/connect/v4/fasten-stitch-element.css">
<script type="module" src="https://cdn.fastenhealth.com/connect/v4/fasten-stitch-element.js"></script>

<fasten-stitch-element public-id="public_test_…">Connect a provider</fasten-stitch-element>

提供 React SDK(@fastenhealth/fasten-stitch-element-react)和 React Native 支持——请参阅 Stitch v4 文档。

监听元素的 eventBus DOM 事件。载荷以 JSON 字符串的形式放在 event.detail.data 中——请对其进行解析:

document.querySelector('fasten-stitch-element')
  .addEventListener('eventBus', (event) => {
    const payload = JSON.parse(event.detail.data);
    if (payload.event_type === 'widget.complete') {
      // payload.data: [{ org_connection_id, platform_type, connection_status, … }]
      // POST it to YOUR backend and persist org_connection_id
    }
  });

在服务器端保存每个 org_connection_id,并记录时间戳和连接元数据——它既是导出的 API 句柄,也是应用同意审计跟踪的起点。(更丰富的连接元数据,包括 EHR 提供时的 consent_expires_at,会通过 patient.connection_success Webhook 到达——步骤 5。)

**继续前请验证:**连接一个沙箱服务提供方——使用步骤 7 表格中的 FooClinic 账号 [email protected] / f00clinic 是最快的首次测试方式——并确认 org_connection_id 已保存到后端存储中。


第 4 步:请求导出

仅从后端执行:

POST https://api.connect.fastenhealth.com/v1/bridge/fhir/ehi-export
Authorization: Basic base64(public_id:private_key)
Content-Type: application/json

{"org_connection_id": "…"}

响应中包含 task_id;处理是异步的(耗时从几秒到几分钟不等,任务也可能超时——随后会收到 patient.ehi_export_failed webhook,因此请规划有上限的重试:由于 failure_reason 往往会被隐藏,请进行少量重试并逐步延长间隔,然后停止,并将情况告知用户或 Fasten 支持团队)。

确保用户了解:

  • 下载链接仅通过 webhook 发送。 状态端点(GET /v1/bridge/fhir/ehi-export/{task_id})仅供查询信息,会返回 pending/success/failed,不会返回链接;Fasten 的文档明确不建议轮询。若未注册 webhook 端点,就无法获取导出内容。
  • 该端点对每个 org_connection_id 都是幂等的——再次请求会返回现有任务。对于遗漏的 webhook 投递,文档说明的恢复方式包括 Fasten 的自动重试(约 24 小时内最多重试 4 次)、门户中的 Delivery Logs(可查看 15 天内的负载)以及测试模式下的 Webhook Simulator。(实际上,有人观察到再次请求会重新投递完成 webhook,但文档并未说明这一行为——不要依赖它来构建功能。)
  • 顺序说明: 请在首次导出前注册 webhook 端点(第 5 步),否则首次完成通知可能无处投递——在沙盒环境中,可通过幂等的再次请求安全地恢复。

继续前请验证: 已记录 task_id,且该任务对应的状态端点返回 pending 或 success。


步骤 5:接收 Webhook 并下载

实现一个 webhook 端点(例如 POST /api/webhooks/fasten),以便:

  1. 验证签名。 Fasten 遵循 Standard Webhooks 规范——使用任意 Standard Webhooks 库和门户中该端点的签名密钥进行验证。这是任何 webhook 端点的基础安全措施,适用于两种模式。注意:密钥按端点和模式区分——Fasten 的常见问题要求测试和正式环境使用不同的 webhook URL,且每个 URL 都有自己的签名密钥。
  2. 处理以下事件(每个负载信封都包含 api_mode、用于幂等处理的稳定 id、type 和 data):
    • patient.ehi_export_success — data 包含 task_id、org_connection_id、download_links[](url、export_type、content_type),以及按资源类型统计数量的 stats。自动订阅。
    • patient.ehi_export_failed — 由于真实错误可能包含 PHI,failure_reason 通常为 suppressed_please_contact。自动订阅。
    • patient.connection_success 和 patient.authorization_revoked — 默认未启用;请在门户中为该端点开启。撤销事件可能会批量发送。
  3. 立即下载。 使用相同的 Basic auth 获取每个 download_links[].url;API 会回复一个指向签名 URL 的重定向(有效期约为 10 分钟——如需新的 URL,请重新请求)。链接自 webhook 发送起 24 小时内有效;Fasten 会在 24 小时后删除导出文件。应将 webhook 视为应用接管文件的时刻。导出文件大小从数 MB 到数 GB 不等(取决于记录的丰富程度),请流式写入存储,而不要缓存在内存中。
  4. 尽快返回 2xx,并在确认后再进行耗时处理;投递失败时会使用相同的事件 id 重试。

在门户的 webhook 设置中注册端点 URL。

本地开发——webhook 必须能够访问开发者的机器:

选项方法说明
隧道(首选)cloudflared tunnel --url http://localhost:PORT(无需账户)或 ngrok http PORT;注册 https://<tunnel>/api/webhooks/fasten全自动。Quick tunnel 的 URL 每次重启都会变化——请更新门户中的 URL;另请注意,新端点会有新的签名密钥(也要更新环境变量;直接编辑现有端点的 URL 会保留密钥)
手动粘贴在门户中注册端点 URL,即使无法访问也可以(系统仍会尝试投递并记录日志),然后从 Webhooks → Delivery Logs 复制 patient.ehi_export_success 负载,粘贴到应用中一个运行相同下载逻辑的小型接收端点无需隧道;足以用于沙盒开发
托管收件箱(smee.io、requestbin)Fasten 自己的文档建议将这些服务用于临时测试仅限沙盒——切勿通过第三方收件箱转发真实患者的 webhook 流量

**继续之前请先验证:**在门户的 Webhook Simulator 中发送 webhook.test 事件,并确认端点收到事件(模拟器事件会走正常投递流程,因此会验证签名)。如果采用手动粘贴方式,则应改为将复制的负载传入接收端点,并确认文件已写入存储。然后端到端运行一次真实的沙盒导出。


第 6 步:解析和展示

导出文件采用 NDJSON/JSONL 格式:每行一个 FHIR 资源。请宽容地解析——现实中的记录往往杂乱无章:

  • 跳过格式错误的行,而不是让整个文件解析失败;防御性地将任何 Bundle 解包为其条目。
  • 按 resourceType 分组。典型的导出包含 Patient、Condition、MedicationRequest、AllergyIntolerance、Observation(通常占大多数,包括实验室检查和生命体征)、DiagnosticReport、Immunization、Procedure、Encounter、DocumentReference/Binary(通常是 PDF),以及作为参考数据的 Practitioner/Organization/Location。
  • 防御性地呈现名称、代码和日期:优先使用 .text,其次依次回退到 coding[].display → code;日期可能分散在 effectiveDateTime、onsetDateTime、authoredOn、issued、period.start 中。
  • 在密钥就绪前,你可以基于 Fasten 的示例导出 gist,构建并测试这一整层。
  • 如果应用需要正式的架构,请运行 fhir-data-model-design,并将传入的资源映射到其输出。

第 7 步:端到端测试

测试模式下可用的沙箱(完整的凭据列表:测试患者凭据):

沙箱凭据适用场景
FooClinic(Sandbox)—— Fasten 自有沙箱,包含 16 个角色[email protected] / f00clinic(11 个资源);[email protected] / f00clinic(包含 3,500 多个资源的肿瘤病历)首次运行;容量测试
Epic 沙箱fhircamila / epicepic1模拟真实的 Epic 格式数据
Cerner、athenahealth、支付方沙箱(Aetna、Cigna、Medicare、VA)请参阅凭据指南覆盖多种平台类型

端到端验证——集成完成前,以下每项都必须通过:

  • 小组件连接到沙箱提供方;org_connection_id 已在服务端持久化
  • 已从后端请求导出;已记录 task_id
  • 已收到 Webhook,并验证签名;文件已流式传输到应用存储
  • 记录已解析,并在应用 UI 中可见
  • 已处理 patient.ehi_export_failed:通过门户的 Webhook Simulator 测试处理程序(或向端点发送带签名的模拟负载);存在有界重试路径
  • 已在门户中启用 patient.authorization_revoked,并按照应用的同意政策进行处理——以相同方式测试(模拟器是沙箱测试路径;无法按需触发真实撤销事件)
  • 客户端包和版本控制中均不包含私钥

数据隐私:健康数据的去向

请明确地带用户逐项了解下表——这是创新者常常忽略、之后又追悔莫及的部分。这是产品指导,不构成法律建议;请说明,在正式上线前,应由法律顾问、合规负责人或机构隐私团队进行审查。

阶段健康数据由谁持有备注
门户登录仅服务提供方患者凭据会输入服务提供方自己的门户;在此流程中,应用和 Fasten 都不会存储这些凭据
检索与打包Fasten 的云(AWS;子处理方列于 trust.fastenhealth.com,均标注为美国)Fasten 表示,数据在传输中和静态存储时均经过加密,并且成功传输后,临时副本会在 24 小时内自动删除
导出文件静态存储(Fasten)Fasten,≤ 24 小时保留期限结束后删除;下载链接也会随之失效
Webhook 负载应用的后端(以及路径中的任何隧道或收件箱)包含标识符、统计数据和下载链接——链接仍需 API 密钥才能使用,但应将负载视为敏感信息;实时模式下不使用第三方收件箱
下载应用的后端基本身份验证 + 短时有效的签名 URL(约 10 分钟)
应用中的静态存储应用团队——无限期这是该架构的核心:应用持有这些记录。加密、访问控制、保留、删除和泄露响应现在都由应用承担

启用实时模式前必须做出的决定(在简报的「输出」部分记录):

  • 下载时转移保管责任。 24 小时后,此流程中唯一留存的副本就是应用中的副本。在真实记录进入系统之前,先决定记录存放在哪里、谁可以访问、如何加密,以及患者如何要求删除记录。
  • 监管框架取决于应用服务对象。 需要梳理以下三个分支:
    • 由消费者主导: 根据 HHS OCR 关于访问权和健康应用的指导,个人指定发送至既非受监管实体也非业务伙伴的应用的记录,不再受 HIPAA 规则约束;但 FTC《健康数据泄露通知规则》和州健康隐私法(例如,将消费者健康记录应用视为医疗保健提供者的 California CMIA,以及 Washington My Health My Data)很可能适用;此外,FTC Act Section 5 也适用于应用作出的任何隐私承诺。Fasten 的材料未涉及 HBNR;此项分析由应用团队自行负责。
    • 代表受监管实体行事: 该应用很可能属于需要签署 BAA 的业务伙伴,包括评估是否与 Fasten 签署 BAA。Fasten 的政策称,对于部分客户,Fasten“可能符合业务伙伴的定义”;Fasten 是否签署 BAA 尚未公开说明——请直接询问 Fasten。
    • 研究用途: 如果记录将用于研究,请在启用实时模式前联系 IRB,使连接和同意环节与研究知情同意流程保持一致,并检查所在机构的受监管实体身份和数据治理规则(数据风险分类、获批的存储环境——学术医疗中心通常都有此类规则)是否会改变存储和访问要求。 运行 digital-health-compliance-planning,查看完整分析。
  • 需要核实供应商声明。 Fasten 自称已通过 SOC 2 鉴证,并在营销材料中宣称“SOC2 & HIPAA-compliant”;但其隐私政策称其为“not directly subject to HIPAA”的 IAS 提供商。SOC 2 报告和 HIPAA 评估需通过其信任中心申请获取。对于正式部署,请索取这些材料;不要在应用自身的隐私说明中复述营销声明。
  • 同意由患者控制且会过期。 连接元数据可能包含 consent_expires_at——根据 Fasten 文档,仅当 EHR 提供该信息时才会包含(他们提到 HTI-2 的规定将于 2026 年 1 月生效,但 EHR 的支持仍不均衡)。患者可以撤销同意;撤销会停止后续数据获取,但不会撤销此前已披露的数据。对于已下载的数据,撤销同意后的现实选择是删除或归档并停止使用(例如因法律保全或审计需要):无论是否已披露,继续在产品中使用已撤销同意所涉数据,都可能与下文“停止后续使用”的义务相冲突。
  • Fasten 的同意条款会延伸至应用。 Fasten 的隐私政策称,作为 CARIN Alliance Code of Conduct 的签署方,它会对所有客户“强制执行”以下要求:仅在获得同意后使用、便于撤销同意,以及披露 AI/ML 的使用情况和与第三方共享的情况。请在注册时确认 Fasten Connect 协议中的具体延伸义务——应用的隐私政策和行为必须切实满足这些要求。
  • 密钥就是安全边界。 私钥授权每次导出和下载。仅在服务端保存,加入 gitignore;如发生泄露则轮换,并为每个环境使用单独的密钥对。
  • 尽量减少留存的数据。 导出内容往往超出大多数产品的需求,尤其是自由文本笔记和 Binary 文档。数据也可能包含敏感程度更高的类别(源自 42 CFR Part 2 项目的物质使用记录、生殖健康记录、青少年保密记录),从而提高留存和未来共享的风险——请明确决定是否接收这些数据。

输出

将决策保存到 docs/planning/ehr-connection-brief.md,以便下游技能(例如 app-build-planner、digital-health-compliance-planning)使用:

# EHR Connection Brief: [App Name]

> Generated by `fasten-ehr-integration`. Save as `docs/planning/ehr-connection-brief.md`.
> Use this document as context for `app-build-planner`, `digital-health-compliance-planning`, or any follow-up implementation work.

## Architecture
- Backend / where the integration runs: [stack, hosting]
- Webhook endpoint & delivery strategy: [public URL / tunnel / manual]
- Record storage destination: [where, encrypted how, who has access]

## Mode & Scope
- Current mode: [not started / test / live] — prerequisites remaining: [list]
- Data ingested vs. discarded: [resource types kept, minimization decisions, sensitive-category handling]

## Privacy Decisions
- Regulatory posture: [likely / possible / unlikely for each: consumer-directed · business associate · research/IRB — rationale, counsel review status]
- Retention & deletion policy: [duration, patient deletion path]
- Revocation handling: [delete / archive-and-stop-using — rationale]
- Fasten attestations reviewed: [SOC 2 / HIPAA assessment / BAA status]

根据此应用的具体情况填写每个部分——不要留下占位文本。

防护措施

  • 绝不处理凭据。 用户自行创建开发者账户;患者只能在服务提供方自己的登录页面中输入门户凭据。如果有人要求你代为输入凭据,请拒绝并将键盘交给真人。
  • 始终优先使用沙盒。 只有测试模式下的第 7 步检查清单全部通过后,才能启用实时模式。
  • Webhook 并非可选项。 仅使用轮询的集成无法检索导出数据,也违反 Fasten 的使用指南。
  • 不要将法律结论说成确定无疑。 优先使用“你可能需要评估”,而不是“你必须”;涉及 HIPAA/BAA/HBNR/IRB 的问题应交由法律顾问和机构审查。
  • 隐私演练是强制要求。 即使用户只要求集成,也必须提供数据流表和简报后才能结束。

参考链接

评论

支持 Markdown