iT邦幫忙

2026 iThome 鐵人賽

DAY 30
0

摘要
走到 Day 30,我們完成了 TW Lab Contract Gate:一個以 Spring Boot + HAPI FHIR R4 建立的 TW Core lab Bundle exchange quality gate。從最初的 Bundle JSON parsing、FHIR R4 validation、TW Core profile validation,到合作方交換契約規則、契約版本比較、terminology evidence、sandbox readiness、SMART/OAuth token boundary、live sandbox read/search evidence、PHI masking、AuditEvent / Provenance preview,這 30 天把一個單純的驗證工具推進成可展示、可測試、可說明安全邊界的 pre-exchange quality gate。

回顧 Day 1-30

  • Day 1-6:建立 Spring Boot + HAPI FHIR R4 parsing / validation layer,補上 Bundle type gate、OperationOutcome 顯示、TW Core package loading 與 graceful degradation。
  • Day 7-13:完成六條 MVP lab exchange contract rules,涵蓋 Observation.subjectDiagnosticReport.result、report / observation patient consistency、LOINC、UCUM、Quantity unit。
  • Day 14-17:把合作方 contract v1.0 / v1.1 比較接回畫面,將新增、移除、嚴格化與放寬差異轉成可解讀的升版修正證據。
  • Day 18:加入 Docker、Docker Compose 與 GitHub Actions,讓 Maven test / package / Docker build 可以在乾淨環境重現。
  • Day 19-22:整理 Quality Test Report、驗證覆蓋證據、contract metadata、lifecycle evidence,以及 live FHIR /metadata endpoint safety。
  • Day 23:把 contract terminologyPolicy 從文件 metadata 推進到 terminology server ValueSet/$expand$validate-code evidence。
  • Day 24-26:補上 sandbox readiness、non-PHI guard、privacy / retention evidence,以及 request-scoped FHIR R4 AuditEvent / Provenance preview。
  • Day 27-29:補強 SMART/OAuth sandbox token flow evidence、safe live read/search policy readiness,最後推進到 allowlisted sandbox Patient / Observation / DiagnosticReport read / search-type execution evidence。
  • Day 30:整理整個專案的完成狀態、核心流程、安全邊界與個人心得,讓作品可以清楚放進 README、履歷與作品集脈絡。

核心流程

  1. 輸入與基礎驗證

使用者可以貼上或上傳 FHIR Bundle JSON,也可以選擇 built-in synthetic sandbox lab fixture。系統先切出基礎驗證層:

https://ithelp.ithome.com.tw/upload/images/20260831/201779132bovawmUmL.jpg

  • JSON parse:確認輸入是不是合法 JSON。
  • FHIR R4 parse:確認 JSON 能不能被 HAPI FHIR 解析成 R4 Resource。
  • Resource Type Gate:目前只接受 Bundle,並要求 Bundle.type = collection
  • FHIR R4 validation:顯示 OperationOutcome issues。
  • TW Core validation:在 package 可安全載入時執行 TW Core profile validation,無法載入時以 graceful degradation 呈現。
  1. 合作方交換契約

專案內建 demo lab contracts:

src/main/resources/contracts/demo-lab-v1.0.json
src/main/resources/contracts/demo-lab-v1.1.json
src/main/resources/contracts/demo-lab-hospital-a-v1.2-reference.json

預設 contract 是:

demo-lab-hospital-a#1.1

Quality Gate 會根據 contract 執行六條 MVP lab exchange rules:

  • LAB-REF-001Observation.subject 必須指向 Bundle 內的 Patient。
  • LAB-REF-002DiagnosticReport.result 必須指向 Bundle 內的 Observation。
  • LAB-REF-003:DiagnosticReport 與 Observation 必須指向同一個 Patient。
  • LAB-CODE-001:Observation LOINC code 必須符合 contract allowed set。
  • LAB-UNIT-001:Quantity observation 必須有可讀單位。
  • LAB-UNIT-002:UCUM system / code 必須符合 contract allowed set。

SHALL failure 會成為 blocking issue,SHOULD / MAY failure 則以 warning 呈現。這讓 report 不只回答「FHIR 合不合法」,也回答:

這份 lab Bundle 是否符合合作方交換契約?

https://ithelp.ithome.com.tw/upload/images/20260831/20177913aoccpvfKaw.jpg

  1. Evidence layers

完成後的首頁會產生 English-first Quality Test Report,主要 evidence layer 包含:

https://ithelp.ithome.com.tw/upload/images/20260831/201779139jXK2YYiYv.jpg

  • JSON parse
  • FHIR R4 parse
  • Resource Type Gate
  • FHIR R4 validation
  • TW Core validation
  • Contract lifecycle
  • Exchange contract rules
  • Unit normalization evidence
  • Terminology server evidence
  • Live FHIR metadata evidence
  • Sandbox readiness evidence
  • Sandbox live read/search execution policy evidence
  • PHI masking / privacy evidence
  • AuditEvent / Provenance resource preview evidence
  • Final Quality Gate outcome

