iT邦幫忙

2026 iThome 鐵人賽

DAY 30
0

本文同步發表於個人部落格:讓更多人進來


三十天終於寫完了,現在,你手上應該有一個跑得動的 SMART app。

昨天把你學的東西分成兩種。一種是規範講死的,換伺服器、換語言都還在。另一種是我幫你選的,你隨時可以挑別的。今天要講的,是前面那一種要去哪裡查。

下面每一個連結我都在 2026 年 8 月左右實際查過一次,記下當時的狀態碼才寫進來。查不到的我就沒列進來。

網站會改版、路徑可能也會異動,所以你讀到的時候有可能已經不一樣了。不過,重點是這幾類資源各自能解決什麼問題,網址只是當下的入口而已。

你手上現在有什麼

經過三十天,你的專案是一支靠靜態網頁就跑得動的 SMART app。一個 HTML 進入點加幾支 ES module,沒有 package.json。不用裝套件,也沒有建置步驟。

它目前可以做的事情大致如下:

  • 完成 standalone 授權,帶 PKCE 與 state
  • .well-known/smart-configuration 找出授權端點,並把結果快取(Cache)起來
  • 讀病人基本資料、生命徵象、病況、用藥
  • 把資料畫成趨勢圖
  • 寫一筆自己量的血壓回去
  • 把五種失敗轉成看得懂的訊息
  • 跟完分頁,不會只拿到第一頁
  • 對兩家醫院各自授權,整合出一個有來源的時間軸

還有一件沒有呈現在畫面上的,但一樣很重要的:你知道它哪裡還不夠。

一個是稽核軌跡。誰在什麼時候讀了哪一筆病人資料,這種紀錄要一行一行留下來。day27 那張安全清單的最後一條就是它,你的 app 沒有。

另一個是快取。day22 把每台伺服器的授權端點存了下來,存活時間 24 小時。這段期間對方要是換了端點,只能靠人去按那顆清除按鈕,程式自己不會發現。

前面說的那八項,只要照著這三十篇做一次就會有,抄一份現成範例也會有。但兩個缺口不一樣。你要先知道稽核軌跡應該要有,也要知道快取需要失效路徑,才看得出這兩個缺口。

真的要讓別人用你的 app,卡住你的多半是這種缺口,不是少一個功能。清楚自己缺哪一項、卡在哪裡,下一步就知道要先補哪一個。

規範去哪裡看

看規範這件事,很多人卡在不知道從哪一份開始。順序是這樣。

SMART App Launch。 這是本系列從頭到尾在講的東西。

  • 正式版:https://hl7.org/fhir/smart-app-launch/
  • 持續建置版:https://build.fhir.org/ig/HL7/smart-app-launch/app-launch.html

兩個都通。正式版比較穩,持續建置版會比正式版早幾個修訂。要查現在到底該怎麼做,看正式版;要查以後會變成怎樣,看持續建置版。

FHIR R4 規範:https://hl7.org/fhir/R4/ 資源長什麼樣、有哪些搜尋參數,都在這裡。day03 教的那些 base resource 就出自這一份。

底下那三份協定。 SMART 不是憑空冒出來的,它是蓋在這三份上面的:

  • OAuth 2.0:https://datatracker.ietf.org/doc/html/rfc6749
  • PKCE:https://datatracker.ietf.org/doc/html/rfc7636
  • OpenID Connect Core:https://openid.net/specs/openid-connect-core-1_0.html

day07 到 day13 講的授權流程、PKCE 跟身分那幾塊,都可以追到這三份。scope 的寫法跟 launch context 是 SMART 自己訂的。那兩塊查 SMART App Launch。真的卡住的時候回頭翻,比找部落格文章可靠。

寫程式的時候會用到的

SMART Health IT 開發者文件:https://docs.smarthealthit.org/,授權那一章在 https://docs.smarthealthit.org/authorization/

這是本系列用的 fhirclient 那個團隊維護的。規範講的是應該怎麼做,這一份講的是這套程式庫怎麼用。

SMART Health IT Launcher:https://launch.smarthealthit.org/ 你這三十天一直在用的那台,這個系列從頭到尾都連得上。

SMART App Gallery:https://apps.smarthealthit.org/ 別人做出來的 SMART app 目錄。想知道這個技術實際被拿來做什麼,看這裡最快。

Synthea:https://synthetichealth.github.io/synthea/ sandbox 裡那些假病人就是它生出來的。它會自己跑出一批有完整病史的假資料。要另外裝執行環境,這裡只是告訴你有這條路可以走。

想要更多測試資料,或是想要有特定病況的病人,就是靠它自己生。

台灣自訂的部分

