前幾天我們討論,風險管理、UI/UX、錯誤處理。接下來要聊聊,軟體要顯示這些資訊,背後的資料要怎麼存?
如果是體溫紀錄 App,第一個想到的可能就是「姓名、體溫、時間」三個欄位。看起來應該就夠用了,但只要加上幫家人登錄、離線補傳或修改紀錄,這三個欄位很快就不夠。今天就沿用家庭生命徵象 App,把一筆紀錄拆開來看。
把資料模型理解成:先決定有哪些東西要記、各自代表什麼,以及彼此怎麼連起來,再決定資料庫和 API 要怎麼寫。
例如「一位家人可以有很多筆量測紀錄」,就是一個關係;「一筆紀錄可能被修改好幾次」,又是另一個關係。如果一開始沒分清楚,後面很容易拿同一個欄位硬塞不同意思,最後連自己都不知道 time 到底是哪個時間。
先不用急著選資料庫。我們可以先畫出這個教學 App 的關係:
flowchart LR
P["量測對象"] -->|擁有多筆| O["量測紀錄:固定 ID"]
O -->|保留各次內容| V["紀錄版本:項目、數值、單位、量測時間、狀態"]
U["操作帳號"] -->|建立或修訂| V
D["量測裝置:已知時關聯"] -->|提供量測來源| V
V -->|記錄傳送結果| S["同步資訊:待同步、已同步、失敗"]
假設我幫爸爸量體溫,再用自己的帳號輸入 App。這時候至少有兩個角色:量測對象是爸爸,登錄者是我。如果系統只存一個 userId,到底指誰?光看名字猜不出來。
所以這個案例會分開保存 subjectId 和 recordedBy,前者指向家人資料,後者指向操作帳號。如果還需要知道誰實際執行量測,也要另外記,因為量的人不一定是輸入的人。
姓名則拿來顯示,不拿來當唯一識別。家人可能改名,也可能同名;「爸爸」更只是某位使用者對他的稱呼。至於這個帳號有沒有權限替他登錄,仍要由授權規則檢查,不能因為傳來一個 subjectId 就直接接受。
Day 4 提過資料要有語意脈絡。若只紀錄 37.2,光看數字本身一定看不出是在量什麼,要一起知道量測項目和單位。如果是體溫,產品也可能需要記錄量測部位與方法,避免之後比較時,把不同條件下的結果混在一起。
若匯入資料需要換算單位,App 保留原始數值、原始單位及換算依據,才能回頭檢查。遇到缺值時,同樣要分清楚是沒量、量測失敗,還是資料沒有傳到。切記:不能為了讓數字欄位不空白,就全部補成 0,因為在某些數值, 0 代表死亡(沒有脈搏怎麼還會活著)。
來源也要拆開看。「手動輸入」描述資料怎麼進 App;「耳溫計量測」描述數值怎麼來。即使是我手動輸入,原始數值仍可能來自一台裝置,兩者並不衝突。
裝置資料可以另外保存型號與識別資訊,紀錄再透過 deviceId 連回去。不過,同型號不代表同一台裝置;不知道是哪台時,也不要隨便補一台。模型要能表達「裝置不詳」,是否允許這種紀錄,則回到產品需求決定。
假設爸爸早上八點量完體溫,我八點十分才輸入,但家裡網路斷了,中午十二點才同步成功。這筆紀錄的時間要存哪個?
這三個時間各自回答不同問題,所以我會分開記:
| 欄位 | 回答的問題 | 案例範例 |
|---|---|---|
measuredAt |
什麼時候量的? | 2026-09-28 08:00,UTC+8 |
recordedAt |
什麼時候登錄的? | 2026-09-28 08:10,UTC+8 |
syncedAt |
這個版本什麼時候確認同步成功? | 2026-09-28 12:00,UTC+8 |
如果畫體溫趨勢,我們要看的是量測時間。拿同步時間來排,早上的體溫就會跑到中午,看起來像剛量過。
時間也要帶著時區資訊,或在儲存時統一成 UTC,再依需求顯示。不過格式正確,不代表時鐘一定正確。如果時間來自使用者補填或裝置時鐘,必要時還要記下時間來源及是否存疑。只記得「早上」時,也不該默默補成精確的八點整。
再延續剛才的例子:我原本輸入 37.2 °C,後來核對才發現應該是 36.7 °C。如果直接蓋掉原本的值,之後有人問「為什麼早上看到的數字不一樣」,我們可能就答不出來了。
下面資料模型會保留同一個紀錄 ID,新增修訂版本,留下修改者、修改時間和原因:
| 資訊 | 第 1 版 | 第 2 版 |
|---|---|---|
| 紀錄 ID/量測對象 | OBS-001/P-001 |
OBS-001/P-001 |
| 項目/數值/單位 | 體溫/37.2/°C | 體溫/36.7/°C |
| 量測時間 | 08:00,UTC+8 | 08:00,UTC+8 |
| 輸入方式/裝置 | 手動/DEV-001 |
手動/DEV-001 |
| 操作者/操作時間 | U-002/08:10,UTC+8 |
U-002/12:30,UTC+8 |
| 操作原因 | 初次登錄 | 核對裝置讀值後,更正輸入錯誤 |
| 紀錄狀態/同步狀態 | 完成登錄/已同步 | 完成登錄/待同步 |
表內時間都在同一天。注意,修正的是輸入值,量測時間仍是八點;如果十二點半重新量了一次,那就應該新增量測紀錄,而不是修改早上的結果。
同樣地,第 1 版已同步,不代表第 2 版也已經送到伺服器。畫面和查詢都得分清楚目前看的版本;畫趨勢時,也不能把兩個版本當成兩次量測一起算。至於多人同時修改時怎麼處理衝突,還需要另外定義規則,光有版本欄位不會自動解決。
回頭看,前幾天提到的需求,其實都需要資料模型配合。畫面想顯示「幫誰記」,資料就要分清對象與操作者;想告訴使用者「還沒同步」,就要知道哪一版還沒送到;想讓人查修改紀錄,就得保留修訂內容。
今天先把 App 內部要保存的意思說清楚。明天再接著談:當這筆資料要交給另一套系統,怎麼用 FHIR、術語和編碼,讓對方也能理解我們記的是什麼。
設計與規劃資料模型時,我們需要把需求仔細的考量清楚,在醫療軟體中,資料的新增/異動是需要被稽核的,所以在設計資料模型時,也需要將這些稽核所需要的欄位、資料表都一併設計清楚。另外,儲存數據時,需要多注意的是單位,單位不正確,那麼紀錄的數值就會意義不同。一筆資料所包含的語意脈絡也是非常重要的,醫護人員在觀看這些數值時,不會只有查看單一數值就下結論,一般來說都會參考多個數值來下診斷的。