摘要
Day 24 已經把 contract 裡的 versionedValueSetcanonical URL 推進到 terminology server$expand/$validate-codeevidence。Day 24 不只補 terminology evidence,同時切出 request-scoped production readiness slice:sandbox auth boundary、non-PHI preflight、CapabilityStatement-based live interaction declarations、AuditEvent / Provenance readiness、PHI masking 與 retention evidence。
Day 24 能回答:
這份 Bundle 的 LOINC / UCUM code,除了 local snapshot 之外,terminology server 是否也能提供 evidence?
但正式交換前還有一個更大的問題:
這個工具是否已經安全到可以接近 live sandbox exchange?
如果一個 quality gate 可以任意呼叫 sandbox endpoint、沒有 auth boundary、沒有 non-PHI guard、report 直接顯示 Patient identifier,也沒有 audit / retention evidence,那它仍然只是 demo。
Day 24 的目標不是變成 production exchange platform。
Day 24 的目標是:
MVP demo -> sandbox pre-exchange readiness gate
也就是說,今天新增的是「交換前安全邊界」:
例如同一份 Bundle 進來時,Day 24 的判斷會是:
| 情境 | 結果 |
|---|---|
| 使用者沒有確認 synthetic / non-PHI | sandbox preflight NOT_EVALUATED,不呼叫任何 sandbox endpoint |
auth mode 是 none |
sandbox preflight NOT_EVALUATED,不呼叫 sandbox metadata |
| sandbox base URL 不在 allowlist | sandbox preflight NOT_EVALUATED,不呼叫 HTTP client |
| allowlist、auth mode、non-PHI guard 都通過 | 只呼叫 /metadata,只讀 CapabilityStatement 宣告,不讀 Patient / Observation / DiagnosticReport |
這讓 report 可以明確說明:
不是因為有 sandbox URL 就可以交換。
必須先通過 endpoint、auth、non-PHI 三個安全邊界。
Day 24 的 request / report flow 變成:
使用者上傳 Bundle
│
├─ 執行原本 JSON / FHIR / TW Core / contract rules
│
├─ terminology server evidence
│ ├─ ValueSet/$expand
│ └─ ValueSet/$validate-code
│
├─ live FHIR metadata evidence
│ └─ GET {FHIR_BASE_URL}/metadata
│
└─ sandbox readiness slice
│
├─ sandbox endpoint guard
│ ├─ allowlist match
│ ├─ reject userinfo / query / fragment
│ ├─ reject private / link-local / metadata IP
│ └─ redirect 不 follow
│
├─ sandbox auth boundary
│ └─ auth mode 不可為 none
│
├─ non-PHI preflight
│ ├─ 使用者必須確認 synthetic / non-PHI
│ └─ Patient identifier / name / telecom / address / birthDate 會停用 live checks
│
├─ CapabilityStatement interaction declarations
│ ├─ Patient read / search-type
│ ├─ Observation read / search-type
│ └─ DiagnosticReport read / search-type
│
└─ request-scoped readiness evidence
├─ AuditEvent / Provenance readiness
├─ input SHA-256
├─ privacy masking categories
└─ retention policy = request-scoped only / no persistent history
最後 Quality Test Report 會新增四個 evidence layer:
Quality Gate blocking result
├─ FHIR / TW Core / contract local rules
├─ Terminology server evidence
├─ Live FHIR metadata evidence
└─ Sandbox readiness evidence
├─ non-PHI preflight
├─ sandbox auth evidence
├─ sandbox interaction declaration evidence
├─ privacy / retention evidence
└─ AuditEvent / Provenance readiness evidence
Day 24 不實作完整 SMART/OAuth authorization code flow。
今天只新增最小 auth boundary:
qualitygate.fhir.sandbox.auth-mode=none
首頁也新增 Sandbox auth mode:
none
bearer_token_configured
policy 是:
| Auth mode | Sandbox preflight |
|---|---|
none |
NOT_EVALUATED,不呼叫 sandbox metadata |
bearer_token_configured |
可進入下一層 guard |
這不是在宣稱已完成 production auth。bearer_token_configured 在 Day 24 只是一個 readiness evidence 狀態:
Authorization header。它只是避免 app 在沒有任何 auth boundary evidence 的情況下執行 live sandbox preflight。真正的 token flow、scope check、refresh token、client registration 與 SMART launch context 要留到 Day 25 之後處理。
Day 24 新增使用者確認:
Confirm this Bundle is synthetic/non-PHI test data
若未確認,sandbox preflight 直接:
NOT_EVALUATED
若已確認,系統仍會掃描 Patient 的直接識別欄位:
Patient.name
Patient.identifier.value
Patient.telecom
Patient.address
Patient.birthDate
如果發現這些欄位,non-PHI preflight 會回:
FAILED
但這個失敗不改變原本 Quality Gate 的 blocking outcome。
它只停用 live sandbox interaction preflight,避免疑似 PHI 被帶進 live checks。
Day 24 不呼叫:
/Patient
/Observation
/DiagnosticReport
它只呼叫 sandbox base URL 的:
GET {SANDBOX_FHIR_BASE_URL}/metadata
然後從 CapabilityStatement 檢查是否宣告:
| Resource | Interaction |
|---|---|
| Patient | read |
| Patient | search-type |
| Observation | read |
| Observation | search-type |
| DiagnosticReport | read |
| DiagnosticReport | search-type |
這個 layer 的定位是:
live resource interaction readiness evidence
不是 live resource interaction execution
原因是 Day 24 還沒有完整 sandbox patient workflow、token handling、scope model、PHI transport policy,也沒有正式 audit retention。
Day 24 的 privacy evidence 是 report-level avoidance,不是正式 PHI de-identification pipeline。
也就是說,目前 report 避免顯示 direct Patient identifiers,並列出應被遮蔽或避免輸出的 field categories:
Patient.name
Patient.identifier.value
Patient.telecom
Patient.address
Patient.birthDate
這不代表系統已完成:
Day 24 能做到的是先把 report 邊界守住:
resource inventory 可以顯示 Patient count / resource id / evidence path。
report 不應直接輸出 Patient name、identifier value、telecom、address、birthDate。
Retention evidence 明確顯示:
request-scoped only; no persistent history
這表示目前版本不會把 uploaded Bundle、terminology response、FHIR metadata response、sandbox response 寫進資料庫。
今天新增的是 request-scoped readiness evidence:
這讓 report 可以回答:
如果下一步要落地 AuditEvent / Provenance,最小 evidence 欄位在哪裡?
qualitygate.fhir.sandbox.allowed-base-urls=
qualitygate.fhir.sandbox.allow-private-network=false
qualitygate.fhir.sandbox.auth-mode=none
預設空 allowlist 和 auth-mode=none 表示:
sandbox readiness evidence = NOT_EVALUATED
HTTP call = not called
SandboxFhirProperties
SandboxFhirEndpointGuard
SandboxFhirPreflightService
SandboxFhirPreflightResult
SandboxInteractionEvidence
NonPhiPreflightService
NonPhiPreflightResult
PrivacyRetentionService
PrivacyRetentionResult
AuditProvenanceReadinessService
AuditProvenanceReadinessResult
ValidationResult 也新增四個 request-scoped result:
nonPhiPreflightResult
sandboxFhirPreflightResult
privacyRetentionResult
auditProvenanceReadinessResult
今天新增測試確認:
none 時不呼叫 HTTP client。/metadata。/Patient、/Observation、/DiagnosticReport。目前測試結果:
Tests run: 99, Failures: 0, Errors: 0, Skipped: 0
完成後,專案的定位變成:
pre-exchange quality gate
├─ FHIR / TW Core validation
├─ partner contract rules
├─ contract lifecycle / compatibility
├─ unit normalization evidence
├─ terminology server evidence
├─ metadata preflight
└─ sandbox readiness evidence
但它仍然不是:
之後預計從 Day 24 的 boundary 往下做:
AuditEvent / Provenance resource generation。Repository:twcore-data-quality-gate