TW Core IG:https://twcore.mohw.gov.tw/ig/twcore/ day25 整篇在講的那份,衛福部的核心實作指引。

TWPAS IG:https://nhicore.nhi.gov.tw/pas/ 健保署的事前審查實作指引。

臺灣醫療資訊標準大平台:https://medstandard.mohw.gov.tw/ 標準相關的入口網。

TW App Gallery:https://medstandard.mohw.gov.tw/tw-app-gallery 同一個站台底下的應用程式目錄,按用途分成十類。

這一條是後來用瀏覽器補確認的,curl 只抓得到外殼。它不在下面那張圖上。

衛福部資訊處電子病歷專區:https://dep.mohw.gov.tw/DOIM/lp-7156-114.html 政策與公告會出現在這裡。

對應關係圖,米色底,標題「四類資源,各自解決一個問題」,副標「十五個網址逐條實抓,記下當天的 HTTP 狀態碼才列進來」。標題右側是一枚珊瑚色外框、淺粉底的圓角標籤,寫著「查證日 2026-08-09」。畫面由上而下四張卡片,每張卡片上緣是一條深藍色橫帶,橫帶左側白字寫類別名稱,右側淺藍字寫這一類解決什麼問題;橫帶底下是資源列,每一列由左到右依序是一枚寫著 200 的等寬字狀態碼徽章、資源名稱、以及等寬字的網址。第一張卡片整塊是深藍色,是這張圖的視覺錨點,橫帶寫著「規範本身」,後面接一枚珊瑚色標籤「順序從這裡開始」,右側寫「現在到底該怎麼做」;三列依序是 200 加 SMART App Launch 正式版 加 https://hl7.org/fhir/smart-app-launch/、200 加 SMART App Launch 建置版 加 https://build.fhir.org/ig/HL7/smart-app-launch/app-launch.html、200 加 FHIR R4 規範 加 https://hl7.org/fhir/R4/。第二張卡片是白底,橫帶寫「底層協定」,右側寫「卡住的時候回頭翻」;三列依序是 200 加 RFC 6749 OAuth 2.0 加 https://datatracker.ietf.org/doc/html/rfc6749、200 加 RFC 7636 PKCE 加 https://datatracker.ietf.org/doc/html/rfc7636、200 加 OpenID Connect Core 1.0 加 https://openid.net/specs/openid-connect-core-1_0.html。第三張卡片是白底,橫帶寫「開發時用得到的」,右側寫「這套程式庫怎麼用」;五列依序是 200 加 SMART Health IT 開發者文件 加 https://docs.smarthealthit.org/、200 加 同上的授權章節 加 https://docs.smarthealthit.org/authorization/、200 加 SMART Health IT Launcher 加 https://launch.smarthealthit.org/、200 加 SMART App Gallery 加 https://apps.smarthealthit.org/、200 加 Synthea 加 https://synthetichealth.github.io/synthea/。第四張卡片是白底,橫帶寫「台灣」,右側寫「本地要照哪一份」;四列依序是 200 加 TW Core IG 加 https://twcore.mohw.gov.tw/ig/twcore/、200 加 TWPAS IG 加 https://nhicore.nhi.gov.tw/pas/、200 加 臺灣醫療資訊標準大平台 加 https://medstandard.mohw.gov.tw/、200 加 衛福部資訊處電子病歷專區 加 https://dep.mohw.gov.tw/DOIM/lp-7156-114.html。圖片最下方兩行註記:第一行灰字寫「方法:curl -sS -L,跟隨轉址,逾時 20 秒,記錄最終的 HTTP 狀態碼」;第二行珊瑚色字寫「HL7 Taiwan 官網當天 HTTPS 連線被重置,不在這張圖上」

社群要去哪裡找

國際上有 HL7 的官方討論區 https://chat.fhir.org/,那裡有一個討論 SMART 的頻道。我只列站台首頁,不列頻道網址。那個網址的 # 後面是前端路由,伺服器回的 200 只能證明站台還活著。

台灣這邊我找了一下,原本想列 HL7 Taiwan 的官網。但實際去抓的結果是 HTTPS 連不上,回的是連線被重置。改用沒加密的 HTTP 才通。

我沒有把它列進來,理由有兩個。一是查證那天它的 TLS 是壞的。一篇在教你做醫療 app 的文章,叫你去連那樣一個站,說不過去。二是我自己沒有參與過那個組織,列了也只是轉貼一個網址。

台灣應該還沒有一個專門在講 SMART on FHIR 的開發社群。 至少我找不到。

如果有興趣,或許大家可以一起成立一個。一開始也不用很正式,幾個人聊聊就可以。