其中 terminology、metadata、sandbox、privacy、audit / provenance 都是 report evidence layer,不會取代本地 contract gate。最終 blocking outcome 仍然以 FHIR / TW Core failure、contract lifecycle blocker,以及 blocking contract rule failure 為主。

https://ithelp.ithome.com.tw/upload/images/20260831/20177913ThtZizq84E.jpg

  1. Sandbox 與 live evidence 邊界

Day 29 後,專案可以在所有 safety gate 通過時產生 request-scoped sandbox read/search evidence,但範圍刻意很窄:

GET {sandboxBase}/Patient/{id}
GET {sandboxBase}/Patient?_id={id}
GET {sandboxBase}/Observation/{id}
GET {sandboxBase}/Observation?_id={id}
GET {sandboxBase}/DiagnosticReport/{id}
GET {sandboxBase}/DiagnosticReport?_id={id}

執行條件包含:

  • sandbox base URL 必須 allowlisted。
  • sandbox auth mode 必須通過。
  • 使用者必須確認 synthetic/non-PHI。
  • non-PHI preflight 不可發現直接 Patient identifier。
  • CapabilityStatement 必須宣告對應 read / search-type
  • OAuth token evidence 若啟用,必須安全通過。

report 只顯示 endpoint called、HTTP status、masked response summary、expected id match 與 retention policy。它不顯示 raw server response,不保存 validation history,不提交 Bundle,也不執行 production endpoint、create、update、delete 或 Bundle submit。

https://ithelp.ithome.com.tw/upload/images/20260831/20177913exjIhIZB76.jpg

  1. Privacy / Audit / Provenance

專案最後補上的 privacy 與 audit layer,是為了讓 quality gate 不只「會驗證」,也能說明資料怎麼被處理。

目前 report 明確呈現:

  • input SHA-256。
  • PHI masking policy version。
  • masked field categories。
  • raw Bundle policy。
  • retention policy:request-scoped only / no persistent history。
  • AuditEvent JSON preview。
  • Provenance JSON preview。
  • generation policy:generated request-scoped only; not persisted; not submitted。

這不是正式 production audit platform,但已經建立未來接 persistent audit log 或外部 FHIR repository 前所需的最小 resource shape。

https://ithelp.ithome.com.tw/upload/images/20260831/201779138SLB9iQyY4.jpg

完成後的專案定位

這個專案最後不是一般 FHIR validator,也不是正式醫療交換平台。它比較像一個介於兩者之間的 pre-exchange quality gate:

TW Lab Contract Gate
   ├─ Parser:資料能不能被讀懂
   ├─ Validator:資料是否符合 FHIR / TW Core
   ├─ Contract Gate:資料是否符合合作方交換契約
   ├─ Evidence Report:terminology / metadata / sandbox / privacy / audit evidence
   └─ Safety Boundary:只做 request-scoped, allowlisted, non-PHI sandbox evidence

它想回答的是這個系列第一天提出的問題:

If a healthcare Bundle passes standard validation, is it really ready to exchange?

經過 30 天後,答案變得更完整:

不只要看 FHIR validation。
還要看 TW Core profile、合作方 contract、reference completeness、terminology evidence、endpoint safety、sandbox readiness、PHI masking、retention policy,以及 audit / provenance evidence。

個人心得

  1. 背景經歷

雖說醫資系上有相關課程,不過剛開始我對 FHIR 的理解都停留在基礎理論上,甚至 TW Core 是從零開始接觸。過去比較熟悉的是一般 Web 開發或後端 API 流程,但醫療交換不是單純把 JSON 傳出去就結束,而是牽涉標準、Profile、Reference、Terminology、合作方契約與安全邊界。

因此這 30 天比較像是邊做邊補領域知識。從 Day 1 先讓 Bundle 能被解析,到後面慢慢理解為什麼 ObservationDiagnosticReportPatient 之間的 reference 會影響交換品質,也讓我感受到醫療資訊系統的嚴謹程度與一般練習專案的不同之處。

  1. 動機

如果只是做一個表單或 CRUD 系統,雖然也能練習技術,但比較難看出資料品質、交換契約和驗證流程之間的關係。
而醫療資料交換剛好是一個很適合練習工程思維的題目,在衛福部近年全面推動 FHIR(國際醫療資料交換標準)的情況下,相關需求會明顯增加,尤其是與合作方進行契約交換時如何更嚴謹的統一格式。
它不能只追求畫面完成,也不能只看單一 API 成功。每一步都要問:

這份資料為什麼可以交換?
如果不能交換,原因要怎麼被看懂、測試、重現?

