VN Core FHIR Implementation Guide — Bộ Hướng dẫn Triển khai FHIR Cốt lõi cho Việt Nam
0.1.0 - STU1 Draft
VN Core FHIR Implementation Guide — Bộ Hướng dẫn Triển khai FHIR Cốt lõi cho Việt Nam - Local Development build (v0.1.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions
Trang này mô tả các quy tắc validation cho VN Core FHIR IG, bao gồm:
Các invariant sau được nhúng trong profile và sẽ tự động kiểm tra khi validate resource bằng FHIR validator.
| Hạng mục | Giá trị |
|---|---|
| Context | Patient.identifier (slice CCCD) |
| Severity | error |
| Mô tả | Số CCCD phải đúng 12 chữ số |
| FHIRPath | value.empty() or value.matches('[0-9]{12}') |
| Căn cứ | Luật Căn cước 2023, Điều 20 |
| Hạng mục | Giá trị |
|---|---|
| Context | Address (VNCoreAddress profile) |
| Severity | warning |
| Mô tả | Địa chỉ Việt Nam (country = 'VN') phải có extension:province |
| FHIRPath | country.empty() or country != 'VN' or extension.where(url = '...vn-ext-province').exists() |
| Mẫu tham chiếu | CH Core invariant ch-addr-2 |
Các quy tắc sau KHÔNG thể kiểm tra bằng FHIRPath invariant vì yêu cầu logic phức tạp hoặc tra cứu dữ liệu ngoài. Implementer PHẢI triển khai trên FHIR server (custom OperationOutcome).
Quy tắc: Chữ số thứ 4 (vị trí index 3) của số CCCD mã hóa giới tính và thế kỷ sinh:
| Chữ số thứ 4 | Giới tính | Thế kỷ sinh |
|---|---|---|
| 0 | Nam | 19xx |
| 1 | Nữ | 19xx |
| 2 | Nam | 20xx |
| 3 | Nữ | 20xx |
| 4 | Nam | 21xx |
| 5 | Nữ | 21xx |
Kiểm tra: Patient.gender phải nhất quán với chữ số thứ 4 của identifier[CCCD].value:
gender = male → chữ số thứ 4 phải chẵn (0, 2, 4, 6, 8)gender = female → chữ số thứ 4 phải lẻ (1, 3, 5, 7, 9)Severity đề xuất: warning (có thể có trường hợp đặc biệt như chuyển giới chưa cập nhật CCCD)
Pseudocode:
cccd_value = patient.identifier.where(system = '.../sid/cccd').value
if cccd_value is not null and cccd_value.length == 12:
digit4 = int(cccd_value[3])
if patient.gender == 'male' and digit4 % 2 != 0:
warning("Chữ số thứ 4 CCCD không phù hợp giới tính nam")
if patient.gender == 'female' and digit4 % 2 != 1:
warning("Chữ số thứ 4 CCCD không phù hợp giới tính nữ")
Quy tắc: Chữ số 5-6 (vị trí index 4-5) là 2 chữ số cuối của năm sinh.
Kiểm tra: Nếu Patient.birthDate có giá trị, 2 chữ số cuối năm sinh phải khớp vị trí 5-6 trong CCCD.
Pseudocode:
cccd_value = patient.identifier.where(system = '.../sid/cccd').value
if cccd_value is not null and patient.birthDate is not null:
birth_year_last2 = patient.birthDate.year % 100 # e.g. 85, 90, 01
cccd_year = int(cccd_value[4:6])
if birth_year_last2 != cccd_year:
warning("Năm sinh trong CCCD không khớp Patient.birthDate")
Severity đề xuất: warning
Quy tắc: 3 chữ số đầu tiên của CCCD là mã tỉnh/TP nơi đăng ký khai sinh (theo danh mục BCA, KHÔNG phải mã TCTK).
Kiểm tra: Server có thể tra cứu danh mục mã tỉnh BCA để xác nhận 3 chữ số đầu là mã tỉnh hợp lệ.
Lưu ý: Mã tỉnh BCA (3 chữ số) khác với mã tỉnh TCTK (2 chữ số) dùng trong VNProvinceCS. Sau NQ 202/2025, mã BCA cũng có thể thay đổi. Cần theo dõi cập nhật.
Severity đề xuất: warning
Quy tắc: Nếu cả extension:province và extension:ward đều có giá trị, mã xã phải thuộc về tỉnh đã chọn theo QĐ 19/2025/QĐ-TTg.
Kiểm tra: Server tra cứu bảng ĐVHC để xác nhận mã xã (5 chữ số) thuộc tỉnh (2 chữ số).
Pseudocode:
province_code = address.extension[province].valueCoding.code # e.g. "01" (Hà Nội)
ward_code = address.extension[ward].valueCoding.code # e.g. "00008" (Phường Ngọc Hà)
# Tra bảng ĐVHC: ward_code phải thuộc province_code
if not dvhc_lookup(ward_code).province == province_code:
error("Mã xã/phường không thuộc tỉnh/TP đã chọn")
Severity đề xuất: error (sai ĐVHC là lỗi dữ liệu nghiêm trọng)
Mẫu tham chiếu: CH Core invariant ch-addr-2 kiểm tra canton code bằng memberOf() — nhưng chỉ kiểm tra membership đơn cấp. Validation đa cấp (xã thuộc tỉnh) yêu cầu server-side.
Quy tắc: Từ 15/8/2025 (NĐ 188/2025/NĐ-CP), số thẻ BHYT có thể sử dụng số CCCD 12 chữ số (duy trì song song với format BHXH 10 số và legacy 15 ký tự). Nếu Coverage.identifier[BHYT].value là CCCD format (12 chữ số), nó nên khớp với Patient.identifier[CCCD].value của beneficiary.
Pseudocode:
bhyt_value = coverage.identifier.where(system = '.../sid/bhyt').value
if bhyt_value is not null and bhyt_value.matches('[0-9]{12}'):
patient = resolve(coverage.beneficiary)
cccd = patient.identifier.where(system = '.../sid/cccd').value
if cccd is not null and bhyt_value != cccd:
warning("identifier[BHYT] (CCCD) không khớp CCCD bệnh nhân")
Severity đề xuất: warning (có thể dùng CCCD người thân cho trẻ em)
Các quy tắc sau mang tính nghiệp vụ, không bắt buộc validate tự động nhưng implementer nên lưu ý.
Encounter.period không được overlap cho cùng bệnh nhân (trừ Encounter lồng nhau)Condition.recordedDate nên nằm trong Encounter.period của encounter tham chiếuObservation.effectiveDateTime nên nằm trong Encounter.periodObservation.valueQuantity.unit14771-0 (SCnc) → mmol/L, KHÔNG dùng LOINC 1558-6 (MCnc) cho mmol/LCondition tham chiếu encounter qua Condition.encounter → nên có entry tương ứng trong Encounter.diagnosisEncounter.diagnosis.use nên phân biệt rõ: AD (chẩn đoán nhập viện), DD (chẩn đoán phân biệt), CM (bệnh kèm)| IG | Phương pháp | Ví dụ |
|---|---|---|
| CH Core (Thụy Sĩ) | FHIRPath memberOf() cho canton code |
ch-addr-2: canton phải thuộc VS |
| US Core (Mỹ) | Bindings extensible + guidance page |
Không dùng invariant cho SSN format |
| AU Core (Úc) | FHIRPath regex cho IHI (16 digits) | Invariant check digit trên Individual Healthcare Identifier |
| JP Core (Nhật) | Server-side cho address hierarchy | Không dùng FHIRPath cho prefecture-city validation |
VN Core áp dụng mô hình kết hợp: FHIRPath cho validation đơn giản (format, membership), server-side cho cross-field logic (CCCD-gender, xã-tỉnh hierarchy).
VN Core IG implements a 3-tier validation approach. Tier 1 (Profile-level) uses FHIRPath invariants for automatic checks: CCCD must be exactly 12 digits, and Vietnamese addresses (country = 'VN') should include the province extension. Tier 2 (Server-side) covers cross-field logic that cannot be expressed in FHIRPath: CCCD digit 4 must match the patient's gender, digits 5-6 must match the birth year, the first 3 digits must be a valid BCA province code, ward codes must belong to the selected province, and BHYT identifiers in CCCD format should match the patient's CCCD. Tier 3 (Documentation) describes business rules for implementers: clinical timeline consistency, LOINC code and unit compatibility, and encounter diagnosis coherence. This hybrid model draws from international best practices (CH Core, US Core, AU Core, JP Core).