五個可以動手做的題目

這五個題目來自我自己專案裡的一份路線圖,每一個都評估過法遵風險跟要花多少工。

題目 在做什麼
縱貫式健康紀錄 病人看自己跨院的完整時間軸
主動式跨院異常追蹤 有新數值時比對歷史,跨院比
用藥對帳 多重用藥的整理與提醒
國際患者摘要 產出一份跨國可攜的病人摘要
跨院轉診全程追蹤 從轉出到回覆,兩邊醫院都要接入

第一個最適合當起點。 病人看的是自己的資料,沒有跨機構同意權的問題,而且使用者一眼就有感。你第四幕做的那條合併時間軸,已經是它的雛形了。

第二個要花的工最少,但要先有第一個。 剩下的幾乎只是把訊息組起來。價值在哪?單一家醫院只能說「這次升高了」,多家醫院才能說「這次比你過去每一次都高」。

第五個在那份路線圖上被標成擱置。 不是技術做不到,是兩家醫院都要願意接進來。那件事要先談成,比寫程式麻煩得多。

第四個要動手的話,規範在 https://hl7.org/fhir/uv/ips/。day25 介紹過它,那是國際病人摘要的實作指引。

取捨矩陣圖,米色底,標題「法遵風險對工程量,五個題目落在哪」,副標「兩個維度的評估出自專案裡那份多院應用路線圖」。縱軸標示法遵風險,由上而下三列分別是高、中、低;橫軸標示工程量,由左至右四欄分別是小、中、大、擱置;格線是淺米色的細線。高風險那一列只有最右邊的擱置欄有東西,是一個珊瑚色虛線外框、淺粉底的方塊,深紅色字寫「跨院轉診全程追蹤」,底下一枚珊瑚色外框的空心標籤寫著「擱置」。中風險那一列有三個題目:小工程量欄是一張白色卡片、左緣一條深藍直條,寫著「主動式跨院異常追蹤」;大工程量欄上下並排兩張同款白色卡片,上面那張寫「用藥對帳」,下面那張寫「國際患者摘要」;中工程量欄是空的。低風險那一列只有中工程量欄有東西,是整張圖唯一的深藍色實心方塊,也是最大的一塊,白色粗體字寫「縱貫式健康紀錄」,底下一枚珊瑚色實心標籤寫著「起點」。從這個深藍方塊的左緣拉出一條珊瑚色的線,往左走一段、直角轉彎、轉角帶圓角之後往上,箭頭指進中風險那一列的「主動式跨院異常追蹤」卡片底部,線的左側以珊瑚色寫著「要先有它」。圖片最下方一行灰字註記:三個中風險的題目,工程量小的一個、大的兩個。風險高低與工程量大小不是同一件事,要分開評

要動手之前,那份路線圖列的三個難題值得先看一眼:

  • 跨院怎麼認人。 不同醫院的 patient id 是不是同一個人
  • 每一家的資料長得不一樣。 檢驗代碼大多一致,但各院還是有自己訂的,單位跟參考區間也不一樣
  • 同意權管到哪裡。 在一台伺服器上拿到授權,不代表資料可以流到另一台去

第一個難題 day24 講過我們的做法:不做比對,讓病人每一家各自授權。 這個選擇順便也解掉了第三個難題。每一條連線都是病人本人授權的,合起來的又是他自己的資料。

跟著做:挑一個題目,寫三行字

最後一次跟著做。不寫程式。

從上面五個題目挑一個,或者你自己想一個。然後寫三行字:

第一行,它要讀哪些 FHIR 資源? 拿 day03 的清單對一次。讀不到的資源,這個題目就做不成。

第二行,它需要哪些 scope? 用 day10 和 day11 的規則組出來。組完看一眼,有沒有多要。

第三行,它會不會寫資料回去? 如果會,day18 和 day27 那條「唯讀要寫成自己訂的規則」要先想清楚。

三行寫完,你就有一份可以動手的規格草稿了。寫不出來的那一行,不是你能力不夠,是這個題目還沒想清楚。

這三十天到底做出了什麼

回頭看整個系列。