這讓我在每天實作時,不只是完成一個功能,而是在累積一套可以說明的 quality gate。

  1. 主題設計

主題一開始鎖定在 TW Core lab Bundle,是因為檢驗資料很適合展示跨 Resource 的交換問題。PatientObservationDiagnosticReport 都是常見 Resource,而且 lab code、unit、report result reference 都能對應到實際交換時會遇到的資料品質問題。

使用者動機設計

這個工具的使用者,不是一般消費者,而是需要檢查醫療資料交換品質的開發者、系統整合者或資料交換測試人員。因此畫面和流程的重點不是華麗互動,而是讓 report 可以快速回答:

哪一層通過?
哪一層失敗?
失敗是 blocking 還是 warning?
這個 evidence 有沒有真的呼叫外部 endpoint?
有沒有保存或顯示 PHI?

所以專案採用 Quality Test Report 的形式,把 JSON、FHIR、TW Core、contract rules、terminology、metadata、sandbox、privacy、AuditEvent / Provenance 分層呈現,讓使用者可以逐層檢查交換 readiness。

功能設計

功能設計上,我刻意把專案分成三個層次:

Parser:資料能不能被讀懂
Validator:資料是否符合 FHIR / TW Core
Quality Gate:資料是否符合合作方交換契約與安全邊界

前半段先把 parsing、validation、contract rules 做穩,後半段再補 terminology server evidence、sandbox readiness、OAuth token boundary、live read/search evidence、PHI masking 和 AuditEvent / Provenance preview。

簡單來說,TW Lab Contract Gate 就是希望讓醫療資料交換前,不只知道格式有沒有錯,也能知道這份資料是否已經具備進入下一步交換的證據。

  1. 遇到的困難

領域知識陌生

FHIR 和 TW Core 一開始最難的地方,是很多錯誤不是程式語法錯,而是交換語意不完整。例如 DiagnosticReport.result 沒有指到 Bundle 內的 Observation,JSON 本身可能完全合法,但交換時就會出問題。

這讓我花了很多時間理解 Resource 之間的關係、Profile validation 和 partner contract rule 的差異,也更理解為什麼單靠標準 validator 還不夠。

Debug 卡關

實作過程中也遇到很多技術卡關,例如 TW Core package loading、OperationOutcome issue 整理、contract version diff、terminology server response parsing、sandbox endpoint allowlist、OAuth token masking,以及 sandbox read/search response summary。

其中最需要小心的是後半段的安全邊界。sandbox live evidence 很容易一不小心就變成「可以讀取任意 Patient / Observation」的工具;OAuth token evidence 也可能不小心把 access token 或 client secret 顯示在 report 裡;AuditEvent / Provenance 如果放入 raw Bundle,又會造成 PHI 風險。

所以後面每天都在反覆確認:

這個 HTTP call 有沒有 allowlist?
這個 evidence 是 request-scoped 嗎?
這個 report 會不會顯示 PHI?
這個結果應該 blocking,還是只作為 evidence?

這些問題雖然讓開發速度變慢,但也讓專案從功能堆疊變成更有邊界感的工程練習。

  1. 收穫
  • 技術面:把 Spring Boot、HAPI FHIR R4、Maven test、Docker、CI 和 Thymeleaf report 串成一條完整流程。
  • 學習面:更理解醫療資料交換不能只看格式,還要看 reference completeness、terminology、contract lifecycle 和 evidence。
  • 工程面:學會每新增一個 live evidence layer,都要同步定義 allowlist、retention、masking、blocking policy 和「不做什麼」。

Day 30 完成後的邊界

目前專案可以:

  • 接收 pasted / uploaded FHIR Bundle JSON。
  • 執行 JSON、FHIR R4、TW Core、contract rule validation。
  • 比較 contract versions 並分類升版影響。
  • 呈現 terminology、metadata、sandbox、privacy、audit / provenance evidence。
  • 在所有 safety gates 通過時執行 allowlisted sandbox read/search evidence。
  • 以 Docker / Docker Compose / CI 重現測試與建置流程。

不包括:

  • production FHIR endpoint 呼叫。
  • Patient / Observation / DiagnosticReport create、update、delete。
  • Bundle submit。
  • full SMART launch / authorization-code flow。
  • persistent validation history。
  • raw Bundle、raw server response、raw access token、client secret 或 PHI 保存。
  • AuditEvent / Provenance 外部提交。

簡單來說,TW Lab Contract Gate 希望證明一件事:

醫療資料交換不能只問「格式對不對」。
更重要的是,要能說明「為什麼這份資料現在可以,或不可以,安全地進入下一步交換」。

上一篇
Day29 - Safe Sandbox Read/Search Evidence
系列文
醫療資料通過標準驗證,就真的能交換嗎?——30 天打造 TW Core 資料品質閘門30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言