Hướng dẫn triển khai FHIR cốt lõi Việt Nam — VN Core FHIR Implementation Guide
0.10.0 - Draft for Community Review
Hướng dẫn triển khai FHIR cốt lõi Việt Nam — VN Core FHIR Implementation Guide - Draft for Community Review (v0.10.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions
Cách hiểu và cách triển khai Must Support trong VN Core cho HIS, EMR, cổng liên thông và hệ thống nhận dữ liệu — phân biệt Must Support với cardinality thuần tuý, xác định khi nào được để trống có giải trình, và gán đúng trách nhiệm cho từng vai trò trong chuỗi HIS → FHIR → gateway → hệ thống nhận.
Must Support chỉ có giá trị khi đi cùng hướng dẫn theo vai trò triển khai, yêu cầu tuân thủ, ví dụ và bộ kiểm thử.
Must Support như cách vá mọi yêu cầu nghiệp vụ vào cardinality.CapabilityStatement theo vai trò triển khai.Khi một phần tử được đánh dấu Must Support:
Must Support có thể đi cùng 0..1, 0..*, 1..1 hoặc 1..*.
| Cardinality | Must Support | Cách hiểu trong triển khai |
|---|---|---|
1..1 + MS |
Bắt buộc và phải hỗ trợ đầy đủ | Không được bỏ trống; nếu quy định cho phép thiếu có giải trình thì phải dùng cơ chế thay thế hợp lệ |
0..1 + MS |
Không bắt buộc phải luôn có | Nếu có dữ liệu trong nguồn thì phải đưa ra và bên nhận phải xử lý được |
0..* + MS |
Không bắt buộc có ít nhất một giá trị | Nếu nguồn có nhiều giá trị thì phải hỗ trợ lặp đúng cấu trúc |
VN Core áp dụng Must Support theo ba lớp:
Ví dụ:
Patient.identifier[CCCD] là Must Support vì là định danh cá nhân lõi hiện hành.Encounter.reasonCode là Must Support vì phản ánh lý do đến khám.Coverage.relationship là Must Support vì quyết định ngữ nghĩa người thụ hưởng và người đóng/đại diện.| Vai trò triển khai | Kỳ vọng tối thiểu |
|---|---|
| Sender | SHALL gửi phần tử Must Support khi dữ liệu có thật và thuộc phạm vi giao dịch; SHALL NOT tạo dữ liệu giả để “đủ profile”. |
| Receiver | SHALL tiếp nhận, lưu giữ hoặc chuyển tiếp được dữ liệu Must Support hợp lệ mà không làm mất ngữ nghĩa. |
| Server | SHOULD hỗ trợ các cơ chế thiếu dữ liệu hợp lệ như data-absent-reason khi profile hoặc hướng dẫn của VN Core cho phép. |
| Client | SHALL NOT coi mọi trường hợp thiếu dữ liệu là lỗi nếu profile hoặc hướng dẫn đã cho phép cách giải trình hợp lệ. |
Ngoài bảng vai trò ở dạng văn xuôi phía trên, VN Core bắt đầu mã hoá các nghĩa vụ này thành obligation extension (chuẩn hl7.fhir.uv.extensions), để công cụ tuân thủ đọc được và sinh kế hoạch kiểm thử. Validator tài nguyên chỉ kiểm tra cấu trúc và các ràng buộc có thể thực thi trên instance; validator không tự chứng minh hành vi gửi, nhận, lưu giữ hoặc hiển thị của một hệ thống. Đây là cách các IG quốc tế hiện đại biểu diễn trách nhiệm theo vai trò ở dạng máy đọc được.
Actor chuyên biệt theo lát cắt (0.10.0). Obligation gắn theo actor CHUYÊN BIỆT của từng lát cắt triển khai, không gắn actor tổng — hai actor tổng (Sender, Receiver) chỉ còn là ngôn ngữ tài liệu cho bảng vai trò văn xuôi phía trên.
Bắt đầu từ đâu: lát "tối thiểu quốc gia". Nếu bạn chỉ đọc một mục của trang này, hãy đọc mục
này. Câu hỏi "ngưỡng nào thì được gọi là đáp ứng VN Core" được trả lời bằng cặp
vn-core-data-responder /
vn-core-data-requester: 15 profile lõi
(Patient, Practitioner, PractitionerRole, Organization, Location, Encounter, Condition,
Observation lab + vital signs, AllergyIntolerance, MedicationRequest, Procedure,
DiagnosticReport, Coverage, DocumentReference) với read SHALL + search-type SHOULD. Hệ thống
đạt lát này conform VN Core kể cả khi KHÔNG triển khai EMR đầy đủ, ứng dụng người dân hay cổng
BHYT. Ba lát còn lại là bề mặt của từng loại sản phẩm, không phải ngưỡng tối thiểu.
Sáu lát và actor tương ứng:
| Actor | Định nghĩa | Nghĩa vụ mã hoá trên element Must Support |
|---|---|---|
| Bên đáp ứng dữ liệu lõi (Data Responder) | FHIR server của cơ sở KCB, kho dữ liệu tuyến trên, cổng tích hợp — ngưỡng tối thiểu quốc gia | SHALL:populate-if-known trên 15 profile lõi — điền phần tử MS vào phản hồi read/search khi có dữ liệu |
| Bên yêu cầu dữ liệu lõi (Data Requester) | Ứng dụng lâm sàng, hệ phân tích, cổng liên thông tuyến trên | SHALL:no-error + SHALL:handle trên cùng 15 profile |
| Bên gửi hồ sơ BHYT (Submitter) | Cơ sở KCB lập và gửi hồ sơ đề nghị thanh toán (QĐ 3176/QĐ-BYT, NĐ 164/2025/NĐ-CP) | Hồ sơ mình lập: SHALL:populate-if-known. Phản hồi nhận về: SHALL:no-error + SHALL:handle |
| Bên giám định BHYT (Adjudicator) | Cổng tiếp nhận, giám định của cơ quan BHXH | Hồ sơ do cơ sở lập: SHALL:no-error + SHALL:persist. Phản hồi do chính cơ quan BHXH sinh (ClaimResponse, CoverageEligibilityResponse, PaymentReconciliation): SHALL:populate-if-known |
| Nguồn tạo hồ sơ lâm sàng (Document Source) | HIS/EMR lập bệnh án điện tử (TT 13/2025/TT-BYT), phần mềm KSK (QĐ 2062/QĐ-BYT) | SHALL:populate-if-known — trục create-populate: điền khi dữ liệu có thật, không bịa để "đủ profile" |
| Kho hồ sơ EMR (Repository) | Kho HSBA điện tử của cơ sở KCB, kho dữ liệu y tế (NĐ 102/2025/NĐ-CP) | SHALL:no-error + SHALL:persist — trục store + return-on-read: tiếp nhận không lỗi, lưu nguyên vẹn để trả lại khi hệ khác đọc |
| Ứng dụng người dân (Citizen App) | Sổ SKĐT trên VNeID (QĐ 1332/QĐ-BYT), cổng công dân | SHALL:no-error + SHALL:handle — trục consume: không lỗi và không bỏ qua ý nghĩa phần tử; thêm SHOULD:display trên whitelist phần tử người dân cần thấy |
| Cổng liên thông thủ tục hành chính (e-Service Gateway) | Cổng dịch vụ công / hệ thống của cơ quan tư pháp, công an, BHXH tiếp nhận thông điệp dữ liệu y tế phục vụ liên thông thủ tục hành chính theo NĐ 63/2024/NĐ-CP — KHÔNG phải kho hồ sơ EMR của cơ sở KCB | SHALL:no-error + SHALL:persist — không được từ chối vì phần tử vắng dữ liệu hợp lệ, và phải lưu trọn nội dung nhận được vì thông điệp là căn cứ giải quyết thủ tục cho công dân |
Ánh xạ sáu trục nghĩa vụ của kiểm toán sang mã obligation chuẩn:
| Trục kiểm toán | Mã obligation | Ghi chú ngữ nghĩa |
|---|---|---|
| create-populate | SHALL:populate-if-known |
actor nguồn; vắng dữ liệu là trạng thái hợp lệ |
| store | SHALL:persist |
chỉ actor kho — consumer chỉ-đọc KHÔNG mang persist |
| return-on-read | SHALL:persist (bao hàm) |
giá trị lưu phải còn dùng được khi đọc lại; mất field khi lưu là vi phạm |
| search | thuộc CapabilityStatement.rest.resource.searchParam |
không phải obligation trên element |
| handle-absent | quy tắc văn xuôi mục "Hệ thống nhận cần làm gì" | KHÔNG có mã obligation cho xử-lý-khi-vắng; SHALL:handle nghĩa là xử lý đúng ý nghĩa khi CÓ MẶT |
| reject-invalid | SHALL:reject-invalid — CHƯA mã hoá |
Nghĩa vụ có thật và thuộc vai BHYT Adjudicator (cổng giám định từ chối hồ sơ sai), nhưng để gắn TRUNG THỰC cần một endpoint tiếp nhận tài liệu khai document.mode — chưa có. Hiện diễn đạt bằng văn xuôi + expectation trên operation $validate-bhyt-claim. Backlog đi cùng document endpoint |
Obligation không gắn lên từng sub-element một — như thế vừa không viết nổi vừa không đọc nổi. Thay vào đó VN Core công bố ba quy tắc phủ sau đây; chúng là một phần của hợp đồng conformance, không phải quy ước nội bộ của tooling. Bộ kiểm thử của bên triển khai được phép — và nên — bám vào đúng ba quy tắc này.
(1) Obligation trên element phức phủ toàn bộ nội dung con của nó. Khi Bundle.entry,
Observation.component, AllergyIntolerance.reaction… mang obligation, mọi sub-element bên
trong (kể cả slice: obligation trên entry phủ entry[claim] và entry[claim].resource)
được phủ theo. Với nhóm nghĩa vụ tiếp nhận/lưu/xử lý (no-error, handle, persist)
phủ là đầy đủ: tiếp nhận không lỗi một element phức nghĩa là tiếp nhận không lỗi trọn nội
dung con; lưu nguyên vẹn nghĩa là không rơi field con nào khi lưu và đọc lại; xử lý đúng nghĩa
là không bỏ qua ý nghĩa của bất kỳ thành phần con hợp lệ nào.
(2) Với nhóm populate*, sub-element optional-MS KHÔNG tự sinh nghĩa vụ điền độc lập.
SHALL:populate-if-known trên element cha nghĩa là: khi điền cha, điền nội dung con theo dữ
liệu có thật đang có. Nó không tự tách thành một nghĩa vụ "phải điền" riêng có thể kiểm
thử độc lập cho từng con optional-MS — muốn một sub-element có nghĩa vụ điền đứng riêng
(để sinh ca kiểm thử riêng), phải gán obligation trực tiếp cho chính sub-element đó. Đây là
điểm khác biệt có chủ ý giữa hai nhóm nghĩa vụ: nghĩa vụ nhận phủ xuống đầy đủ, nghĩa vụ
điền phủ xuống theo cha chứ không nhân bản thành từng khoản riêng.
(3) Obligation kế thừa DỌC theo chuỗi derivation, actor-aware. Instance khớp profile con
luôn khớp profile cha (ngữ nghĩa derivation của FHIR), nên obligation tuyên trên cha áp cho
mọi instance của con — và chỉ áp đúng cho những actor cha đã khai, không suy rộng sang
actor khác. Ví dụ vn-core-bhyt-submission-bundle kế thừa vn-core-bundle (lát Citizen App):
các element cha đã gắn nhận nghĩa vụ citizen-app theo kế thừa, còn nghĩa vụ BHYT của con vẫn
phải gắn ở tầng con trên element không xung đột. Hệ quả vận hành: obligation chỉ được gắn
một tầng cho mỗi (element, actor) — gắn trùng ở cả cha lẫn con là lỗi (sushi merge-by-index
nuốt/trộn caret cha–con, thực nghiệm 08/08/2026) và bị cổng kiểm chặn.
Giới hạn biểu diễn (0.10.0): khi một profile thuộc lát X kế thừa profile thuộc lát Y khác,
element mà profile cha đã gắn obligation KHÔNG thể mang thêm actor của lát X ở tầng con —
sushi merge-by-index trộn actor giữa hai lát (thực nghiệm 09/08/2026, đúng cho cả element id
trùng lẫn slice của element cha). Trường hợp như vậy được khai tường minh trong
INHERITED_ANNOTATION_EXEMPTIONS của cổng kiểm và nghĩa vụ diễn đạt bằng CapabilityStatement +
bảng vai trò văn xuôi. Hiện có một trường hợp: vn-core-bhyt-submission-bundle (lát BHYT)
kế thừa vn-core-bundle (lát Citizen App) — các element type/timestamp/entry và mọi slice
của entry; những element không xung đột (identifier, signature) vẫn mang obligation BHYT.
Phạm vi máy-đọc-được (0.10.0): toàn bộ element Must Support ở mọi độ sâu — kể cả
sub-element, slice lồng nhau (identifier[gcs].value, section[surrogacyParties].entry) và
choice type đã bị công cụ gộp về element gốc (medicationCodeableConcept → medication[x]) —
của mọi profile thuộc sáu lát cắt:
Data Responder/Requester (15 profile
lõi, ngưỡng tối thiểu quốc gia), EMR (44 profile),
Citizen App (16 profile),
cổng BHYT (7 profile hồ sơ cơ sở lập
Ba profile giấy chứng sinh là thành viên của cả hai lát EMR và Liên thông: chúng vừa được lưu trong bệnh án điện tử (TT 13/2025/TT-BYT) vừa được gửi liên thông. Khai một bên là bỏ mất một nửa nghĩa vụ có thật.
Hai lát trên cùng một element — cách viết đúng: 41 element của ba profile giấy chứng sinh
mang nghĩa vụ lát EMR qua kế thừa từ vn-core-composition / vn-core-document-reference, VÀ
mang thêm actor vn-actor-eservice-gateway của lát Liên thông. Ghi caret trên element ở profile
con thì công cụ trộn obligation giữa hai lát; đường đúng là đặt obligation ở root
StructureDefinition kèm elementId, theo đặc tả obligation 5.3.0. Ghi ở đó thì mỗi lát giữ
được actor-set riêng của mình trên cùng một element.
Sổ nợ có khoá MS_COVERAGE_EXEMPTIONS của cổng vì vậy không còn khoản nào cho lát Liên thông
— 41 khoá đã gỡ. Khoản còn lại duy nhất là quốc tịch trên vn-core-patient, và đó là quyết định
có chủ ý chứ không phải nợ kỹ thuật: MA_QUOCTICH là trường của chuẩn dữ liệu đầu ra
QĐ 3176/QĐ-BYT, tức nghĩa vụ của kênh BHYT; nâng Must Support toàn cục sẽ áp nghĩa vụ ấy lên mọi
hệ EMR và mọi ứng dụng công dân — siết rộng hơn căn cứ pháp lý cho phép.
Mỗi element như vậy phải được phủ theo đúng ba quy tắc trên — obligation trực tiếp, qua
element cha theo quy tắc (1), hoặc kế thừa theo quy tắc (3) — và đúng actor-set; kiểm bằng cổng
scripts/validate-actor-obligations.py (fail-closed; cổng đồng thời CHẶN gắn trùng tầng
cha–con). Một số ít element hậu duệ tự thêm mà cả ba nguồn phủ chưa với tới được ghi trong
sổ nợ có khoá (MS_COVERAGE_EXEMPTIONS) của chính cổng kiểm, kèm lý do từng khoản —
với các element đó, bảng vai trò văn xuôi ở trên là nguồn nghĩa vụ cho tới khi khoản nợ được
đóng. Bảng văn xuôi và obligation extension phải diễn đạt cùng một nghĩa vụ; mọi sai lệch
giữa hai dạng là lỗi tài liệu cần được báo cáo và sửa.
Lớp obligation máy-đọc-được là bề mặt công khai mà bộ kiểm thử của bên triển khai sẽ bám vào, nên VN Core cam kết tường minh (QĐ3, phản biện kiến trúc 08/08/2026):
hl7.fhir.uv.extensions phiên bản 5.3.0 — danh sách 69 mã
vendor hermetic trong scripts/validate-actor-obligations.py là nguồn đối chiếu của IG,
không trôi theo package cache của môi trường build.experimental=true, nháp công khai để cộng đồng rà soát) — tooling
R4 phổ thông có thể không render/validate ActorDefinition; điều đó KHÔNG ảnh hưởng việc
validate resource lâm sàng, vì obligation gắn trên StructureDefinition qua extension chuẩn.Đối với phần tử Must Support, hệ thống nhận cần tối thiểu:
"N/A", "Không rõ", "000000000000" vào trường chuẩn hoá.data-absent-reason khi phần tử được phép thiếu hoặc profile đã quy định rõ cách diễn đạt ngoại lệ.| Tình huống | Cách biểu diễn khuyến nghị | Ghi chú |
|---|---|---|
| Có dữ liệu trong HIS | Gửi giá trị thật | Đây luôn là ưu tiên số 1 |
| Chưa biết nhưng có khả năng sẽ có sau | data-absent-reason = temp-unknown |
Ví dụ đang chờ kết quả hoặc đang xác minh |
| Đã hỏi nhưng không biết | data-absent-reason = asked-unknown |
Ví dụ không nhớ chính xác tiền sử |
| Không áp dụng | data-absent-reason = not-applicable |
Ví dụ dữ liệu không có ý nghĩa trong ca này |
| Bị che do bảo mật/quyền riêng tư | data-absent-reason = masked |
Chỉ dùng khi thật sự có chính sách che giấu |
| Hệ thống nguồn chưa hỗ trợ | data-absent-reason = unsupported |
Cần coi là trạng thái chuyển tiếp, không nên kéo dài |
| Không thực hiện xét nghiệm/thủ thuật | data-absent-reason = not-performed |
Chủ yếu dùng cho kết quả/quan sát |
| Có định danh thay thế hợp lệ | Giữ slice định danh chính theo quy tắc profile và gửi thêm định danh thay thế đúng system |
Không dùng forceMajeureReason chỉ vì bệnh nhân dùng hộ chiếu, GKS hoặc định danh hợp lệ khác |
| Thiếu CCCD trong ca bất khả kháng | data-absent-reason + lý do bất khả kháng của VN Core |
Xem thêm trang kiểm tra hợp lệ và profile Patient |
| Resource / phần tử | Cách xử lý |
|---|---|
Patient.identifier[CCCD] |
Nếu chưa có CCCD do ca bất khả kháng, dùng data-absent-reason trên value và kèm lý do bất khả kháng hợp lệ |
Patient.birthDate |
Nếu chưa xác định được ngày sinh, dùng data-absent-reason; không ghi ngày giả |
Observation.value[x] |
Nếu không có giá trị vì không thực hiện hoặc lỗi quy trình, dùng dataAbsentReason của Observation |
Coverage.relationship |
Không được bỏ khi đã có subscriber khác beneficiary |
Claim.item.productOrService |
Nếu tạm thời chưa có mã chuẩn trong ví dụ/test, chỉ dùng data-absent-reason trong phạm vi bộ dữ liệu kiểm thử có chủ đích, không dùng cho dữ liệu triển khai thật |
identifier.system rõ ràng.system, không trộn vào một giá trị duy nhất.Ví dụ trong VN Core:
CCCD là định danh cá nhân hiện hành.GPHN là định danh hành nghề hiện hành.CCHN là credential CHUYỂN TIẾP, không thuần lịch sử: theo NĐ 96/2023/NĐ-CP Điều 143 khoản 2, CCHN cấp theo Luật KCB 40/2009/QH12 được tiếp tục sử dụng như giấy phép hành nghề đến khi chuyển đổi. Trạng thái đọc ở identifier[CCHN].extension[practiceLicenseStatus].required, phải dùng mã nằm trong ValueSet.extensible, ưu tiên mã trong ValueSet; chỉ dùng mã ngoài khi thật sự không có tương đương phù hợp.text của CodeableConcept;data-absent-reason nếu đúng bản chất là thiếu dữ liệu, không phải thiếu ánh xạ.Với phần tử Must Support kiểu Reference:
Nguồn HIS thường có
Ánh xạ khuyến nghị
| Dữ liệu HIS | Resource / phần tử |
|---|---|
| Mã bệnh nhân nội bộ | Patient.identifier[MRN] |
| CCCD | Patient.identifier[CCCD] |
| Mã số BHXH | Patient.identifier[BHXH] |
| Số thẻ BHYT | Patient.identifier[BHYT] hoặc Coverage.identifier[BHYT] theo ngữ cảnh |
| Họ tên cha/mẹ/người giám hộ | RelatedPerson.name hoặc Patient.contact.name |
| Quan hệ với bệnh nhân | RelatedPerson.relationship / Patient.contact.relationship |
Quy tắc vận hành
GKS, BHXH, BHYT, RelatedPerson và lý do thiếu CCCD khi cần.Patient.name hoặc Patient.identifier.Nguồn HIS thường có
Ánh xạ khuyến nghị
| Dữ liệu HIS | Resource / phần tử |
|---|---|
| Số lượt khám | Encounter.identifier hoặc phần mở rộng/ngữ nghĩa riêng của bên thanh toán layer |
| Thời gian vào/ra | Encounter.period |
| Lý do đến khám | Encounter.reasonCode |
| Khoa/phòng tiếp nhận | Encounter.location hoặc serviceProvider + Location |
Quy tắc vận hành
Khi dùng Composition
Khi dùng DocumentReference
Ánh xạ khuyến nghị
| Nguồn tài liệu | Resource |
|---|---|
| Bệnh án điện tử có cấu trúc | Composition |
| Bản PDF giấy ra viện / bản scan | DocumentReference |
| Tập tài liệu và chữ ký | DocumentReference + Provenance |
Nguồn HIS/BHYT thường có
Ánh xạ khuyến nghị
| Dữ liệu | Resource / phần tử |
|---|---|
| Thẻ BHYT | Coverage.identifier[BHYT] |
| Người thụ hưởng | Coverage.beneficiary |
| Người đóng/người đại diện | Coverage.subscriber |
| Quan hệ | Coverage.relationship |
| Nơi đăng ký KCB ban đầu | phần mở rộng tương ứng của VN Core |
Quy tắc vận hành
subscriber khác beneficiary, không được để relationship = self.Nguyên tắc cốt lõi
MA_LK và các bảng XML là ràng buộc của lớp liên thông hồ sơ BHYT, không phải lý do để làm méo mô hình resource lõi.Chuỗi tối thiểu
| Nghiệp vụ | Hướng mô hình hoá |
|---|---|
| Đợt khám chữa bệnh | Encounter + Coverage + Claim |
| Chẩn đoán | Condition / Claim.diagnosis |
| Dịch vụ / thuốc / vật tư | Claim.item và các resource chuyên ngành liên quan |
| Tài liệu hỗ trợ | DocumentReference, Composition, DiagnosticReport |
| Xuất XML/gửi cổng | lớp liên thông hồ sơ BHYT (BHYT Submission) |
data-absent-reason.| Nếu cần | Nên đọc tiếp |
|---|---|
| Nắm quy tắc tổng quát về tên tiếng Việt, địa chỉ, định danh, Organization/Location | Hướng dẫn chung |
| Tra các quy tắc kiểm tra mức profile, mức nghiệp vụ và mức xuất BHYT | Hướng dẫn kiểm tra hợp lệ |
| Xem ví dụ luồng dữ liệu đầu-cuối theo tình huống lâm sàng | Tình huống lâm sàng |
| Tra danh sách các profile và phần tử Must Support của từng profile | Hồ sơ |
This page explains how VN Core interprets Must Support: differences from cardinality, sender and receiver responsibilities, valid absent-data patterns, and HIS-to-FHIR guidance. It also publishes the machine-readable obligation layer and its three coverage rules — complex-element coverage, no standalone fill duty under populate*, actor-aware derivation inheritance — enforced at every nesting depth by the actor-obligation gate.