時序流程圖,米色底,標題「三十篇分成五幕,各自交出什麼」,副標「色塊寬度照篇數比例,光是第二幕就佔掉三分之一」。畫面分成上中下三層。上層是一條由五個深藍色色塊構成的橫條,寬度照篇數比例分配,左側灰字小標寫「三十篇怎麼分」;五個色塊由左到右依序是幕一 4 篇、幕二 10 篇、幕三 8 篇、幕四 5 篇、幕五 3 篇,其中幕二的色塊最寬、顏色最深並帶陰影,色塊正上方掛著一枚珊瑚色標籤寫「後面十六篇的基礎」。中層是五張等寬的白色卡片,每張上緣一條深藍色橫線,卡片標題底下以等寬字標出篇章範圍,再往下是該幕的關鍵字。第一張標題「建立地圖」,範圍 day01-04,關鍵字是 SMART 是什麼、FHIR 資源長怎樣、環境怎麼架。第二張標題「把授權拆到底」,範圍 day05-14,關鍵字是 discovery、授權碼與 PKCE、scope 與 context、身分與 token。第三張標題「變成真的 app」,範圍 day15-22,關鍵字是讀資料、畫圖、寫回去、錯誤與分頁、接多台。第四張標題「處理真實世界」,範圍 day23-27,關鍵字是標準沒寫到的、跨院怎麼合、生態與通路、安全怎麼查。第五張標題「收尾」,範圍 day28-30,關鍵字是上線要注意什麼、決策站不站得住、這一篇。下層是一條深藍色橫帶,左上方灰字小標寫「做完這一幕,app 多了什麼」;橫帶內五格由左到右,每格上行是淺藍小字、下行是白色粗體字,依序是一個能跑的加靜態頁面、一張加等寬字的 access token、讀得到加也寫得回、一條加跨院時間軸、一份加上線檢查清單;每兩格之間有一個淺藍色的向右箭號,共四個。圖片最下方一行灰字註記:第二幕十篇的產出只有一張 token,但後面十六篇的每一步都要先有它

第二幕那十篇是整個系列最硬的部分,也是後面所有東西的基礎。

三十篇裡有一件事我從第一篇做到最後。跟著做的每一步都能在公開 sandbox 重現,不需要任何醫院給你權限。

這正是 SMART on FHIR 最重要的一點。它是一套標準,授權那一套流程換到真的醫院也還是這樣走。至於對方核發哪些 scope、資料照哪一份 profile,那要一家一家問。day23 跟 day25 講過這件事。

附錄:程式碼在哪裡

範例都在 losehrt/ithome-2026-smart-app。MIT 授權。

每個資料夾都是一份完整可跑的專案。讀到哪一天就進哪個資料夾,不用回頭拼前幾天的檔案。跑法是 python3 -m http.server 5173,不需要 Node.js,也不用打包工具。

不想 clone 的話,下表「線上跑」那一欄點下去就會跑。線上版首頁也列了同一份清單。

想回到某一天當時的狀態,資料夾名稱前面那段就是 tag,git checkout day09 這樣用。

資料夾 對應哪幾天 線上跑
day04-sandbox-setup day04 開啟
day06-smart-discovery day06 開啟
day09-first-authorization day09、day10、day11 開啟
day12-launch-context day12 開啟
day14-token-lifecycle day13、day14 開啟
day15-first-smart-app day15 開啟
day16-clinical-data day16 開啟
day17-clinical-data day17 開啟
day18-write-back day18 開啟
day19-error-handling day19 開啟
day20-search-and-write day20 開啟
day22-multi-server day21、day22 開啟
day24-cross-server day24 開啟

沒列到的那幾天沒有自己的資料夾。day01 到 day03、day05 是規範與請求的片段,讀文章就好。day07 全程在網址列上操作,一個檔案都不用改。day08 寫的 pkce.jsday09-first-authorization/ 裡那份一字不差。day23 之後都沒有新的程式碼。

小結

day01 的收尾我寫過一句話:

這個系列真正想做的,是讓更多人有能力做出下一個火線超人。

三十天過去,那句話沒有變。醫療資訊這個領域最大的問題不是技術難,是兩邊都懂的人太少。懂臨床怎麼跑的人,跟寫得出 app 的人,很少是同一個。

三十篇範例,一行 Rails 都沒有,也沒有用到任何前端框架。這是故意的。醫療資訊的門檻,一半來自規範本身,另一半是那一整套語言跟框架墊高的。讀規範要懂 FHIR,跑個範例還得先會 Rails 或某個框架。光是後面這一關,就能嚇退大半個 web 圈的人。

換成瀏覽器原生 JS,後面那一關直接拿掉。剩下的難度,才是規範本身該有的難度。臨床那一關我拆不掉,那得自己去看現場怎麼跑,或者找一個願意講給你聽的人。

標準已經在那裡了。sandbox 是公開的,規範是免費的,程式庫是開源的。缺的是有人願意花三十天把它搞懂。

你已經花了。

那接下來就換你了。挑一個題目,寫那三行字,然後開始。


上一篇
Day29 - SMART 那一層改過四次
系列文
SMART on FHIR 開發之路:30 天做一個跨醫院的 app30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言