Profile, Extension, Implementation Guide: cách FHIR được nội địa hóa
Mỗi quốc gia áp dụng FHIR đều phải nội địa hóa thông qua ba khái niệm gắn liền nhau: Profile (ràng buộc bổ sung trên Resource cơ sở), Extension (thêm trường mà FHIR base chưa có), và Implementation Guide (gói tài liệu phát hành toàn bộ chuẩn). VN Core IG là cách Việt Nam áp các ràng buộc cho BHYT, VNeID, ICD-10 VN, danh mục 34 tỉnh sau Nghị quyết 202/2025/QH15, và mô hình bệnh án điện tử theo Thông tư 13/2025/TT-BYT.
Trang này dành cho lập trình viên, vendor HIS/EMR, và cơ quan quản lý cần nắm cách Profile/Extension/IG vận hành trước khi đọc spec hoặc đánh giá sản phẩm tuân thủ FHIR Việt Nam.
Tóm tắt nhanh
- Profile là StructureDefinition thêm ràng buộc (cardinality, binding, Must Support, slicing, fixed value) lên Resource cơ sở mà không phá vỡ tương thích.
- Extension bổ sung trường dữ liệu FHIR base không có; mỗi extension có URL canonical riêng và phải được khai báo trong IG.
- Implementation Guide là gói phát hành gồm Profile, Extension, Terminology, Example, narrative, được biên dịch ra HTML site và package
.tgz. - FSH (FHIR Shorthand) là DSL được biên dịch bằng SUSHI để sinh ra StructureDefinition JSON; thay thế việc viết XML/JSON tay.
- VN Core IG hiện ở phiên bản 0.5.0 với canonical
http://fhir.hl7.org.vn/core, 52 Profile và 44 Extension đang hoạt động trên repo nguồn.
Nội dung trang
- Vì sao FHIR base không đủ cho y tế Việt Nam
- Profile là gì — pattern ràng buộc
- Bốn loại constraint phổ biến
- Extension — khi nào và viết thế nào
- FSH và SUSHI — bộ công cụ chuẩn
- Implementation Guide — cấu trúc và quy trình build
- Case study: VN Core IG
- So sánh quốc tế: US, JP, KR, CH, AU Core
- Câu hỏi thường gặp
- Tham chiếu và đọc tiếp
1. Vì sao FHIR base không đủ cho y tế Việt Nam
Resource cơ sở của FHIR R4 (4.0.1, 146 resources) được thiết kế ở mức tổng quát toàn cầu. Tài nguyên Patient chuẩn cho phép identifier[] với cardinality 0..*, không yêu cầu định danh cụ thể nào. Nó có address với các thành phần line, city, district, state, postalCode, country, nhưng không có trường mã hóa cấp xã/phường — đơn vị hành chính cấp 3 quan trọng tại Việt Nam sau Nghị quyết 202/2025/QH15.
Nghiệp vụ y tế Việt Nam đặt ra một loạt yêu cầu cụ thể mà FHIR base không đáp ứng trực tiếp. Bệnh án điện tử theo Thông tư 13/2025/TT-BYT bắt buộc gắn số định danh cá nhân (CCCD 12 số). Thanh toán BHYT yêu cầu thẻ BHYT, mã đối tượng tham gia, nơi đăng ký khám chữa bệnh ban đầu, hạn sử dụng. Hồ sơ bệnh án theo chuẩn QĐ 4210/QĐ-BYT cần dân tộc trong danh mục 54 nhóm, nghề nghiệp theo TCTK, hạng cơ sở khám chữa bệnh, tuyến chuyên môn kỹ thuật theo mô hình hai cấp.
Profile và Extension giải bài toán nội địa hóa này bằng cách bổ sung ràng buộc và trường dữ liệu trong khi vẫn duy trì khả năng đọc/ghi với mọi server FHIR R4 chuẩn. Một Patient instance tuân thủ VNCorePatient vẫn là Patient hợp lệ với spec lõi của HL7 — đây là tính chất quan trọng giữ FHIR có tính tương tác toàn cầu.
2. Profile là gì — pattern ràng buộc
Một Profile là một StructureDefinition derive (kế thừa) từ Resource cơ sở hoặc từ một Profile khác, thêm ràng buộc bổ sung. Profile không tự định nghĩa cấu trúc dữ liệu mới, nó chỉ siết tập hợp giá trị hợp lệ mà instance phải tuân theo. Sơ đồ kế thừa của VNCorePatient minh họa rõ:
Patient (base — http://hl7.org/fhir/StructureDefinition/Patient)
└── derive
VNCorePatient (http://fhir.hl7.org.vn/core/StructureDefinition/vn-core-patient)
- identifier slice CCCD 1..1 MS, BHYT 0..* MS, MRN 0..* MS
- extension contains ethnicity, occupation, ward, province
- address conforms to VNCoreAddress
- address.country fixed = "VN" Bốn quy tắc bất di bất dịch của Profile
Khi viết Profile, có bốn quy tắc về tính tương thích bắt buộc phải tôn trọng. Vi phạm bất kỳ quy tắc nào sẽ làm Profile không còn là constraint hợp lệ trên base, dẫn tới instance không thể đọc bằng client FHIR chuẩn:
- Không được nới lỏng cardinality: nếu base định nghĩa
1..1, Profile không thể đổi sang0..1; nếu base là1..*, Profile không thể đổi sang0..*. - Không được thay đổi data type: trường khai báo
stringtrong base không thể đổi sangintegertrong Profile; chỉ được giới hạn trong các kiểu base đã cho phép qua choice type. - Có thể siết cardinality:
0..1có thể đổi thành1..1;0..*có thể đổi thành1..*hoặc1..3. - Có thể tăng độ chặt của binding: từ
examplesangpreferred,extensible, hoặcrequired; nhưng không được hạ độ chặt của một binding đãrequiredtrên base.
Bốn quy tắc này đảm bảo nguyên tắc Liskov: mọi instance hợp lệ với Profile cũng hợp lệ với base, nhưng không nhất thiết ngược lại. Đây là lý do FHIR validator có thể kiểm tra một Patient instance vừa với spec base vừa với VNCorePatient mà không xảy ra mâu thuẫn.
3. Bốn loại constraint phổ biến
Cardinality
Cardinality định nghĩa số lần một element xuất hiện. Ký pháp FHIR dùng cặp min..max: 0..1 là tùy chọn đơn lẻ, 1..1 là bắt buộc đơn lẻ, 0..* là tùy chọn lặp, 1..* là bắt buộc lặp ít nhất một lần. VNCorePatient siết identifier 1..* để buộc mọi bệnh nhân phải có ít nhất một định danh, sau đó dùng slicing để chỉ định slice CCCD ở mức 1..1.
Binding strength
Binding gắn một element code, Coding hoặc CodeableConcept với một ValueSet. FHIR R4 định nghĩa bốn mức:
- required — instance bắt buộc dùng code thuộc ValueSet, validator báo lỗi nếu vi phạm.
- extensible — ưu tiên ValueSet, chỉ được dùng code ngoài nếu không có code phù hợp trong ValueSet.
- preferred — khuyến nghị nhưng không bắt buộc.
- example — minh họa, không ràng buộc gì.
Profile VNCoreCondition bind Condition.code với ValueSet ICD-10 VN ở mức extensible để cho phép sử dụng SNOMED CT khi mã ICD-10 không đủ chi tiết, đồng thời giữ ICD-10 VN làm danh mục ưu tiên.
Must Support
Must Support (đánh dấu MS) yêu cầu hệ thống tuân thủ Profile phải hỗ trợ element theo cách mà IG quy định. Spec FHIR cố ý không định nghĩa "support" cụ thể là gì ở mức toàn cầu — IG phải tự nêu rõ. VN Core quy ước rằng MS có nghĩa: server lưu trữ phải có khả năng ghi/đọc round-trip element này; client gửi dữ liệu phải gửi nếu có; UI hiển thị phải render element nếu được yêu cầu.
Must Support không phải là cardinality. Một element 0..1 MS vẫn có thể vắng mặt trong instance — nhưng hệ thống phải có khả năng xử lý khi nó xuất hiện. Một element 1..1 MS bắt buộc phải có giá trị; nếu nghiệp vụ không có giá trị, phải dùng data-absent-reason như VNCorePatient quy định cho slice CCCD trong các trường hợp đặc biệt như trẻ sơ sinh trước 2016 hoặc người nước ngoài.
Slicing
Slicing chia một array thành các "lát" được nhận diện qua discriminator. VNCorePatient slice identifier theo system để tách CCCD, BHYT, mã bệnh án (MRN), số hộ chiếu, số giấy khai sinh:
* identifier ^slicing.discriminator.type = #value
* identifier ^slicing.discriminator.path = "system"
* identifier ^slicing.rules = #open
* identifier contains
CCCD 1..1 MS and
BHYT 0..* MS and
MRN 0..* MS and
passport 0..1 MS and
GKS 0..1 MS
* identifier[CCCD].system = "http://fhir.hl7.org.vn/core/sid/cccd" (exactly)
* identifier[BHYT].system = "http://fhir.hl7.org.vn/core/sid/bhyt" (exactly)
Discriminator type = #value kết hợp path = "system" nghĩa là validator phân biệt slice dựa trên giá trị của identifier.system. Rule #open cho phép thêm slice ngoài danh sách đã liệt kê (ví dụ mã bệnh án nội bộ); rule #closed sẽ chặn mọi slice không khai báo.
4. Extension — khi nào và viết thế nào
Extension là cơ chế chuẩn để thêm trường dữ liệu mà FHIR base không có. Mọi Resource và DataType đều có sẵn trường extension với cardinality 0..*; mỗi extension được nhận diện qua một URL canonical duy nhất. Khi nghiệp vụ Việt Nam cần lưu loại đối tượng tham gia BHYT trên thẻ BHYT, VN Core định nghĩa VNCoreExtBHYTCardType:
Extension: VNCoreExtBHYTCardType
Id: vn-ext-bhyt-card-type
Title: "Loại đối tượng thẻ BHYT — BHYT Card Type"
Description: "Mã loại đối tượng tham gia BHYT theo QĐ 1351/QĐ-BHXH và QĐ 3276/QĐ-BYT"
Context: Coverage
* value[x] only CodeableConcept
* valueCodeableConcept from VNBHYTCardTypeVS (extensible)
URL canonical đầy đủ là http://fhir.hl7.org.vn/core/StructureDefinition/vn-ext-bhyt-card-type. Khi instance Coverage tham chiếu extension này, JSON serialize ra:
{
"resourceType": "Coverage",
"id": "example-coverage-bhyt-01",
"status": "active",
"extension": [{
"url": "http://fhir.hl7.org.vn/core/StructureDefinition/vn-ext-bhyt-card-type",
"valueCodeableConcept": {
"coding": [{
"system": "http://fhir.hl7.org.vn/core/CodeSystem/vn-bhyt-card-type-cs",
"code": "DN",
"display": "Người lao động doanh nghiệp"
}]
}
}]
}
Extension chia thành hai loại. Simple extension chỉ chứa một value[x]. Complex extension chứa nhiều sub-extension lồng nhau. VN Core hiện có 44 extension trong repo nguồn, bao gồm VNCoreExtEthnicity (dân tộc), VNCoreExtWard (xã/phường), VNCoreExtProvince (tỉnh/thành), VNCoreExtFacilityCareLevel (tuyến chuyên môn kỹ thuật), VNCoreExtOrgRank (hạng cơ sở), VNCoreExtTreatmentOutcome (kết quả điều trị) và 38 extension khác phục vụ Claim, Coverage, Device, Encounter.
Nguyên tắc thiết kế: chỉ tạo extension khi đã chắc chắn FHIR base và các IG quốc tế đã publish (US Core, IPS, IPA) không có. Nếu một concept đã có extension chuẩn của HL7 (ví dụ patient-birthPlace, patient-nationality), VN Core dùng lại thay vì tạo mới.
5. FSH và SUSHI — bộ công cụ chuẩn
FSH (FHIR Shorthand) là DSL được HL7 chuẩn hóa để viết Profile, Extension, ValueSet, CodeSystem dưới dạng văn bản gọn. SUSHI (SUSHI Unshortens SHorthand Inputs) là compiler chính thức biên dịch FSH ra StructureDefinition JSON. Bộ đôi FSH + SUSHI thay thế việc viết tay XML/JSON dài hàng nghìn dòng — cùng một profile có thể giảm từ 800 dòng JSON xuống còn 60 dòng FSH có cấu trúc dễ đọc.
Đây là profile VNCorePatient viết bằng FSH (rút gọn để minh họa):
Profile: VNCorePatient
Parent: Patient
Id: vn-core-patient
Title: "Bệnh nhân VN Core — VN Core Patient Profile"
Description: "Profile Patient cho Việt Nam, gắn với số định danh cá nhân
theo TT 13/2025/TT-BYT và NĐ 102/2025/NĐ-CP."
* identifier 1..* MS
* identifier ^slicing.discriminator.type = #value
* identifier ^slicing.discriminator.path = "system"
* identifier ^slicing.rules = #open
* identifier contains
CCCD 1..1 MS and
BHYT 0..* MS and
MRN 0..* MS
* identifier[CCCD].system = "http://fhir.hl7.org.vn/core/sid/cccd" (exactly)
* identifier[CCCD].value 1..1 MS
* identifier[CCCD].value obeys vn-cccd-format
* name 1..* MS
* gender 1..1 MS
* birthDate 1..1 MS
* address only VNCoreAddress
* extension contains
VNCoreExtEthnicity named ethnicity 0..1 MS and
VNCoreExtOccupation named occupation 0..1 MS
* obeys vn-patient-force-majeure-reason
Lệnh sushi . chạy trong thư mục dự án sẽ đọc tất cả file .fsh, kiểm tra cú pháp, resolve các tham chiếu giữa Profile-Extension-ValueSet, và xuất ra fsh-generated/resources/StructureDefinition-vn-core-patient.json. Quy trình build IG đầy đủ tiếp tục bằng IG Publisher (file publisher.jar chính thức của HL7) để sinh HTML site, validation report, và package .tgz.
Một số IG (đặc biệt là CH Core và US Core đời đầu) vẫn duy trì StructureDefinition JSON viết tay. Tuy nhiên xu hướng từ 2022 trở đi là chuyển hết sang FSH vì lợi thế bảo trì: diff dễ đọc, code review hiệu quả, dependency giữa các artifact tự động được SUSHI giải.
6. Implementation Guide — cấu trúc và quy trình build
Implementation Guide là gói phát hành đầy đủ kết hợp specification và documentation. Một IG hoàn chỉnh chứa các thành phần sau:
- Profiles — StructureDefinition cho mỗi Resource được nội địa hóa.
- Extensions — StructureDefinition cho các trường thêm.
- Terminology — CodeSystem (định nghĩa code), ValueSet (tập hợp code dùng được trong binding), ConceptMap (ánh xạ giữa các code system).
- NamingSystem — đăng ký URI cho identifier (CCCD, BHYT, BHXH, mã hộ chiếu).
- CapabilityStatement — mô tả tập hợp Resource và operation mà server tuân thủ IG phải hỗ trợ.
- SearchParameter, OperationDefinition — tham số tìm kiếm và operation tùy chỉnh.
- Examples — instance JSON minh họa, validate được với chính các Profile của IG.
- Pagecontent — narrative markdown giải thích nghiệp vụ, hướng dẫn cài đặt, ví dụ workflow.
Quy trình build hai bước. Bước một: sushi . biên dịch FSH → StructureDefinition JSON, đặt vào fsh-generated/. Bước hai: IG Publisher (chạy qua script _genonce.sh) đọc sushi-config.yaml, ig.ini, fsh-generated, và pagecontent, tạo HTML site đầy đủ trong output/, kèm package .tgz để publish lên FHIR Package Registry. Output điển hình bao gồm index.html, qa.html (báo cáo QA), artifacts.html (danh mục mọi artifact), và file package.tgz để dependency của IG khác kéo về qua npm-style resolution.
IG có versioning theo SemVer, được khai báo trong sushi-config.yaml. Mọi IG khi tham chiếu IG khác đều phải pin version cụ thể (ví dụ [email protected]) để build deterministic.
7. Case study: VN Core IG
VN Core là Implementation Guide quốc gia do Omi HealthTech (OmiGroup) phát triển và đóng góp cho cộng đồng y tế số Việt Nam. Phiên bản hiện tại (theo sushi-config.yaml trong repo) là 0.5.0 với các thông số kỹ thuật:
| Thuộc tính | Giá trị |
|---|---|
| IG ID | hl7.fhir.vn.core |
| Canonical URL | http://fhir.hl7.org.vn/core |
| FHIR Version | R4 (4.0.1) |
| Version | 0.5.0 |
| Status | draft |
| Jurisdiction | VN |
| License | CC-BY-4.0 |
| Số Profile / Extension | 52 Profile, 44 Extension trong repo nguồn |
Tập Profile bao quát các Resource trọng tâm cho hệ thống bệnh viện và BHYT: VNCorePatient, VNCorePractitioner, VNCorePractitionerRole, VNCoreOrganization, VNCoreOrganizationDepartment, VNCoreEncounter, VNCoreCondition, VNCoreObservation (với các specialization VitalSigns, BloodPressure, BodyHeight, BodyWeight, BodyTemperature, HeartRate, RespiratoryRate, SpO2, Lab, YHCT), VNCoreProcedure, VNCoreMedicationRequest, VNCoreMedicationDispense, VNCoreCoverage, VNCoreClaim, VNCoreClaimResponse, VNCoreExplanationOfBenefit, VNCorePaymentReconciliation, VNCoreImmunization, VNCoreAllergyIntolerance, VNCoreDevice, VNCoreImplantableDevice, VNCoreImagingStudy, VNCoreDiagnosticReport (với Lab, Imaging, Pathology variants), VNCoreDocumentReference, VNCoreComposition, VNCoreConsent, VNCoreProvenance, VNCoreAuditEvent, và bundle VNCoreBHYTSubmissionBundle phục vụ submission BHYT theo NĐ 164/2025/NĐ-CP.
Extension tập trung vào các trường nghiệp vụ Việt Nam mà FHIR base và các IG quốc tế chưa có: dân tộc, nghề nghiệp, tuyến chuyên môn kỹ thuật, hạng cơ sở khám chữa bệnh, loại đối tượng BHYT, kỳ thanh toán BHYT, lý do bất khả kháng cho định danh thiếu, phương thức consent, retention audit log, mã đăng ký lưu hành thiết bị y tế, nhóm rủi ro thiết bị y tế (loại A/B/C/D theo NĐ 98/2021), đơn vị hành chính cấp tỉnh/xã sau Nghị quyết 202/2025/QH15.
Terminology của VN Core gồm các CodeSystem nội địa: ICD-10 VN (theo QĐ 4469/QĐ-BYT), danh mục dân tộc 54 nhóm, danh mục đơn vị hành chính 34 tỉnh, danh mục mã đối tượng BHYT theo QĐ 3276/QĐ-BYT, danh mục thuật ngữ y học cổ truyền theo QĐ 2552 và 3080/QĐ-BYT, ConceptMap SNOMED CT VN theo QĐ 2427/2493/2805/QĐ-BYT.
8. So sánh quốc tế: US, JP, KR, CH, AU Core
VN Core không phát triển trong chân không. Bảng dưới so sánh quy mô và mức độ áp dụng của các National Core IG mà Omi HealthTech tham chiếu trong quá trình thiết kế:
| IG | Quốc gia | Số Profile | Trạng thái | Mức độ áp dụng |
|---|---|---|---|---|
| US Core | Mỹ | ~30 | STU 8 (trial use) | Bắt buộc cho EHR certification (ONC/ASTP) |
| JP Core | Nhật | ~50 | v1.x | Khuyến nghị MHLW; bắt cầu với SS-MIX2 |
| KR Core | Hàn Quốc | ~20 | draft | Pilot KOSMOS / EMR vendors lớn |
| CH Core | Thụy Sĩ | ~15 | v3+ | Bắt buộc cho EPD (electronic patient dossier) |
| AU Core | Úc | ~20 | v1.x | ADHA recommendation; My Health Record |
| VN Core | Việt Nam | 52 | draft 0.5.0 | Community draft, đang chuẩn bị Affiliate |
Quy mô VN Core tương đương JP Core về số lượng Profile, lớn hơn US Core và CH Core. Khác biệt chính là VN Core ngay từ phiên bản 0.5.0 đã bao quát cả khối thanh toán BHYT (Claim, Coverage, ExplanationOfBenefit, PaymentReconciliation) — một điểm mà US Core không cover (ONC tách riêng cho Da Vinci) và JP Core chỉ chạm bề mặt. Nguyên nhân: hệ thống thanh toán BHYT một lớp (single-payer) ở Việt Nam khiến mapping XML 4210 → FHIR Claim trở thành use case sống còn cho mọi vendor HIS.
Đọc thêm: trang FHIR quốc tế và bài học cho Việt Nam phân tích sâu hơn về kiến trúc, governance, và lộ trình adoption của các National Core IG.
9. Câu hỏi thường gặp
Có bắt buộc viết Profile bằng FSH không?
Không. FSH là DSL convenience, không phải spec bắt buộc. Bạn vẫn có thể viết StructureDefinition trực tiếp bằng JSON hoặc XML rồi đặt vào thư mục input/resources/ để IG Publisher pick up. Tuy nhiên, mọi National Core IG mới phát hành từ 2022 trở đi (bao gồm VN Core, AU Core, KR Core) đều dùng FSH vì lợi thế bảo trì rõ rệt.
Implementation Guide có versioning không?
Có, theo SemVer. VN Core hiện ở 0.5.0, sẽ tăng minor khi thêm Profile/Extension không phá vỡ tương thích, tăng patch khi sửa lỗi narrative hoặc binding nhỏ, và phải tăng major khi đổi cardinality kiểu phá vỡ tương thích. Mọi IG khi tham chiếu (dependency) IG khác đều phải pin version cụ thể qua dependencies trong sushi-config.yaml.
Có thể derive Profile từ Profile khác không?
Có. Một bệnh viện có thể derive BachMaiPatient từ VNCorePatient để thêm constraint riêng (ví dụ slice identifier mã bệnh án nội bộ với regex pattern cụ thể). Quy tắc bốn bất biến vẫn áp dụng: Profile con phải hợp lệ với mọi ràng buộc của Profile cha.
Khi nào nên tạo Extension mới và khi nào nên dùng extension chuẩn HL7?
Luôn ưu tiên extension đã chuẩn hóa của HL7 hoặc của IG quốc tế đã publish stable (US Core, IPS, IPA). Chỉ tạo extension mới khi (1) concept là đặc thù Việt Nam hoặc (2) extension chuẩn không bind đúng ValueSet cần thiết. VN Core dùng lại patient-birthPlace, patient-nationality, patient-religion của HL7 thay vì tạo bản local.
Must Support có nghĩa là bắt buộc có dữ liệu không?
Không. Must Support là yêu cầu cho hệ thống — phải có khả năng xử lý element. Cardinality mới quyết định một instance có bắt buộc chứa dữ liệu hay không. Một element 0..1 MS hợp lệ kể cả khi vắng mặt.
10. Tham chiếu và đọc tiếp
Tài liệu chuẩn HL7
- FHIR R4 — Profiling FHIR (§5.2)
- FHIR R4 — Conformance Rules: Must Support
- FHIR R4 — Address datatype definition
- FHIR R4 — JSON representation
- FSH School — FHIR Shorthand documentation
- US Core IG — STU 8
- JP Core IG
- CH Core IG
- AU Core IG
Văn bản pháp lý Việt Nam
- Thông tư 13/2025/TT-BYT — Bệnh án điện tử (ban hành 06/6/2025, hiệu lực 21/7/2025).
- Nghị định 102/2025/NĐ-CP — Quản lý dữ liệu y tế số (13/5/2025, hiệu lực 01/7/2025).
- Luật 91/2025/QH15 — Bảo vệ dữ liệu cá nhân (26/6/2025, hiệu lực 01/01/2026).
- Nghị quyết 202/2025/QH15 — Sắp xếp đơn vị hành chính cấp tỉnh (12/6/2025).
- Quyết định 4469/QĐ-BYT — ICD-10 VN (28/10/2020).
- Quyết định 3276/QĐ-BYT — Danh mục mã đối tượng đến KCB (17/10/2025).