Blood Bank Management Data Specifications

Blood Bank Management Data Specifications

Shared Entity References

This module references the following shared entities defined in their owning modules. Blood Bank does not redefine these tables — it uses foreign-key references only.

Shared Entity Owning Module Table(s) FK Used Here
Patients ehr-patient-mgmt patients patients.patient_id
Providers ehr-patient-mgmt providers providers.provider_id
Encounters scheduling encounters encounters.encounter_id
Facilities ehr-patient-mgmt facilities, departments facilities.facility_id
Users & Auth ehr-patient-mgmt users, roles, permissions users.user_id
Lab Results lis lab_results lab_results.result_id
Payers policy-contract-mgmt payers, insurance_plans (referenced indirectly via EHR/RCM)

Entity Relationship Diagram

erDiagram patients ||--o{ blood_type_screen : "has" patients ||--o{ crossmatch_records : "has" patients ||--o{ transfusion_orders : "has" patients ||--o{ transfusion_administration : "has" patients ||--o{ transfusion_reactions : "has" encounters ||--o{ blood_type_screen : "during" encounters ||--o{ transfusion_orders : "during" encounters ||--o{ transfusion_administration : "during" encounters ||--o{ transfusion_reactions : "during" providers ||--o{ transfusion_orders : "orders" providers ||--o{ transfusion_reactions : "investigated by" facilities ||--o{ blood_component_inventory : "stores" facilities ||--o{ blood_donations : "collected at" users ||--o{ blood_type_screen : "tested by" users ||--o{ crossmatch_records : "performed by" users ||--o{ transfusion_administration : "verified by" users ||--o{ blood_quarantine_log : "released by" users ||--o{ blood_discard_log : "discarded by" blood_donors ||--o{ blood_donations : "donates" blood_donations ||--o{ blood_components : "produces" blood_components ||--o{ blood_component_inventory : "tracked as" blood_components ||--o{ crossmatch_records : "crossmatched" blood_components ||--o{ transfusion_administration : "transfused" blood_components ||--o{ blood_quarantine_log : "quarantined in" blood_components ||--o{ blood_discard_log : "discarded in" blood_type_screen ||--o{ crossmatch_records : "basis for" transfusion_orders ||--o{ crossmatch_records : "fulfilled by" transfusion_orders ||--o{ transfusion_administration : "results in" transfusion_administration ||--o{ transfusion_reactions : "may cause" blood_donors { bigint donor_id PK } blood_donations { bigint donation_id PK bigint donor_id FK bigint facility_id FK bigint collector_id FK } blood_components { bigint component_id PK bigint donation_id FK } blood_component_inventory { bigint inventory_id PK bigint component_id FK bigint facility_id FK bigint issued_to_patient_id FK } blood_type_screen { bigint ts_id PK bigint patient_id FK bigint encounter_id FK bigint tested_by FK } crossmatch_records { bigint crossmatch_id PK bigint patient_id FK bigint component_id FK bigint ts_id FK bigint order_id FK bigint performed_by FK } transfusion_orders { bigint order_id PK bigint patient_id FK bigint encounter_id FK bigint ordering_provider_id FK } transfusion_administration { bigint admin_id PK bigint order_id FK bigint component_id FK bigint patient_id FK bigint encounter_id FK bigint verifier1_id FK bigint verifier2_id FK } transfusion_reactions { bigint reaction_id PK bigint admin_id FK bigint patient_id FK bigint component_id FK bigint investigated_by FK } blood_quarantine_log { bigint quarantine_id PK bigint component_id FK bigint released_by FK } blood_discard_log { bigint discard_id PK bigint component_id FK bigint discarded_by FK bigint witness_id FK }

Table Definitions

Notes for all tables: - Use TIMESTAMP WITH TIME ZONE where supported; shown as TIMESTAMP for brevity. - All tables include created_at, created_by, updated_at, updated_by for auditability (UAE PDPL, DOH/DHA audit expectations), even if not listed in key_fields.


1. blood_donors

Purpose: Donor registry with demographics, Emirates ID, baseline blood group, and deferral history. Used for donor eligibility, recall, and MOH hemovigilance reporting.

Field Specifications

Field Type Nullable Default Constraint Description
donor_id BIGINT NO IDENTITY PK Internal donor identifier
emirates_id VARCHAR(18) NO UNIQUE, format 784-YYYY-NNNNNNN-C UAE Emirates ID of donor
mrn_patient_id BIGINT YES FK → patients.patient_id Link if donor is also a patient
first_name_en VARCHAR(100) NO Donor first name (English)
middle_name_en VARCHAR(100) YES Donor middle name (English)
last_name_en VARCHAR(100) NO Donor last name (English)
first_name_ar VARCHAR(100) YES Donor first name (Arabic)
last_name_ar VARCHAR(100) YES Donor last name (Arabic)
dob DATE NO Date of birth
gender VARCHAR(10) NO 'unknown' IN ('male','female','other','unknown') Donor gender
nationality_code VARCHAR(3) YES ISO 3166-1 alpha-3 Nationality
phone_mobile VARCHAR(20) NO E.164 format Mobile number (+971 5X XXX XXXX)
phone_home VARCHAR(20) YES Home phone
email VARCHAR(150) YES Email address
address_line1 VARCHAR(200) YES Address line 1
address_line2 VARCHAR(200) YES Address line 2 / PO Box
emirate VARCHAR(20) YES IN ('Abu Dhabi','Dubai','Sharjah','Ajman','Umm Al Quwain','Ras Al Khaimah','Fujairah') Emirate of residence
abo_group VARCHAR(2) YES FK → md_abo_groups.code ABO group (O, A, B, AB)
rh_type VARCHAR(3) YES FK → md_rh_types.code Rh type (+, -)
blood_type_source VARCHAR(20) YES IN ('donation','external','unknown') Source of ABO/Rh
donor_status VARCHAR(20) NO 'active' IN ('active','temporarily_deferred','permanently_deferred','inactive','deceased') Current donor status
total_donations INTEGER NO 0 ≥ 0 Total successful donations
last_donation_date DATE YES Date of last successful donation
deferral_reason_code VARCHAR(20) YES FK → md_donor_deferral_reasons.code Latest deferral reason
deferral_until DATE YES Date until which donor is deferred
consent_signed BOOLEAN NO FALSE Informed consent for donation recorded
consent_datetime TIMESTAMP YES When consent was obtained
notes TEXT YES Free-text notes / alerts
created_at TIMESTAMP NO CURRENT_TIMESTAMP Record creation time
created_by BIGINT NO FK → users.user_id User who created record
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Last update time
updated_by BIGINT YES FK → users.user_id User who last updated

SQL DDL

SQL
CREATE TABLE blood_donors (
    donor_id              BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    emirates_id           VARCHAR(18) NOT NULL,
    mrn_patient_id        BIGINT,
    first_name_en         VARCHAR(100) NOT NULL,
    middle_name_en        VARCHAR(100),
    last_name_en          VARCHAR(100) NOT NULL,
    first_name_ar         VARCHAR(100),
    last_name_ar          VARCHAR(100),
    dob                   DATE NOT NULL,
    gender                VARCHAR(10) NOT NULL DEFAULT 'unknown',
    nationality_code      VARCHAR(3),
    phone_mobile          VARCHAR(20) NOT NULL,
    phone_home            VARCHAR(20),
    email                 VARCHAR(150),
    address_line1         VARCHAR(200),
    address_line2         VARCHAR(200),
    emirate               VARCHAR(20),
    abo_group             VARCHAR(2),
    rh_type               VARCHAR(3),
    blood_type_source     VARCHAR(20),
    donor_status          VARCHAR(20) NOT NULL DEFAULT 'active',
    total_donations       INTEGER NOT NULL DEFAULT 0,
    last_donation_date    DATE,
    deferral_reason_code  VARCHAR(20),
    deferral_until        DATE,
    consent_signed        BOOLEAN NOT NULL DEFAULT FALSE,
    consent_datetime      TIMESTAMP,
    notes                 TEXT,
    created_at            TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by            BIGINT NOT NULL,
    updated_at            TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by            BIGINT,
    CONSTRAINT uq_blood_donors_emirates_id UNIQUE (emirates_id),
    CONSTRAINT fk_blood_donors_patient
        FOREIGN KEY (mrn_patient_id) REFERENCES patients(patient_id)
        ON UPDATE CASCADE ON DELETE SET NULL,
    CONSTRAINT fk_blood_donors_deferral_reason
        FOREIGN KEY (deferral_reason_code) REFERENCES md_donor_deferral_reasons(code),
    CONSTRAINT fk_blood_donors_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_blood_donors_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT chk_blood_donors_gender
        CHECK (gender IN ('male','female','other','unknown')),
    CONSTRAINT chk_blood_donors_status
        CHECK (donor_status IN ('active','temporarily_deferred','permanently_deferred','inactive','deceased')),
    CONSTRAINT chk_blood_donors_emirate
        CHECK (emirate IS NULL OR emirate IN ('Abu Dhabi','Dubai','Sharjah','Ajman','Umm Al Quwain','Ras Al Khaimah','Fujairah')),
    CONSTRAINT chk_blood_donors_total_donations
        CHECK (total_donations >= 0),
    CONSTRAINT chk_blood_donors_deferral_dates
        CHECK (deferral_until IS NULL OR deferral_until >= CURRENT_DATE)
);

CREATE INDEX idx_blood_donors_emirates_id ON blood_donors(emirates_id);
CREATE INDEX idx_blood_donors_name_en ON blood_donors(last_name_en, first_name_en);
CREATE INDEX idx_blood_donors_status ON blood_donors(donor_status);
CREATE INDEX idx_blood_donors_deferral ON blood_donors(donor_status, deferral_until);

Terminology Bindings

Field Terminology Example Value
abo_group ISBT 128 ABO codes A, B, AB, O
rh_type ISBT 128 Rh codes POS, NEG
deferral_reason_code UAE MOH donor deferral list / local ValueSet TRAVEL_MALARIA, LOW_HB
gender HL7 AdministrativeGender male

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
donor_id RelatedPerson RelatedPerson.id
mrn_patient_id Patient RelatedPerson.patient.reference (Patient/{id})
emirates_id RelatedPerson identifier[EmiratesID].value
first_name_en, last_name_en RelatedPerson name[0].given, name[0].family
phone_mobile RelatedPerson telecom[phone].value
email RelatedPerson telecom[email].value
dob RelatedPerson birthDate
gender RelatedPerson gender
abo_group, rh_type Observation Observation.code (LOINC 883-9) + valueCodeableConcept (ISBT) for donor typing
donor_status RelatedPerson extension[donor-status].valueCode

2. blood_donations

Purpose: Individual donation events, including collection details, screening outcome, and infectious disease status. Supports linkage to LIS for infectious marker testing.

Field Specifications

Field Type Nullable Default Constraint Description
donation_id BIGINT NO IDENTITY PK Donation event identifier
donor_id BIGINT NO FK → blood_donors.donor_id Donor
donation_number VARCHAR(30) NO UNIQUE ISBT 128 donation identification number
donation_datetime TIMESTAMP NO CURRENT_TIMESTAMP Start time of collection
donation_end_datetime TIMESTAMP YES donation_datetime End time of collection
donation_type VARCHAR(20) NO IN ('whole_blood','apheresis_platelet','apheresis_plasma','autologous','directed') Donation type
volume_ml INTEGER YES > 0 Collected volume in mL
facility_id BIGINT NO FK → facilities.facility_id Collection facility
collection_site VARCHAR(100) YES Site (e.g., "Mobile Unit Dubai Mall")
collector_id BIGINT NO FK → users.user_id Phlebotomist/technologist
pre_hb_g_dl NUMERIC(4,1) YES 0–25 Pre-donation hemoglobin
complications TEXT YES Any adverse events during donation
screening_pass BOOLEAN NO FALSE Donor screening passed for this donation
infectious_disease_status VARCHAR(20) NO 'pending' IN ('pending','negative','positive','indeterminate') Overall infectious disease result
infectious_panel_result_id BIGINT YES FK → lab_results.result_id Link to LIS panel result
status VARCHAR(20) NO 'collected' IN ('scheduled','collected','quarantined','released','discarded') Donation lifecycle status
notes TEXT YES Additional notes
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created timestamp
created_by BIGINT NO FK → users.user_id Created by
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Updated timestamp
updated_by BIGINT YES FK → users.user_id Updated by

SQL DDL

SQL
CREATE TABLE blood_donations (
    donation_id               BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    donor_id                  BIGINT NOT NULL,
    donation_number           VARCHAR(30) NOT NULL,
    donation_datetime         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    donation_end_datetime     TIMESTAMP,
    donation_type             VARCHAR(20) NOT NULL,
    volume_ml                 INTEGER,
    facility_id               BIGINT NOT NULL,
    collection_site           VARCHAR(100),
    collector_id              BIGINT NOT NULL,
    pre_hb_g_dl               NUMERIC(4,1),
    complications             TEXT,
    screening_pass            BOOLEAN NOT NULL DEFAULT FALSE,
    infectious_disease_status VARCHAR(20) NOT NULL DEFAULT 'pending',
    infectious_panel_result_id BIGINT,
    status                    VARCHAR(20) NOT NULL DEFAULT 'collected',
    notes                     TEXT,
    created_at                TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by                BIGINT NOT NULL,
    updated_at                TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by                BIGINT,
    CONSTRAINT uq_blood_donations_number UNIQUE (donation_number),
    CONSTRAINT fk_blood_donations_donor
        FOREIGN KEY (donor_id) REFERENCES blood_donors(donor_id)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_blood_donations_facility
        FOREIGN KEY (facility_id) REFERENCES facilities(facility_id),
    CONSTRAINT fk_blood_donations_collector
        FOREIGN KEY (collector_id) REFERENCES users(user_id),
    CONSTRAINT fk_blood_donations_lab_result
        FOREIGN KEY (infectious_panel_result_id) REFERENCES lab_results(result_id),
    CONSTRAINT fk_blood_donations_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_blood_donations_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT chk_blood_donations_type
        CHECK (donation_type IN ('whole_blood','apheresis_platelet','apheresis_plasma','autologous','directed')),
    CONSTRAINT chk_blood_donations_status
        CHECK (status IN ('scheduled','collected','quarantined','released','discarded')),
    CONSTRAINT chk_blood_donations_infectious_status
        CHECK (infectious_disease_status IN ('pending','negative','positive','indeterminate')),
    CONSTRAINT chk_blood_donations_times
        CHECK (donation_end_datetime IS NULL OR donation_end_datetime >= donation_datetime),
    CONSTRAINT chk_blood_donations_volume
        CHECK (volume_ml IS NULL OR volume_ml > 0)
);

CREATE INDEX idx_blood_donations_donor ON blood_donations(donor_id);
CREATE INDEX idx_blood_donations_number ON blood_donations(donation_number);
CREATE INDEX idx_blood_donations_status ON blood_donations(status);
CREATE INDEX idx_blood_donations_infectious ON blood_donations(infectious_disease_status);
CREATE INDEX idx_blood_donations_datetime ON blood_donations(donation_datetime);

Terminology Bindings

Field Terminology Example Value
donation_type Local ValueSet (ISBT-aligned) whole_blood
infectious_disease_status Local ValueSet negative
status Local ValueSet quarantined

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
donation_id Procedure Procedure.id
donor_id RelatedPerson Procedure.subject (donor as subject)
donation_datetime Procedure performedDateTime
donation_type Procedure code (SNOMED CT for blood donation)
facility_id Organization Procedure.performer.actor
infectious_panel_result_id DiagnosticReport Procedure.partOf / DiagnosticReport.basedOn

3. blood_components

Purpose: Individual blood component units derived from donations or apheresis, with full traceability, processing attributes, and expiry.

Field Specifications

Field Type Nullable Default Constraint Description
component_id BIGINT NO IDENTITY PK Component unit identifier
donation_id BIGINT NO FK → blood_donations.donation_id Source donation
component_number VARCHAR(40) NO UNIQUE ISBT 128 product code + donation number
component_type VARCHAR(30) NO FK → md_blood_component_types.code Component type (RBC, FFP, etc.)
abo_group VARCHAR(2) NO FK → md_abo_groups.code ABO group
rh_type VARCHAR(3) NO FK → md_rh_types.code Rh type
volume_ml INTEGER YES > 0 Volume in mL
collection_datetime TIMESTAMP NO When component created
expiry_datetime TIMESTAMP NO > collection_datetime Expiry date/time
status VARCHAR(20) NO 'quarantined' IN ('quarantined','available','reserved','issued','transfused','discarded') Component lifecycle status
irradiated BOOLEAN NO FALSE Irradiation flag
irradiation_datetime TIMESTAMP YES When irradiated
leukoreduced BOOLEAN NO FALSE Leukoreduction flag
washed BOOLEAN NO FALSE Washed flag
antigen_negative_for VARCHAR(200) YES Comma-separated antigen codes (e.g., "K-,E-")
special_attributes JSONB YES Additional attributes (CMV-, HbS-, etc.)
quarantine_reason VARCHAR(200) YES Reason if quarantined
final_disposition VARCHAR(20) YES IN ('transfused','discarded','returned','split') Final outcome
final_disposition_datetime TIMESTAMP YES When final disposition occurred
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created timestamp
created_by BIGINT NO FK → users.user_id Created by
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Updated timestamp
updated_by BIGINT YES FK → users.user_id Updated by

SQL DDL

SQL
CREATE TABLE blood_components (
    component_id               BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    donation_id                BIGINT NOT NULL,
    component_number           VARCHAR(40) NOT NULL,
    component_type             VARCHAR(30) NOT NULL,
    abo_group                  VARCHAR(2) NOT NULL,
    rh_type                    VARCHAR(3) NOT NULL,
    volume_ml                  INTEGER,
    collection_datetime        TIMESTAMP NOT NULL,
    expiry_datetime            TIMESTAMP NOT NULL,
    status                     VARCHAR(20) NOT NULL DEFAULT 'quarantined',
    irradiated                 BOOLEAN NOT NULL DEFAULT FALSE,
    irradiation_datetime       TIMESTAMP,
    leukoreduced               BOOLEAN NOT NULL DEFAULT FALSE,
    washed                     BOOLEAN NOT NULL DEFAULT FALSE,
    antigen_negative_for       VARCHAR(200),
    special_attributes         JSONB,
    quarantine_reason          VARCHAR(200),
    final_disposition          VARCHAR(20),
    final_disposition_datetime TIMESTAMP,
    created_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by                 BIGINT NOT NULL,
    updated_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by                 BIGINT,
    CONSTRAINT uq_blood_components_number UNIQUE (component_number),
    CONSTRAINT fk_blood_components_donation
        FOREIGN KEY (donation_id) REFERENCES blood_donations(donation_id)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_blood_components_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_blood_components_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT chk_blood_components_status
        CHECK (status IN ('quarantined','available','reserved','issued','transfused','discarded')),
    CONSTRAINT chk_blood_components_final_disposition
        CHECK (final_disposition IS NULL OR final_disposition IN ('transfused','discarded','returned','split')),
    CONSTRAINT chk_blood_components_times
        CHECK (expiry_datetime > collection_datetime),
    CONSTRAINT chk_blood_components_volume
        CHECK (volume_ml IS NULL OR volume_ml > 0)
);

CREATE INDEX idx_blood_components_donation ON blood_components(donation_id);
CREATE INDEX idx_blood_components_status_expiry ON blood_components(status, expiry_datetime);
CREATE INDEX idx_blood_components_group ON blood_components(abo_group, rh_type, component_type, status);
CREATE INDEX idx_blood_components_number ON blood_components(component_number);

Terminology Bindings

Field Terminology Example Value
component_type ISBT 128 product codes E3080 (RBC, leukoreduced)
abo_group ISBT 128 ABO O
rh_type ISBT 128 Rh POS
antigen_negative_for ISBT red cell antigen codes K-,E-

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
component_id BiologicallyDerivedProduct BiologicallyDerivedProduct.id
component_number BiologicallyDerivedProduct identifier.value
component_type BiologicallyDerivedProduct productCategory / productCode
abo_group, rh_type Observation Observation.code (LOINC 883-9) + valueCodeableConcept
status BiologicallyDerivedProduct status
expiry_datetime BiologicallyDerivedProduct expirationDate
special_attributes BiologicallyDerivedProduct extension[special-attributes]

4. blood_component_inventory

Purpose: Current inventory status and physical location of each component unit across facilities, including issuance and return tracking.

Field Specifications

Field Type Nullable Default Constraint Description
inventory_id BIGINT NO IDENTITY PK Inventory record identifier
component_id BIGINT NO FK → blood_components.component_id Component unit
facility_id BIGINT NO FK → facilities.facility_id Facility where stored
storage_location VARCHAR(100) NO Fridge/freezer identifier, shelf, bin
temperature_zone VARCHAR(20) NO FK → md_component_storage_zones.code Storage temp category (RBC, FFP, etc.)
status VARCHAR(20) NO 'in_stock' IN ('in_stock','reserved','issued','in_transit','returned','discarded') Inventory status
received_datetime TIMESTAMP NO CURRENT_TIMESTAMP When received into inventory
issued_datetime TIMESTAMP YES When issued from inventory
issued_to_patient_id BIGINT YES FK → patients.patient_id Intended recipient
issued_to_encounter_id BIGINT YES FK → encounters.encounter_id Encounter context
issued_to_location VARCHAR(100) YES Ward/clinic issued to
issued_by BIGINT YES FK → users.user_id User issuing unit
returned_datetime TIMESTAMP YES When returned to inventory
returned_condition VARCHAR(20) YES IN ('acceptable','temperature_excursion','damaged','other') Condition on return
current_temperature_c NUMERIC(4,1) YES Last recorded temperature
in_transit_to_facility_id BIGINT YES FK → facilities.facility_id Destination if in transit
notes TEXT YES Notes (e.g., transport details)
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created timestamp
created_by BIGINT NO FK → users.user_id Created by
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Updated timestamp
updated_by BIGINT YES FK → users.user_id Updated by

SQL DDL

SQL
CREATE TABLE blood_component_inventory (
    inventory_id              BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    component_id              BIGINT NOT NULL,
    facility_id               BIGINT NOT NULL,
    storage_location          VARCHAR(100) NOT NULL,
    temperature_zone          VARCHAR(20) NOT NULL,
    status                    VARCHAR(20) NOT NULL DEFAULT 'in_stock',
    received_datetime         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    issued_datetime           TIMESTAMP,
    issued_to_patient_id      BIGINT,
    issued_to_encounter_id    BIGINT,
    issued_to_location        VARCHAR(100),
    issued_by                 BIGINT,
    returned_datetime         TIMESTAMP,
    returned_condition        VARCHAR(20),
    current_temperature_c     NUMERIC(4,1),
    in_transit_to_facility_id BIGINT,
    notes                     TEXT,
    created_at                TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by                BIGINT NOT NULL,
    updated_at                TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by                BIGINT,
    CONSTRAINT fk_bci_component
        FOREIGN KEY (component_id) REFERENCES blood_components(component_id)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_bci_facility
        FOREIGN KEY (facility_id) REFERENCES facilities(facility_id),
    CONSTRAINT fk_bci_issued_patient
        FOREIGN KEY (issued_to_patient_id) REFERENCES patients(patient_id),
    CONSTRAINT fk_bci_issued_encounter
        FOREIGN KEY (issued_to_encounter_id) REFERENCES encounters(encounter_id),
    CONSTRAINT fk_bci_issued_by
        FOREIGN KEY (issued_by) REFERENCES users(user_id),
    CONSTRAINT fk_bci_transit_facility
        FOREIGN KEY (in_transit_to_facility_id) REFERENCES facilities(facility_id),
    CONSTRAINT fk_bci_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_bci_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT chk_bci_status
        CHECK (status IN ('in_stock','reserved','issued','in_transit','returned','discarded')),
    CONSTRAINT chk_bci_return_condition
        CHECK (returned_condition IS NULL OR returned_condition IN ('acceptable','temperature_excursion','damaged','other'))
);

CREATE INDEX idx_bci_component ON blood_component_inventory(component_id);
CREATE INDEX idx_bci_status_facility ON blood_component_inventory(facility_id, status);
CREATE INDEX idx_bci_patient ON blood_component_inventory(issued_to_patient_id);
CREATE INDEX idx_bci_expiry_lookup ON blood_component_inventory(facility_id, status, component_id);

(Expiry is resolved via join to blood_components.expiry_datetime for FEFO logic.)

Terminology Bindings

Field Terminology Example Value
temperature_zone Component Storage Requirements master RBC_2_6C
returned_condition Local ValueSet temperature_excursion

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
inventory_id BiologicallyDerivedProduct BiologicallyDerivedProduct.extension[inventory-id]
facility_id Organization BiologicallyDerivedProduct.storage[0].scale / Organization.id
storage_location BiologicallyDerivedProduct storage[0].description
current_temperature_c BiologicallyDerivedProduct storage[0].temperature
issued_to_patient_id Patient Procedure.subject (transfusion)
status BiologicallyDerivedProduct status

5. blood_type_screen

Purpose: Patient ABO/Rh typing and antibody screening results, including validity window and concordance with historical type. Used for pre-transfusion testing and electronic crossmatch eligibility.

Field Specifications

Field Type Nullable Default Constraint Description
ts_id BIGINT NO IDENTITY PK Type & screen record ID
patient_id BIGINT NO FK → patients.patient_id Patient
encounter_id BIGINT NO FK → encounters.encounter_id Encounter
specimen_id VARCHAR(40) NO Specimen/barcode ID
specimen_collection_datetime TIMESTAMP YES When specimen collected
abo_group VARCHAR(2) NO FK → md_abo_groups.code ABO group
rh_type VARCHAR(3) NO FK → md_rh_types.code Rh type
forward_group VARCHAR(20) YES Forward grouping result
reverse_group VARCHAR(20) YES Reverse grouping result
antibody_screen_result VARCHAR(20) NO 'negative' IN ('negative','positive','inconclusive') Antibody screen outcome
antibody_specificity VARCHAR(200) YES Identified antibodies (e.g., "anti-K, anti-E")
auto_control_result VARCHAR(20) YES IN ('negative','positive') Auto control
tested_by BIGINT NO FK → users.user_id Technologist
tested_datetime TIMESTAMP NO CURRENT_TIMESTAMP When testing performed
valid_until TIMESTAMP NO Validity (e.g., 72h)
historical_type_concordant BOOLEAN NO TRUE Concordant with historical type
historical_ts_id BIGINT YES FK → blood_type_screen.ts_id Reference to prior T&S
comments TEXT YES Comments / discrepancy notes
result_status VARCHAR(20) NO 'final' IN ('preliminary','final','amended','cancelled') Result status
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created timestamp
created_by BIGINT NO FK → users.user_id Created by
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Updated timestamp
updated_by BIGINT YES FK → users.user_id Updated by

SQL DDL

SQL
CREATE TABLE blood_type_screen (
    ts_id                     BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    patient_id                BIGINT NOT NULL,
    encounter_id              BIGINT NOT NULL,
    specimen_id               VARCHAR(40) NOT NULL,
    specimen_collection_datetime TIMESTAMP,
    abo_group                 VARCHAR(2) NOT NULL,
    rh_type                   VARCHAR(3) NOT NULL,
    forward_group             VARCHAR(20),
    reverse_group             VARCHAR(20),
    antibody_screen_result    VARCHAR(20) NOT NULL DEFAULT 'negative',
    antibody_specificity      VARCHAR(200),
    auto_control_result       VARCHAR(20),
    tested_by                 BIGINT NOT NULL,
    tested_datetime           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    valid_until               TIMESTAMP NOT NULL,
    historical_type_concordant BOOLEAN NOT NULL DEFAULT TRUE,
    historical_ts_id          BIGINT,
    comments                  TEXT,
    result_status             VARCHAR(20) NOT NULL DEFAULT 'final',
    created_at                TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by                BIGINT NOT NULL,
    updated_at                TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by                BIGINT,
    CONSTRAINT fk_bts_patient
        FOREIGN KEY (patient_id) REFERENCES patients(patient_id)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_bts_encounter
        FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id),
    CONSTRAINT fk_bts_tested_by
        FOREIGN KEY (tested_by) REFERENCES users(user_id),
    CONSTRAINT fk_bts_historical
        FOREIGN KEY (historical_ts_id) REFERENCES blood_type_screen(ts_id),
    CONSTRAINT fk_bts_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_bts_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT chk_bts_antibody_screen
        CHECK (antibody_screen_result IN ('negative','positive','inconclusive')),
    CONSTRAINT chk_bts_auto_control
        CHECK (auto_control_result IS NULL OR auto_control_result IN ('negative','positive')),
    CONSTRAINT chk_bts_result_status
        CHECK (result_status IN ('preliminary','final','amended','cancelled')),
    CONSTRAINT chk_bts_validity
        CHECK (valid_until > tested_datetime)
);

CREATE INDEX idx_bts_patient ON blood_type_screen(patient_id, valid_until);
CREATE INDEX idx_bts_specimen ON blood_type_screen(specimen_id);
CREATE INDEX idx_bts_antibody ON blood_type_screen(antibody_screen_result);
CREATE INDEX idx_bts_encounter ON blood_type_screen(encounter_id);

Terminology Bindings

Field Terminology Example Value
abo_group ISBT 128 ABO A
rh_type ISBT 128 Rh NEG
antibody_specificity ISBT red cell antigen nomenclature anti-K
antibody_screen_result Local ValueSet positive

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
ts_id Observation Observation.id
patient_id Patient Observation.subject.reference
encounter_id Encounter Observation.encounter.reference
specimen_id Specimen Observation.specimen.reference
abo_group, rh_type Observation code (LOINC 882-1/883-9) + valueCodeableConcept
antibody_screen_result Observation interpretation / valueCodeableConcept (LOINC 890-4)
antibody_specificity Observation component[antibody].valueCodeableConcept
tested_datetime Observation effectiveDateTime
result_status Observation status

6. crossmatch_records

Purpose: Crossmatch testing results linking a specific component to a patient and transfusion order, including electronic vs serological method and validity.

Field Specifications

Field Type Nullable Default Constraint Description
crossmatch_id BIGINT NO IDENTITY PK Crossmatch record ID
patient_id BIGINT NO FK → patients.patient_id Patient
component_id BIGINT NO FK → blood_components.component_id Component being crossmatched
ts_id BIGINT NO FK → blood_type_screen.ts_id Underlying type & screen
order_id BIGINT YES FK → transfusion_orders.order_id Related transfusion order
crossmatch_type VARCHAR(20) NO IN ('electronic','immediate_spin','ahg','other') Crossmatch method
result VARCHAR(20) NO IN ('compatible','incompatible','not_performed','cancelled') Crossmatch result
incompatibility_reason VARCHAR(200) YES Reason if incompatible
performed_by BIGINT NO FK → users.user_id Technologist
performed_datetime TIMESTAMP NO CURRENT_TIMESTAMP When performed
valid_until TIMESTAMP YES Validity of crossmatch
comments TEXT YES Additional notes
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created timestamp
created_by BIGINT NO FK → users.user_id Created by
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Updated timestamp
updated_by BIGINT YES FK → users.user_id Updated by

SQL DDL

SQL
CREATE TABLE crossmatch_records (
    crossmatch_id          BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    patient_id             BIGINT NOT NULL,
    component_id           BIGINT NOT NULL,
    ts_id                  BIGINT NOT NULL,
    order_id               BIGINT,
    crossmatch_type        VARCHAR(20) NOT NULL,
    result                 VARCHAR(20) NOT NULL,
    incompatibility_reason VARCHAR(200),
    performed_by           BIGINT NOT NULL,
    performed_datetime     TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    valid_until            TIMESTAMP,
    comments               TEXT,
    created_at             TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by             BIGINT NOT NULL,
    updated_at             TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by             BIGINT,
    CONSTRAINT fk_cm_patient
        FOREIGN KEY (patient_id) REFERENCES patients(patient_id)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_cm_component
        FOREIGN KEY (component_id) REFERENCES blood_components(component_id)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_cm_ts
        FOREIGN KEY (ts_id) REFERENCES blood_type_screen(ts_id),
    CONSTRAINT fk_cm_order
        FOREIGN KEY (order_id) REFERENCES transfusion_orders(order_id),
    CONSTRAINT fk_cm_performed_by
        FOREIGN KEY (performed_by) REFERENCES users(user_id),
    CONSTRAINT fk_cm_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_cm_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT chk_cm_type
        CHECK (crossmatch_type IN ('electronic','immediate_spin','ahg','other')),
    CONSTRAINT chk_cm_result
        CHECK (result IN ('compatible','incompatible','not_performed','cancelled')),
    CONSTRAINT chk_cm_incompatibility_reason
        CHECK (result <> 'incompatible' OR incompatibility_reason IS NOT NULL)
);

CREATE INDEX idx_cm_patient ON crossmatch_records(patient_id);
CREATE INDEX idx_cm_component ON crossmatch_records(component_id);
CREATE INDEX idx_cm_order ON crossmatch_records(order_id);
CREATE INDEX idx_cm_result ON crossmatch_records(result);

Terminology Bindings

Field Terminology Example Value
crossmatch_type Crossmatch Eligibility Rules master electronic
result Local ValueSet compatible

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
crossmatch_id Observation Observation.id
patient_id Patient Observation.subject
component_id BiologicallyDerivedProduct Observation.focus
crossmatch_type Observation method
result Observation valueCodeableConcept
performed_datetime Observation effectiveDateTime
order_id ServiceRequest Observation.basedOn

7. transfusion_orders

Purpose: Physician orders for blood transfusion, including requested component type, units, priority, indication, and special requirements. Integrated with CPOE.

Field Specifications

Field Type Nullable Default Constraint Description
order_id BIGINT NO IDENTITY PK Transfusion order ID
patient_id BIGINT NO FK → patients.patient_id Patient
encounter_id BIGINT NO FK → encounters.encounter_id Encounter
ordering_provider_id BIGINT NO FK → providers.provider_id Ordering physician
component_type_requested VARCHAR(30) NO FK → md_blood_component_types.code Requested component type
units_requested INTEGER NO 1 > 0 Number of units requested
priority VARCHAR(20) NO 'routine' IN ('routine','urgent','stat','massive_transfusion') Priority
indication_code VARCHAR(10) YES FK → md_transfusion_indications.code Coded indication
indication_text VARCHAR(500) YES Free-text indication
special_requirements VARCHAR(200) YES e.g., "irradiated, CMV-negative"
target_hb_g_dl NUMERIC(4,1) YES Target hemoglobin if RBCs
order_status VARCHAR(20) NO 'pending' IN ('pending','in_progress','completed','cancelled') Order status
order_datetime TIMESTAMP NO CURRENT_TIMESTAMP When order placed
needed_by_datetime TIMESTAMP YES When blood needed
emergency_release BOOLEAN NO FALSE Uncrossmatched/emergency release flag
massive_transfusion_protocol BOOLEAN NO FALSE Part of MTP
comments TEXT YES Additional comments
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created timestamp
created_by BIGINT NO FK → users.user_id Created by (CPOE user)
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Updated timestamp
updated_by BIGINT YES FK → users.user_id Updated by

SQL DDL

SQL
CREATE TABLE transfusion_orders (
    order_id                    BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    patient_id                  BIGINT NOT NULL,
    encounter_id                BIGINT NOT NULL,
    ordering_provider_id        BIGINT NOT NULL,
    component_type_requested    VARCHAR(30) NOT NULL,
    units_requested             INTEGER NOT NULL DEFAULT 1,
    priority                    VARCHAR(20) NOT NULL DEFAULT 'routine',
    indication_code             VARCHAR(10),
    indication_text             VARCHAR(500),
    special_requirements        VARCHAR(200),
    target_hb_g_dl              NUMERIC(4,1),
    order_status                VARCHAR(20) NOT NULL DEFAULT 'pending',
    order_datetime              TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    needed_by_datetime          TIMESTAMP,
    emergency_release           BOOLEAN NOT NULL DEFAULT FALSE,
    massive_transfusion_protocol BOOLEAN NOT NULL DEFAULT FALSE,
    comments                    TEXT,
    created_at                  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by                  BIGINT NOT NULL,
    updated_at                  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by                  BIGINT,
    CONSTRAINT fk_to_patient
        FOREIGN KEY (patient_id) REFERENCES patients(patient_id)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_to_encounter
        FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id),
    CONSTRAINT fk_to_provider
        FOREIGN KEY (ordering_provider_id) REFERENCES providers(provider_id),
    CONSTRAINT fk_to_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_to_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT fk_to_indication_code
        FOREIGN KEY (indication_code) REFERENCES md_transfusion_indications(code),
    CONSTRAINT chk_to_units
        CHECK (units_requested > 0),
    CONSTRAINT chk_to_priority
        CHECK (priority IN ('routine','urgent','stat','massive_transfusion')),
    CONSTRAINT chk_to_status
        CHECK (order_status IN ('pending','in_progress','completed','cancelled'))
);

CREATE INDEX idx_to_patient ON transfusion_orders(patient_id, order_status);
CREATE INDEX idx_to_encounter ON transfusion_orders(encounter_id);
CREATE INDEX idx_to_provider ON transfusion_orders(ordering_provider_id);
CREATE INDEX idx_to_priority ON transfusion_orders(priority);
CREATE INDEX idx_to_emergency ON transfusion_orders(emergency_release) WHERE emergency_release = TRUE;

Terminology Bindings

Field Terminology Example Value
component_type_requested ISBT 128 product codes / master RBC_LEUKOREDUCED
indication_code Facility-defined Transfusion Indication Codes ANEMIA_HB_LT7
priority Local ValueSet stat

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
order_id ServiceRequest ServiceRequest.id
patient_id Patient ServiceRequest.subject
encounter_id Encounter ServiceRequest.encounter
ordering_provider_id Practitioner ServiceRequest.requester
component_type_requested ServiceRequest code (SNOMED CT for transfusion of RBC/platelets)
units_requested ServiceRequest quantity.value
priority ServiceRequest priority
indication_code Condition ServiceRequest.reasonCode (ICD-10-AM or local)
emergency_release ServiceRequest extension[emergency-release].valueBoolean

8. transfusion_administration

Purpose: Bedside transfusion administration records, including verification, timing, volume, rate, vitals, and whether a reaction occurred.

Field Specifications

Field Type Nullable Default Constraint Description
admin_id BIGINT NO IDENTITY PK Transfusion administration ID
order_id BIGINT NO FK → transfusion_orders.order_id Related order
component_id BIGINT NO FK → blood_components.component_id Component transfused
patient_id BIGINT NO FK → patients.patient_id Patient
encounter_id BIGINT NO FK → encounters.encounter_id Encounter
verifier1_id BIGINT NO FK → users.user_id First verifier (nurse)
verifier2_id BIGINT YES FK → users.user_id Second verifier
start_datetime TIMESTAMP NO Start of transfusion
end_datetime TIMESTAMP YES start_datetime End of transfusion
volume_infused INTEGER YES ≥ 0 Volume infused (mL)
rate_ml_per_hr INTEGER YES ≥ 0 Average rate
pre_vitals_json JSONB YES Pre-transfusion vitals (structured)
post_vitals_json JSONB YES Post-transfusion vitals
intra_vitals_json JSONB YES Vitals during transfusion timeline
reaction_occurred BOOLEAN NO FALSE Whether reaction occurred
reaction_id BIGINT YES FK → transfusion_reactions.reaction_id Linked reaction if any
status VARCHAR(20) NO 'in_progress' IN ('planned','in_progress','completed','stopped','cancelled') Administration status
bedside_location VARCHAR(100) YES Bed/room identifier
product_barcode_scanned BOOLEAN NO FALSE Barcode scan completed
patient_barcode_scanned BOOLEAN NO FALSE Wristband scan completed
notes TEXT YES Additional notes
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created timestamp
created_by BIGINT NO FK → users.user_id Created by
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Updated timestamp
updated_by BIGINT YES FK → users.user_id Updated by

SQL DDL

SQL
CREATE TABLE transfusion_administration (
    admin_id                BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    order_id                BIGINT NOT NULL,
    component_id            BIGINT NOT NULL,
    patient_id              BIGINT NOT NULL,
    encounter_id            BIGINT NOT NULL,
    verifier1_id            BIGINT NOT NULL,
    verifier2_id            BIGINT,
    start_datetime          TIMESTAMP NOT NULL,
    end_datetime            TIMESTAMP,
    volume_infused          INTEGER,
    rate_ml_per_hr          INTEGER,
    pre_vitals_json         JSONB,
    post_vitals_json        JSONB,
    intra_vitals_json       JSONB,
    reaction_occurred       BOOLEAN NOT NULL DEFAULT FALSE,
    reaction_id             BIGINT,
    status                  VARCHAR(20) NOT NULL DEFAULT 'in_progress',
    bedside_location        VARCHAR(100),
    product_barcode_scanned BOOLEAN NOT NULL DEFAULT FALSE,
    patient_barcode_scanned BOOLEAN NOT NULL DEFAULT FALSE,
    notes                   TEXT,
    created_at              TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by              BIGINT NOT NULL,
    updated_at              TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by              BIGINT,
    CONSTRAINT fk_ta_order
        FOREIGN KEY (order_id) REFERENCES transfusion_orders(order_id),
    CONSTRAINT fk_ta_component
        FOREIGN KEY (component_id) REFERENCES blood_components(component_id),
    CONSTRAINT fk_ta_patient
        FOREIGN KEY (patient_id) REFERENCES patients(patient_id),
    CONSTRAINT fk_ta_encounter
        FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id),
    CONSTRAINT fk_ta_verifier1
        FOREIGN KEY (verifier1_id) REFERENCES users(user_id),
    CONSTRAINT fk_ta_verifier2
        FOREIGN KEY (verifier2_id) REFERENCES users(user_id),
    CONSTRAINT fk_ta_reaction
        FOREIGN KEY (reaction_id) REFERENCES transfusion_reactions(reaction_id),
    CONSTRAINT fk_ta_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_ta_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT chk_ta_status
        CHECK (status IN ('planned','in_progress','completed','stopped','cancelled')),
    CONSTRAINT chk_ta_times
        CHECK (end_datetime IS NULL OR end_datetime >= start_datetime),
    CONSTRAINT chk_ta_volume
        CHECK (volume_infused IS NULL OR volume_infused >= 0),
    CONSTRAINT chk_ta_rate
        CHECK (rate_ml_per_hr IS NULL OR rate_ml_per_hr >= 0)
);

CREATE INDEX idx_ta_patient ON transfusion_administration(patient_id);
CREATE INDEX idx_ta_order ON transfusion_administration(order_id);
CREATE INDEX idx_ta_component ON transfusion_administration(component_id);
CREATE INDEX idx_ta_status ON transfusion_administration(status);
CREATE INDEX idx_ta_reaction ON transfusion_administration(reaction_occurred) WHERE reaction_occurred = TRUE;

Terminology Bindings

Vitals JSON fields should use:

JSON Path (example) Terminology Example Value
pre_vitals_json.bp_systolic.code LOINC 8480-6
pre_vitals_json.bp_diastolic.code LOINC 8462-4
pre_vitals_json.temperature.code LOINC 8310-5

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
admin_id Procedure Procedure.id
patient_id Patient Procedure.subject
encounter_id Encounter Procedure.encounter
order_id ServiceRequest Procedure.basedOn
component_id BiologicallyDerivedProduct Procedure.usedReference
start_datetime, end_datetime Procedure performedPeriod.start / .end
status Procedure status
pre_vitals_json, post_vitals_json Observation Separate Observation resources linked via partOf

9. transfusion_reactions

Purpose: Documentation and investigation of adverse transfusion reactions, including classification, severity, investigation findings, and MOH hemovigilance reporting status.

Field Specifications

Field Type Nullable Default Constraint Description
reaction_id BIGINT NO IDENTITY PK Reaction record ID
admin_id BIGINT NO FK → transfusion_administration.admin_id Related administration
patient_id BIGINT NO FK → patients.patient_id Patient
component_id BIGINT NO FK → blood_components.component_id Component involved
reaction_type VARCHAR(30) NO FK → md_transfusion_reaction_types.code Reaction type
severity VARCHAR(20) NO IN ('mild','moderate','severe','life_threatening','death') Severity
symptoms TEXT NO Signs/symptoms description
onset_time TIMESTAMP NO Time of reaction onset
investigation_findings TEXT YES Investigation summary
clerical_check_ok BOOLEAN NO TRUE Identity/label check result
dat_result VARCHAR(20) YES IN ('positive','negative','not_done') Direct antiglobulin test
hemolysis_check VARCHAR(20) YES IN ('present','absent','not_done') Hemolysis in plasma/urine
classification VARCHAR(50) YES Final classification (e.g., "definite hemolytic")
reported_to_moh BOOLEAN NO FALSE Reported to MOH hemovigilance
moh_report_reference VARCHAR(50) YES MOH report ID/reference
investigated_by BIGINT NO FK → providers.provider_id Pathologist/medical director
investigation_completed_datetime TIMESTAMP YES When investigation completed
outcome VARCHAR(30) YES IN ('recovered','ongoing','death','unknown') Patient outcome
related_lab_result_id BIGINT YES FK → lab_results.result_id Key post-reaction lab panel
comments TEXT YES Additional notes
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created timestamp
created_by BIGINT NO FK → users.user_id Created by
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Updated timestamp
updated_by BIGINT YES FK → users.user_id Updated by

SQL DDL

SQL
CREATE TABLE transfusion_reactions (
    reaction_id                    BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    admin_id                       BIGINT NOT NULL,
    patient_id                     BIGINT NOT NULL,
    component_id                   BIGINT NOT NULL,
    reaction_type                  VARCHAR(30) NOT NULL,
    severity                       VARCHAR(20) NOT NULL,
    symptoms                       TEXT NOT NULL,
    onset_time                     TIMESTAMP NOT NULL,
    investigation_findings         TEXT,
    clerical_check_ok              BOOLEAN NOT NULL DEFAULT TRUE,
    dat_result                     VARCHAR(20),
    hemolysis_check                VARCHAR(20),
    classification                 VARCHAR(50),
    reported_to_moh                BOOLEAN NOT NULL DEFAULT FALSE,
    moh_report_reference           VARCHAR(50),
    investigated_by                BIGINT NOT NULL,
    investigation_completed_datetime TIMESTAMP,
    outcome                        VARCHAR(30),
    related_lab_result_id          BIGINT,
    comments                       TEXT,
    created_at                     TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by                     BIGINT NOT NULL,
    updated_at                     TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by                     BIGINT,
    CONSTRAINT fk_tr_admin
        FOREIGN KEY (admin_id) REFERENCES transfusion_administration(admin_id),
    CONSTRAINT fk_tr_patient
        FOREIGN KEY (patient_id) REFERENCES patients(patient_id),
    CONSTRAINT fk_tr_component
        FOREIGN KEY (component_id) REFERENCES blood_components(component_id),
    CONSTRAINT fk_tr_investigated_by
        FOREIGN KEY (investigated_by) REFERENCES providers(provider_id),
    CONSTRAINT fk_tr_lab_result
        FOREIGN KEY (related_lab_result_id) REFERENCES lab_results(result_id),
    CONSTRAINT fk_tr_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_tr_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT fk_tr_reaction_type
        FOREIGN KEY (reaction_type) REFERENCES md_transfusion_reaction_types(code),
    CONSTRAINT chk_tr_severity
        CHECK (severity IN ('mild','moderate','severe','life_threatening','death')),
    CONSTRAINT chk_tr_dat_result
        CHECK (dat_result IS NULL OR dat_result IN ('positive','negative','not_done')),
    CONSTRAINT chk_tr_hemolysis
        CHECK (hemolysis_check IS NULL OR hemolysis_check IN ('present','absent','not_done')),
    CONSTRAINT chk_tr_outcome
        CHECK (outcome IS NULL OR outcome IN ('recovered','ongoing','death','unknown')),
    CONSTRAINT chk_tr_moh_reporting
        CHECK (reported_to_moh = FALSE OR moh_report_reference IS NOT NULL)
);

CREATE INDEX idx_tr_patient ON transfusion_reactions(patient_id);
CREATE INDEX idx_tr_type ON transfusion_reactions(reaction_type);
CREATE INDEX idx_tr_moh ON transfusion_reactions(reported_to_moh);
CREATE INDEX idx_tr_admin ON transfusion_reactions(admin_id);

Terminology Bindings

Field Terminology Example Value
reaction_type ISBT hemovigilance + local FNHTR, ALLERGIC_MILD
classification ISBT hemovigilance definite, possible
severity Local ValueSet severe

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
reaction_id AdverseEvent AdverseEvent.id
patient_id Patient AdverseEvent.subject
component_id BiologicallyDerivedProduct AdverseEvent.suspectEntity.instance
onset_time AdverseEvent AdverseEvent.date
reaction_type AdverseEvent AdverseEvent.event
severity AdverseEvent AdverseEvent.seriousness / severity
reported_to_moh AdverseEvent AdverseEvent.outcome / extension[reportedToAuthority]
investigation_findings AdverseEvent AdverseEvent.note

10. blood_quarantine_log

Purpose: Quarantine tracking for units pending testing or under investigation (e.g., positive infectious markers, suspected reaction).

Field Specifications

Field Type Nullable Default Constraint Description
quarantine_id BIGINT NO IDENTITY PK Quarantine record ID
component_id BIGINT NO FK → blood_components.component_id Component quarantined
quarantine_reason VARCHAR(200) NO Reason for quarantine
quarantined_datetime TIMESTAMP NO CURRENT_TIMESTAMP When quarantined
quarantined_by BIGINT NO FK → users.user_id User who quarantined
released_datetime TIMESTAMP YES quarantined_datetime When released
released_by BIGINT YES FK → users.user_id User who released
release_reason VARCHAR(200) YES Reason for release
final_disposition VARCHAR(20) YES IN ('returned_to_inventory','discarded','transfused') Outcome after quarantine
notes TEXT YES Additional notes
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created timestamp
created_by BIGINT NO FK → users.user_id Created by
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Updated timestamp
updated_by BIGINT YES FK → users.user_id Updated by

SQL DDL

SQL
CREATE TABLE blood_quarantine_log (
    quarantine_id        BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    component_id         BIGINT NOT NULL,
    quarantine_reason    VARCHAR(200) NOT NULL,
    quarantined_datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    quarantined_by       BIGINT NOT NULL,
    released_datetime    TIMESTAMP,
    released_by          BIGINT,
    release_reason       VARCHAR(200),
    final_disposition    VARCHAR(20),
    notes                TEXT,
    created_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by           BIGINT NOT NULL,
    updated_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by           BIGINT,
    CONSTRAINT fk_bql_component
        FOREIGN KEY (component_id) REFERENCES blood_components(component_id)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_bql_quarantined_by
        FOREIGN KEY (quarantined_by) REFERENCES users(user_id),
    CONSTRAINT fk_bql_released_by
        FOREIGN KEY (released_by) REFERENCES users(user_id),
    CONSTRAINT fk_bql_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_bql_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT chk_bql_disposition
        CHECK (final_disposition IS NULL OR final_disposition IN ('returned_to_inventory','discarded','transfused')),
    CONSTRAINT chk_bql_release_time
        CHECK (released_datetime IS NULL OR released_datetime >= quarantined_datetime)
);

CREATE INDEX idx_bql_component ON blood_quarantine_log(component_id);
CREATE INDEX idx_bql_quarantine_time ON blood_quarantine_log(quarantined_datetime);

Terminology Bindings

Field Terminology Example Value
quarantine_reason Local ValueSet PENDING_INFECTIOUS_RESULTS
final_disposition Local ValueSet discarded

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
quarantine_id BiologicallyDerivedProduct extension[quarantine-log].id
component_id BiologicallyDerivedProduct BiologicallyDerivedProduct.id
quarantine_reason BiologicallyDerivedProduct extension[quarantine-reason].valueCodeableConcept
quarantined_datetime BiologicallyDerivedProduct extension[quarantine-start].valueDateTime

11. blood_discard_log

Purpose: Documentation of discarded/expired blood products, including reason, method, and witnesses, to support MOH and internal audit requirements.

Field Specifications

Field Type Nullable Default Constraint Description
discard_id BIGINT NO IDENTITY PK Discard record ID
component_id BIGINT NO FK → blood_components.component_id Component discarded
discard_reason VARCHAR(100) NO FK → md_discard_reasons.code Reason for discard
discard_datetime TIMESTAMP NO CURRENT_TIMESTAMP When discarded
discarded_by BIGINT NO FK → users.user_id User discarding
witness_id BIGINT YES FK → users.user_id Witness
disposal_method VARCHAR(50) NO IN ('biohazard_incineration','return_to_supplier','other') Disposal method
biohazard_manifest_number VARCHAR(50) YES Manifest/reference number
notes TEXT YES Additional notes
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created timestamp
created_by BIGINT NO FK → users.user_id Created by
updated_at TIMESTAMP NO CURRENT_TIMESTAMP Updated timestamp
updated_by BIGINT YES FK → users.user_id Updated by

SQL DDL

SQL
CREATE TABLE blood_discard_log (
    discard_id               BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    component_id             BIGINT NOT NULL,
    discard_reason           VARCHAR(100) NOT NULL,
    discard_datetime         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    discarded_by             BIGINT NOT NULL,
    witness_id               BIGINT,
    disposal_method          VARCHAR(50) NOT NULL,
    biohazard_manifest_number VARCHAR(50),
    notes                    TEXT,
    created_at               TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by               BIGINT NOT NULL,
    updated_at               TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by               BIGINT,
    CONSTRAINT fk_bdl_component
        FOREIGN KEY (component_id) REFERENCES blood_components(component_id)
        ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_bdl_discarded_by
        FOREIGN KEY (discarded_by) REFERENCES users(user_id),
    CONSTRAINT fk_bdl_witness
        FOREIGN KEY (witness_id) REFERENCES users(user_id),
    CONSTRAINT fk_bdl_created_by
        FOREIGN KEY (created_by) REFERENCES users(user_id),
    CONSTRAINT fk_bdl_updated_by
        FOREIGN KEY (updated_by) REFERENCES users(user_id),
    CONSTRAINT fk_bdl_discard_reason
        FOREIGN KEY (discard_reason) REFERENCES md_discard_reasons(code),
    CONSTRAINT chk_bdl_disposal_method
        CHECK (disposal_method IN ('biohazard_incineration','return_to_supplier','other'))
);

CREATE INDEX idx_bdl_component ON blood_discard_log(component_id);
CREATE INDEX idx_bdl_reason ON blood_discard_log(discard_reason);
CREATE INDEX idx_bdl_datetime ON blood_discard_log(discard_datetime);

Terminology Bindings

Field Terminology Example Value
discard_reason Local ValueSet (aligned with MOH) EXPIRED, INFECTIOUS_POSITIVE
disposal_method Local ValueSet biohazard_incineration

FHIR Resource Mapping

Table Field FHIR Resource FHIR Path
discard_id BiologicallyDerivedProduct extension[discard-log].id
component_id BiologicallyDerivedProduct BiologicallyDerivedProduct.id
discard_reason BiologicallyDerivedProduct extension[discard-reason].valueCodeableConcept
discard_datetime BiologicallyDerivedProduct extension[discard-datetime].valueDateTime

Terminology Master Data (Referenced)

These are master tables owned by the Blood Bank module but defined in the master-data specification; referenced here for clarity:

  • md_abo_groups (ABO/Rh Blood Group Codes)
  • md_rh_types
  • md_blood_component_types
  • md_transfusion_reaction_types
  • md_donor_deferral_reasons
  • md_infectious_disease_tests
  • md_component_storage_zones
  • md_crossmatch_eligibility_rules
  • md_transfusion_indications
  • md_discard_reasons

Data Volume Estimates

Approximate volumes for a 300-bed UAE hospital.

Table Initial Rows (Year 1) Annual Growth Notes
blood_donors 5,000 +1,000/year Active + deferred donors
blood_donations 8,000 +8,000/year Includes mobile drives
blood_components 16,000 +16,000/year ~2 components per donation average
blood_component_inventory 20,000 +20,000/year Includes historical issued/returned records
blood_type_screen 40,000 +40,000/year Inpatients + pre-op + antenatal
crossmatch_records 35,000 +35,000/year Multiple units per order
transfusion_orders 20,000 +20,000/year All components
transfusion_administration 25,000 +25,000/year Includes partially transfused units
transfusion_reactions 200 +200/year ~0.5–1% reaction rate
blood_quarantine_log 3,000 +3,000/year Includes temporary quarantines
blood_discard_log 2,000 +2,000/year Expired, damaged, infectious

Storage planning should allow for at least 10 years of online data for clinical traceability, with appropriate indexing and partitioning (e.g., by year on high-volume tables like blood_type_screen, crossmatch_records, transfusion_administration).


Data Retention Policy (UAE Context)

UAE MOH blood safety regulations and DOH/DHA hemovigilance requirements generally expect long-term traceability from donor to recipient, often 15–30 years. UAE PDPL requires data minimisation and secure archival.

Table Minimum Retention Rationale / Notes
blood_donors 30 years after last donation Donor deferral and look-back investigations
blood_donations 30 years Traceability of infectious disease investigations
blood_components 30 years Donor-to-recipient traceability per MOH blood safety
blood_component_inventory 15 years Inventory and issue/return audit trail
blood_type_screen 15 years Historical blood group and antibody history for patient safety
crossmatch_records 15 years Compatibility evidence for transfusions
transfusion_orders 15 years Clinical decision and medico-legal record
transfusion_administration 15 years Bedside administration and verification audit
transfusion_reactions 30 years Hemovigilance, MOH reporting, medico-legal
blood_quarantine_log 15 years Quarantine decisions and outcomes
blood_discard_log 15 years Wastage, biohazard disposal audit

Implementation Notes:

  • After the retention period, records should be securely anonymised or destroyed in line with UAE PDPL and facility policy.
  • For donor–recipient traceability, consider immutable audit logs and WORM storage for key linkage data (blood_donations, blood_components, transfusion_administration, transfusion_reactions).
  • Archival strategies (cold storage, partitioning) must still support regulatory queries and MOH hemovigilance audits on historical data.
content/clinical/blood-bank/03-data-specifications.md Generated 2026-02-20 22:54