Policy & Contract Management Data Specifications
Shared Entity References
This module OWNS payer, insurance plan, and contract master data. It REFERENCES shared entities from other modules as follows:
| Shared Entity |
Owning Module |
Table(s) |
FK Used in Policy & Contract Mgmt |
| Facilities |
ehr-patient-mgmt |
facilities |
facilities.facility_id |
| Departments |
ehr-patient-mgmt |
departments |
departments.department_id |
| Users & Auth |
ehr-patient-mgmt |
users, roles, permissions |
users.user_id |
Payers, insurance plans, and contracts defined here are referenced by other modules (e.g. Billing & Claims, Patient Access, CPOE) via:
| Shared Entity |
Table(s) |
Typical FK in Other Modules |
| Payers |
payers |
payers.payer_id |
| Insurance |
insurance_plans |
insurance_plans.plan_id |
| Contracts |
contracts, contract_fee_schedules, fee_schedule_items |
contracts.contract_id, contract_fee_schedules.fee_schedule_id |
Entity Relationship Diagram
erDiagram
facilities ||--o{ contracts : "has"
facilities ||--o{ payer_networks : "in network"
users ||--o{ contracts : "approved by"
users ||--o{ contract_fee_schedules : "created by"
users ||--o{ contract_amendments : "approved by"
payers ||--o{ insurance_plans : "offers"
payers ||--o{ contracts : "contracts with"
payers ||--o{ payer_contacts : "has"
payers ||--o{ payer_networks : "defines"
payers ||--o{ coverage_rules : "governs"
payers ||--o{ prior_auth_rules : "governs"
payers ||--o{ reimbursement_rates : "analyzed for"
insurance_plans ||--o{ coverage_rules : "constrained by"
insurance_plans ||--o{ prior_auth_rules : "constrained by"
contracts ||--o{ contract_fee_schedules : "has"
contracts ||--o{ contract_amendments : "amended by"
contracts ||--o{ reimbursement_rates : "baseline for"
contracts ||--o{ payer_networks : "implied by"
contract_fee_schedules ||--o{ fee_schedule_items : "contains"
payers {
bigint payer_id PK
}
insurance_plans {
bigint plan_id PK
bigint payer_id FK
}
contracts {
bigint contract_id PK
bigint payer_id FK
bigint facility_id FK
bigint approved_by FK
bigint parent_contract_id FK
}
contract_fee_schedules {
bigint fee_schedule_id PK
bigint contract_id FK
bigint created_by FK
}
fee_schedule_items {
bigint item_id PK
bigint fee_schedule_id FK
}
coverage_rules {
bigint rule_id PK
bigint payer_id FK
bigint plan_id FK
}
prior_auth_rules {
bigint rule_id PK
bigint payer_id FK
bigint plan_id FK
}
payer_contacts {
bigint contact_id PK
bigint payer_id FK
}
contract_amendments {
bigint amendment_id PK
bigint contract_id FK
bigint approved_by FK
}
payer_networks {
bigint network_id PK
bigint payer_id FK
bigint facility_id FK
}
reimbursement_rates {
bigint rate_id PK
bigint payer_id FK
bigint contract_id FK
}
Table Definitions
Conventions:
- SQL shown in PostgreSQL style.
- Timestamps are in UTC.
- All tables include created_at, created_by, updated_at, updated_by for auditability (UAE PDPL accountability).
1. payers
Purpose: Canonical master of all insurance payers and TPAs used by the organization, including DHA/DOH license identifiers and eClaim routing configuration. Referenced by all RCM and clinical modules.
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
payer_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
payer_code |
VARCHAR(30) |
NO |
— |
UNIQUE |
Internal payer code / DHA/DOH code |
payer_name_en |
VARCHAR(255) |
NO |
— |
— |
Payer legal name (English) |
payer_name_ar |
VARCHAR(255) |
YES |
— |
— |
Payer legal name (Arabic) |
payer_type |
VARCHAR(30) |
NO |
'insurance' |
CHECK in ('insurance','tpa','government','self-pay','other') |
High-level type |
payer_class |
VARCHAR(30) |
NO |
— |
FK → payer_classifications.code (ref/master) |
DHA/DOH payer classification (e.g. THIQA, SAADA, private) |
tpa_name |
VARCHAR(255) |
YES |
— |
— |
Linked TPA if applicable |
dha_license |
VARCHAR(50) |
YES |
— |
— |
DHA payer license number (Dubai) |
doh_license |
VARCHAR(50) |
YES |
— |
— |
DOH payer license number (Abu Dhabi) |
moh_license |
VARCHAR(50) |
YES |
— |
— |
MOH license if applicable (federal) |
trade_license_number |
VARCHAR(50) |
YES |
— |
— |
UAE trade license number |
payer_classification_source |
VARCHAR(20) |
YES |
— |
CHECK in ('DHA','DOH','MOH','internal') |
Source of classification |
eclaim_routing |
VARCHAR(30) |
YES |
— |
CHECK in ('DHA-eClaimLink','DOH-eClaims','direct-portal','paper','other') |
Primary submission channel |
eligibility_endpoint |
VARCHAR(500) |
YES |
— |
— |
URL / endpoint for eligibility checks |
claims_endpoint |
VARCHAR(500) |
YES |
— |
— |
URL / endpoint for claims submission |
auth_endpoint |
VARCHAR(500) |
YES |
— |
— |
URL / endpoint for prior auth |
contact_email |
VARCHAR(255) |
YES |
— |
— |
Generic payer contact email |
contact_phone |
VARCHAR(50) |
YES |
— |
— |
Generic payer contact phone (+971…) |
address_line1 |
VARCHAR(255) |
YES |
— |
— |
Address line 1 |
address_line2 |
VARCHAR(255) |
YES |
— |
— |
Address line 2 / PO Box |
emirate |
VARCHAR(50) |
YES |
— |
CHECK in ('Abu Dhabi','Dubai','Sharjah','Ajman','Umm Al Quwain','Ras Al Khaimah','Fujairah') |
Emirate of main office |
country |
VARCHAR(100) |
NO |
'United Arab Emirates' |
— |
Country |
is_active |
BOOLEAN |
NO |
TRUE |
— |
Active flag |
activation_date |
DATE |
YES |
— |
— |
When activated in HIS |
deactivation_date |
DATE |
YES |
— |
CHECK (deactivation_date IS NULL OR deactivation_date >= activation_date) |
When deactivated |
notes |
TEXT |
YES |
— |
— |
Free-text notes |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
User who created |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Last updated timestamp |
updated_by |
BIGINT |
YES |
— |
FK → users.user_id |
User who last updated |
SQL DDL
SQLCREATE TABLE payers (
payer_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
payer_code VARCHAR(30) NOT NULL UNIQUE,
payer_name_en VARCHAR(255) NOT NULL,
payer_name_ar VARCHAR(255),
payer_type VARCHAR(30) NOT NULL DEFAULT 'insurance',
payer_class VARCHAR(30) NOT NULL,
tpa_name VARCHAR(255),
dha_license VARCHAR(50),
doh_license VARCHAR(50),
moh_license VARCHAR(50),
trade_license_number VARCHAR(50),
payer_classification_source VARCHAR(20),
eclaim_routing VARCHAR(30),
eligibility_endpoint VARCHAR(500),
claims_endpoint VARCHAR(500),
auth_endpoint VARCHAR(500),
contact_email VARCHAR(255),
contact_phone VARCHAR(50),
address_line1 VARCHAR(255),
address_line2 VARCHAR(255),
emirate VARCHAR(50),
country VARCHAR(100) NOT NULL DEFAULT 'United Arab Emirates',
is_active BOOLEAN NOT NULL DEFAULT TRUE,
activation_date DATE,
deactivation_date DATE,
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 chk_payers_type
CHECK (payer_type IN ('insurance','tpa','government','self-pay','other')),
CONSTRAINT chk_payers_class_source
CHECK (payer_classification_source IS NULL OR payer_classification_source IN ('DHA','DOH','MOH','internal')),
CONSTRAINT chk_payers_eclaim_routing
CHECK (eclaim_routing IS NULL OR eclaim_routing IN ('DHA-eClaimLink','DOH-eClaims','direct-portal','paper','other')),
CONSTRAINT chk_payers_emirate
CHECK (emirate IS NULL OR emirate IN ('Abu Dhabi','Dubai','Sharjah','Ajman','Umm Al Quwain','Ras Al Khaimah','Fujairah')),
CONSTRAINT chk_payers_deactivation_after_activation
CHECK (deactivation_date IS NULL OR activation_date IS NULL OR deactivation_date >= activation_date)
);
COMMENT ON TABLE payers IS 'Insurance payer and TPA master for UAE facilities.';
COMMENT ON COLUMN payers.payer_class IS 'Classification per DHA/DOH payer registries (e.g. THIQA, SAADA, private).';
ALTER TABLE payers
ADD CONSTRAINT fk_payers_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_payers_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE;
CREATE INDEX idx_payers_name_en ON payers (payer_name_en);
CREATE INDEX idx_payers_class ON payers (payer_class);
CREATE INDEX idx_payers_active ON payers (is_active);
CREATE INDEX idx_payers_dha_license ON payers (dha_license);
CREATE INDEX idx_payers_doh_license ON payers (doh_license);
Terminology Bindings
| Field |
Terminology |
Example Value |
payer_class |
DHA/DOH payer classification code set (local master) |
THIQA, SAADA, PRIVATE |
emirate |
UAE emirate codes |
Dubai |
payer_type |
Internal value set |
insurance |
FHIR Mapping
Payers map primarily to Organization.
| Table Field |
FHIR Resource |
FHIR Path |
payer_id |
Organization |
Organization.id |
payer_name_en |
Organization |
Organization.name |
payer_name_ar |
Organization |
Organization.alias (Arabic name) |
payer_type |
Organization |
Organization.type |
payer_class |
Organization |
Organization.extension[payerClass] (custom UAE profile) |
dha_license |
Organization |
Organization.identifier (system = DHA) |
doh_license |
Organization |
Organization.identifier (system = DOH) |
contact_email |
Organization |
Organization.telecom |
contact_phone |
Organization |
Organization.telecom |
address_*, emirate, country |
Organization |
Organization.address |
is_active |
Organization |
Organization.active |
2. insurance_plans
Purpose: Defines insurance products/plans offered by each payer, including network type, coverage level, and basic financial parameters used for eligibility and estimation.
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
plan_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
payer_id |
BIGINT |
NO |
— |
FK → payers.payer_id |
Owning payer |
plan_code |
VARCHAR(50) |
NO |
— |
UNIQUE (per payer) |
Plan code (e.g. THIQA-BASIC) |
plan_name_en |
VARCHAR(255) |
NO |
— |
— |
Plan name (English) |
plan_name_ar |
VARCHAR(255) |
YES |
— |
— |
Plan name (Arabic) |
plan_type |
VARCHAR(30) |
NO |
— |
CHECK in ('HMO','PPO','EPO','POS','Indemnity','Government','Other') |
Plan type |
network_type |
VARCHAR(30) |
NO |
— |
CHECK in ('In-Network','Out-of-Network','Tiered','Open') |
Network model |
coverage_level |
VARCHAR(30) |
YES |
— |
e.g. basic, enhanced, VIP |
Benefit richness |
payer_class |
VARCHAR(30) |
YES |
— |
Optional override of payer_class |
For plan-specific class |
annual_maximum |
NUMERIC(14,2) |
YES |
— |
≥ 0 |
Annual benefit max (AED) |
lifetime_maximum |
NUMERIC(14,2) |
YES |
— |
≥ 0 |
Lifetime max (AED) |
copay_percentage |
NUMERIC(5,2) |
YES |
— |
0–100 |
Standard copay % |
coinsurance_percentage |
NUMERIC(5,2) |
YES |
— |
0–100 |
Coinsurance % |
deductible |
NUMERIC(14,2) |
YES |
— |
≥ 0 |
Deductible (AED) |
oop_maximum |
NUMERIC(14,2) |
YES |
— |
≥ 0 |
Out-of-pocket max (AED) |
effective_date |
DATE |
NO |
— |
— |
Plan start date |
expiry_date |
DATE |
YES |
— |
≥ effective_date |
Plan end date |
is_active |
BOOLEAN |
NO |
TRUE |
— |
Active flag |
requires_referral |
BOOLEAN |
NO |
FALSE |
— |
PCP referral requirement |
notes |
TEXT |
YES |
— |
— |
Free-text notes |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
Creator |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Updated timestamp |
updated_by |
BIGINT |
YES |
— |
FK → users.user_id |
Last updater |
SQL DDL
SQLCREATE TABLE insurance_plans (
plan_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
payer_id BIGINT NOT NULL,
plan_code VARCHAR(50) NOT NULL,
plan_name_en VARCHAR(255) NOT NULL,
plan_name_ar VARCHAR(255),
plan_type VARCHAR(30) NOT NULL,
network_type VARCHAR(30) NOT NULL,
coverage_level VARCHAR(30),
payer_class VARCHAR(30),
annual_maximum NUMERIC(14,2),
lifetime_maximum NUMERIC(14,2),
copay_percentage NUMERIC(5,2),
coinsurance_percentage NUMERIC(5,2),
deductible NUMERIC(14,2),
oop_maximum NUMERIC(14,2),
effective_date DATE NOT NULL,
expiry_date DATE,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
requires_referral 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 uq_insurance_plans_payer_code UNIQUE (payer_id, plan_code),
CONSTRAINT chk_insurance_plans_plan_type
CHECK (plan_type IN ('HMO','PPO','EPO','POS','Indemnity','Government','Other')),
CONSTRAINT chk_insurance_plans_network_type
CHECK (network_type IN ('In-Network','Out-of-Network','Tiered','Open')),
CONSTRAINT chk_insurance_plans_copay_pct
CHECK (copay_percentage IS NULL OR (copay_percentage >= 0 AND copay_percentage <= 100)),
CONSTRAINT chk_insurance_plans_coins_pct
CHECK (coinsurance_percentage IS NULL OR (coinsurance_percentage >= 0 AND coinsurance_percentage <= 100)),
CONSTRAINT chk_insurance_plans_amounts_non_negative
CHECK (
(annual_maximum IS NULL OR annual_maximum >= 0) AND
(lifetime_maximum IS NULL OR lifetime_maximum >= 0) AND
(deductible IS NULL OR deductible >= 0) AND
(oop_maximum IS NULL OR oop_maximum >= 0)
),
CONSTRAINT chk_insurance_plans_expiry_after_effective
CHECK (expiry_date IS NULL OR expiry_date >= effective_date)
);
COMMENT ON TABLE insurance_plans IS 'Insurance products/plans per payer used for eligibility and estimation.';
ALTER TABLE insurance_plans
ADD CONSTRAINT fk_insurance_plans_payer
FOREIGN KEY (payer_id) REFERENCES payers(payer_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_insurance_plans_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_insurance_plans_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE;
CREATE INDEX idx_insurance_plans_payer ON insurance_plans (payer_id);
CREATE INDEX idx_insurance_plans_active ON insurance_plans (is_active, effective_date, expiry_date);
CREATE INDEX idx_insurance_plans_code ON insurance_plans (plan_code);
Terminology Bindings
| Field |
Terminology |
Example Value |
plan_type |
Internal value set aligned with DHA/DOH |
HMO |
coverage_level |
Facility-defined |
VIP |
payer_class |
DHA/DOH payer classification |
THIQA |
FHIR Mapping
Insurance plans map to InsurancePlan and are referenced from Coverage.
| Table Field |
FHIR Resource |
FHIR Path |
plan_id |
InsurancePlan |
InsurancePlan.id |
plan_name_en |
InsurancePlan |
InsurancePlan.name |
plan_code |
InsurancePlan |
InsurancePlan.identifier |
plan_type |
InsurancePlan |
InsurancePlan.type |
coverage_level |
InsurancePlan |
InsurancePlan.extension[coverageLevel] |
annual_maximum |
InsurancePlan |
InsurancePlan.coverage.benefit.limit.value |
effective_date |
InsurancePlan |
InsurancePlan.period.start |
expiry_date |
InsurancePlan |
InsurancePlan.period.end |
payer_id |
InsurancePlan |
InsurancePlan.ownedBy.reference → Organization/payer_id |
3. contracts
Purpose: Stores contractual agreements between each payer and facility, including contract type, rate methodology, payment terms, and versioning. Drives expected reimbursement and payment timelines.
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
contract_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
payer_id |
BIGINT |
NO |
— |
FK → payers.payer_id |
Contracted payer |
facility_id |
BIGINT |
NO |
— |
FK → facilities.facility_id |
Facility covered |
department_id |
BIGINT |
YES |
— |
FK → departments.department_id |
Optional department-specific contract |
contract_code |
VARCHAR(50) |
NO |
— |
UNIQUE (payer, facility, version) |
Internal contract code |
contract_type |
VARCHAR(30) |
NO |
— |
CHECK in ('fee-for-service','per-diem','case-rate','capitation','percentage-of-tariff','mixed') |
Contract type |
rate_methodology |
VARCHAR(30) |
NO |
— |
FK → rate_methodologies.code (ref/master) |
Rate calculation method |
payment_terms_days |
INT |
NO |
30 |
> 0 |
Days to payment per contract |
grace_period_days |
INT |
YES |
— |
≥ 0 |
Additional grace days |
effective_date |
DATE |
NO |
— |
— |
Contract start date |
expiry_date |
DATE |
NO |
— |
> effective_date |
Contract end date |
auto_renew |
BOOLEAN |
NO |
FALSE |
— |
Auto-renew flag |
auto_renew_period_months |
INT |
YES |
— |
≥ 0 |
Renewal period |
status |
VARCHAR(30) |
NO |
'draft' |
CHECK in ('draft','under_review','pending_signature','active','expired','terminated') |
Lifecycle status |
approved_by |
BIGINT |
YES |
— |
FK → users.user_id |
Final approver |
approved_date |
TIMESTAMP |
YES |
— |
— |
Approval timestamp |
document_path |
VARCHAR(500) |
YES |
— |
— |
Path/URL to signed PDF |
version |
INT |
NO |
1 |
≥ 1 |
Version number |
parent_contract_id |
BIGINT |
YES |
— |
FK → contracts.contract_id |
Previous version |
termination_date |
DATE |
YES |
— |
≥ effective_date |
Early termination date |
termination_reason |
TEXT |
YES |
— |
— |
Reason for termination |
notes |
TEXT |
YES |
— |
— |
Free-text notes |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
Creator |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Updated timestamp |
updated_by |
BIGINT |
YES |
— |
FK → users.user_id |
Last updater |
SQL DDL
SQLCREATE TABLE contracts (
contract_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
payer_id BIGINT NOT NULL,
facility_id BIGINT NOT NULL,
department_id BIGINT,
contract_code VARCHAR(50) NOT NULL,
contract_type VARCHAR(30) NOT NULL,
rate_methodology VARCHAR(30) NOT NULL,
payment_terms_days INT NOT NULL DEFAULT 30,
grace_period_days INT,
effective_date DATE NOT NULL,
expiry_date DATE NOT NULL,
auto_renew BOOLEAN NOT NULL DEFAULT FALSE,
auto_renew_period_months INT,
status VARCHAR(30) NOT NULL DEFAULT 'draft',
approved_by BIGINT,
approved_date TIMESTAMP,
document_path VARCHAR(500),
version INT NOT NULL DEFAULT 1,
parent_contract_id BIGINT,
termination_date DATE,
termination_reason TEXT,
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_contracts_code_version UNIQUE (payer_id, facility_id, contract_code, version),
CONSTRAINT chk_contracts_type
CHECK (contract_type IN ('fee-for-service','per-diem','case-rate','capitation','percentage-of-tariff','mixed')),
CONSTRAINT chk_contracts_payment_terms
CHECK (payment_terms_days > 0),
CONSTRAINT chk_contracts_grace_period
CHECK (grace_period_days IS NULL OR grace_period_days >= 0),
CONSTRAINT chk_contracts_dates
CHECK (expiry_date > effective_date),
CONSTRAINT chk_contracts_termination_date
CHECK (termination_date IS NULL OR termination_date >= effective_date),
CONSTRAINT chk_contracts_status
CHECK (status IN ('draft','under_review','pending_signature','active','expired','terminated'))
);
COMMENT ON TABLE contracts IS 'Contracts between payers and facilities, including type, rate methodology, and lifecycle status.';
ALTER TABLE contracts
ADD CONSTRAINT fk_contracts_payer
FOREIGN KEY (payer_id) REFERENCES payers(payer_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_contracts_facility
FOREIGN KEY (facility_id) REFERENCES facilities(facility_id) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_contracts_department
FOREIGN KEY (department_id) REFERENCES departments(department_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_contracts_parent
FOREIGN KEY (parent_contract_id) REFERENCES contracts(contract_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_contracts_approved_by
FOREIGN KEY (approved_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_contracts_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_contracts_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE;
CREATE INDEX idx_contracts_payer_facility ON contracts (payer_id, facility_id);
CREATE INDEX idx_contracts_status_dates ON contracts (status, effective_date, expiry_date);
CREATE INDEX idx_contracts_active ON contracts (payer_id, facility_id, status)
WHERE status = 'active';
CREATE INDEX idx_contracts_expiry_alerts ON contracts (expiry_date)
WHERE status IN ('active','pending_signature','under_review');
Terminology Bindings
| Field |
Terminology |
Example Value |
contract_type |
Facility-defined contract type master |
fee-for-service |
rate_methodology |
Facility-defined rate methodology master |
90%_DHA_TARIFF |
status |
Internal lifecycle value set |
active |
FHIR Mapping
Contracts map to Contract and are referenced from Coverage and Claim.
| Table Field |
FHIR Resource |
FHIR Path |
contract_id |
Contract |
Contract.id |
contract_code |
Contract |
Contract.identifier |
payer_id |
Contract |
Contract.party[role='payer'].reference |
facility_id |
Contract |
Contract.party[role='provider'].reference |
contract_type |
Contract |
Contract.type |
effective_date |
Contract |
Contract.applies.start |
expiry_date |
Contract |
Contract.applies.end |
payment_terms_days |
Contract |
Contract.term.text (or extension) |
status |
Contract |
Contract.status |
document_path |
Contract |
Contract.legal (Attachment URL) |
4. contract_fee_schedules
Purpose: Header records for fee schedules associated with a contract (e.g. “DHA 2026 Outpatient Tariff – 90%”).
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
fee_schedule_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
contract_id |
BIGINT |
NO |
— |
FK → contracts.contract_id |
Owning contract |
schedule_name |
VARCHAR(255) |
NO |
— |
— |
Human-readable name |
base_tariff |
VARCHAR(30) |
NO |
— |
CHECK in ('DHA','DOH','Custom','Other') |
Base tariff source |
tariff_version |
VARCHAR(50) |
YES |
— |
— |
e.g. DHA-2026 |
rate_methodology |
VARCHAR(30) |
YES |
— |
FK → rate_methodologies.code |
Overrides contract if needed |
effective_date |
DATE |
NO |
— |
— |
Start date |
expiry_date |
DATE |
YES |
— |
≥ effective_date |
End date |
status |
VARCHAR(30) |
NO |
'draft' |
CHECK in ('draft','under_review','active','retired') |
Lifecycle |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
Creator |
approved_by |
BIGINT |
YES |
— |
FK → users.user_id |
Approver |
approved_date |
TIMESTAMP |
YES |
— |
— |
Approval timestamp |
notes |
TEXT |
YES |
— |
— |
Notes |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Updated timestamp |
updated_by |
BIGINT |
YES |
— |
FK → users.user_id |
Last updater |
SQL DDL
SQLCREATE TABLE contract_fee_schedules (
fee_schedule_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
contract_id BIGINT NOT NULL,
schedule_name VARCHAR(255) NOT NULL,
base_tariff VARCHAR(30) NOT NULL,
tariff_version VARCHAR(50),
rate_methodology VARCHAR(30),
effective_date DATE NOT NULL,
expiry_date DATE,
status VARCHAR(30) NOT NULL DEFAULT 'draft',
created_by BIGINT NOT NULL,
approved_by BIGINT,
approved_date TIMESTAMP,
notes TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_by BIGINT,
CONSTRAINT chk_contract_fee_schedules_base_tariff
CHECK (base_tariff IN ('DHA','DOH','Custom','Other')),
CONSTRAINT chk_contract_fee_schedules_status
CHECK (status IN ('draft','under_review','active','retired')),
CONSTRAINT chk_contract_fee_schedules_dates
CHECK (expiry_date IS NULL OR expiry_date >= effective_date)
);
COMMENT ON TABLE contract_fee_schedules IS 'Fee schedule headers linked to contracts, based on DHA/DOH or custom tariffs.';
ALTER TABLE contract_fee_schedules
ADD CONSTRAINT fk_fee_schedules_contract
FOREIGN KEY (contract_id) REFERENCES contracts(contract_id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT fk_fee_schedules_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_fee_schedules_approved_by
FOREIGN KEY (approved_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_fee_schedules_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE;
CREATE INDEX idx_fee_schedules_contract ON contract_fee_schedules (contract_id);
CREATE INDEX idx_fee_schedules_status ON contract_fee_schedules (status);
CREATE INDEX idx_fee_schedules_effective ON contract_fee_schedules (effective_date, expiry_date);
Terminology Bindings
| Field |
Terminology |
Example Value |
base_tariff |
Regulatory tariff source |
DHA |
rate_methodology |
Facility-defined |
90%_DHA_TARIFF |
status |
Internal lifecycle |
active |
FHIR Mapping
Fee schedules map to ChargeItemDefinition or Contract.term.asset in FHIR.
| Table Field |
FHIR Resource |
FHIR Path |
fee_schedule_id |
ChargeItemDefinition |
ChargeItemDefinition.id |
schedule_name |
ChargeItemDefinition |
ChargeItemDefinition.title |
base_tariff |
ChargeItemDefinition |
ChargeItemDefinition.extension[baseTariff] |
effective_date |
ChargeItemDefinition |
ChargeItemDefinition.effectivePeriod.start |
expiry_date |
ChargeItemDefinition |
ChargeItemDefinition.effectivePeriod.end |
contract_id |
Contract |
Contract.term.asset (reference to ChargeItemDefinition) |
5. fee_schedule_items
Purpose: Line-level mapping of CPT codes (and modifiers) to contracted facility and professional rates for a given fee schedule.
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
item_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
fee_schedule_id |
BIGINT |
NO |
— |
FK → contract_fee_schedules.fee_schedule_id |
Parent schedule |
cpt_code |
VARCHAR(10) |
NO |
— |
— |
CPT procedure code |
description |
TEXT |
YES |
— |
— |
Description (from CPT master) |
modifier |
VARCHAR(10) |
YES |
— |
— |
CPT modifier (e.g. 26, TC) |
rate_type |
VARCHAR(30) |
NO |
'standard' |
CHECK in ('standard','discounted','premium','penalty') |
Rate category |
facility_rate |
NUMERIC(14,2) |
YES |
— |
≥ 0 |
Facility component rate (AED) |
professional_rate |
NUMERIC(14,2) |
YES |
— |
≥ 0 |
Professional component rate (AED) |
unit_limit |
INT |
YES |
— |
≥ 0 |
Max units per claim line |
is_bundled |
BOOLEAN |
NO |
FALSE |
— |
Bundled into other code |
bundle_parent_cpt |
VARCHAR(10) |
YES |
— |
— |
Parent CPT if bundled |
is_active |
BOOLEAN |
NO |
TRUE |
— |
Active flag |
effective_date |
DATE |
YES |
— |
— |
Optional override |
expiry_date |
DATE |
YES |
— |
≥ effective_date |
Optional override |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
Creator |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Updated timestamp |
updated_by |
BIGINT |
YES |
— |
FK → users.user_id |
Last updater |
SQL DDL
SQLCREATE TABLE fee_schedule_items (
item_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
fee_schedule_id BIGINT NOT NULL,
cpt_code VARCHAR(10) NOT NULL,
description TEXT,
modifier VARCHAR(10),
rate_type VARCHAR(30) NOT NULL DEFAULT 'standard',
facility_rate NUMERIC(14,2),
professional_rate NUMERIC(14,2),
unit_limit INT,
is_bundled BOOLEAN NOT NULL DEFAULT FALSE,
bundle_parent_cpt VARCHAR(10),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
effective_date DATE,
expiry_date DATE,
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 chk_fee_items_rate_type
CHECK (rate_type IN ('standard','discounted','premium','penalty')),
CONSTRAINT chk_fee_items_rates_non_negative
CHECK (
(facility_rate IS NULL OR facility_rate >= 0) AND
(professional_rate IS NULL OR professional_rate >= 0)
),
CONSTRAINT chk_fee_items_unit_limit
CHECK (unit_limit IS NULL OR unit_limit >= 0),
CONSTRAINT chk_fee_items_dates
CHECK (expiry_date IS NULL OR effective_date IS NULL OR expiry_date >= effective_date)
);
COMMENT ON TABLE fee_schedule_items IS 'CPT-to-rate mappings per contract fee schedule.';
ALTER TABLE fee_schedule_items
ADD CONSTRAINT fk_fee_items_schedule
FOREIGN KEY (fee_schedule_id) REFERENCES contract_fee_schedules(fee_schedule_id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT fk_fee_items_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_fee_items_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE;
CREATE INDEX idx_fee_items_schedule ON fee_schedule_items (fee_schedule_id);
CREATE INDEX idx_fee_items_cpt ON fee_schedule_items (cpt_code, modifier);
CREATE INDEX idx_fee_items_active ON fee_schedule_items (fee_schedule_id, cpt_code)
WHERE is_active = TRUE;
Terminology Bindings
| Field |
Terminology |
Example Value |
cpt_code |
CPT |
99213 |
modifier |
CPT Modifiers |
26 |
FHIR Mapping
Fee schedule items map to ChargeItemDefinition.propertyGroup.priceComponent.
| Table Field |
FHIR Resource |
FHIR Path |
cpt_code |
ChargeItemDefinition |
code.coding[system='http://www.ama-assn.org/go/cpt'] |
facility_rate |
ChargeItemDefinition |
propertyGroup.priceComponent.amount (type = base) |
professional_rate |
ChargeItemDefinition |
propertyGroup.priceComponent.amount (type = surcharge) |
modifier |
ChargeItemDefinition |
applicability.condition or extension |
6. coverage_rules
Purpose: Encodes payer/plan-specific coverage and medical necessity rules (age/gender limits, frequency limits, etc.) used by eligibility, estimation, and claims adjudication.
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
rule_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
payer_id |
BIGINT |
NO |
— |
FK → payers.payer_id |
Payer |
plan_id |
BIGINT |
YES |
— |
FK → insurance_plans.plan_id |
Optional plan-specific |
rule_type |
VARCHAR(30) |
NO |
— |
CHECK in ('medical_necessity','benefit_limit','frequency_limit','exclusion','other') |
Rule category |
cpt_codes |
TEXT |
YES |
— |
JSON or comma-separated list |
CPT codes in scope |
icd10_codes |
TEXT |
YES |
— |
JSON or comma-separated list |
ICD-10-AM diagnoses in scope |
age_min |
INT |
YES |
— |
≥ 0 |
Minimum age in years |
age_max |
INT |
YES |
— |
≥ age_min |
Maximum age |
gender |
VARCHAR(10) |
YES |
— |
CHECK in ('male','female','other','any') |
Applicable gender |
frequency_limit |
INT |
YES |
— |
≥ 0 |
Max occurrences |
frequency_period |
VARCHAR(20) |
YES |
— |
CHECK in ('per_day','per_week','per_month','per_year','lifetime') |
Period for frequency |
requires_prior_auth |
BOOLEAN |
NO |
FALSE |
— |
Prior auth requirement |
benefit_limit_amount |
NUMERIC(14,2) |
YES |
— |
≥ 0 |
Monetary limit (AED) |
benefit_limit_units |
INT |
YES |
— |
≥ 0 |
Units/visits limit |
effective_date |
DATE |
NO |
— |
— |
Start date |
expiry_date |
DATE |
YES |
— |
≥ effective_date |
End date |
is_active |
BOOLEAN |
NO |
TRUE |
— |
Active flag |
rule_expression |
TEXT |
YES |
— |
— |
Expression (DSL/JSON) for engine |
notes |
TEXT |
YES |
— |
— |
Notes |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
Creator |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Updated timestamp |
updated_by |
BIGINT |
YES |
— |
FK → users.user_id |
Last updater |
SQL DDL
SQLCREATE TABLE coverage_rules (
rule_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
payer_id BIGINT NOT NULL,
plan_id BIGINT,
rule_type VARCHAR(30) NOT NULL,
cpt_codes TEXT,
icd10_codes TEXT,
age_min INT,
age_max INT,
gender VARCHAR(10),
frequency_limit INT,
frequency_period VARCHAR(20),
requires_prior_auth BOOLEAN NOT NULL DEFAULT FALSE,
benefit_limit_amount NUMERIC(14,2),
benefit_limit_units INT,
effective_date DATE NOT NULL,
expiry_date DATE,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
rule_expression TEXT,
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 chk_coverage_rules_type
CHECK (rule_type IN ('medical_necessity','benefit_limit','frequency_limit','exclusion','other')),
CONSTRAINT chk_coverage_rules_age
CHECK (
(age_min IS NULL OR age_min >= 0) AND
(age_max IS NULL OR (age_max >= 0 AND (age_min IS NULL OR age_max >= age_min)))
),
CONSTRAINT chk_coverage_rules_gender
CHECK (gender IS NULL OR gender IN ('male','female','other','any')),
CONSTRAINT chk_coverage_rules_frequency
CHECK (
(frequency_limit IS NULL OR frequency_limit >= 0) AND
(frequency_period IS NULL OR frequency_period IN ('per_day','per_week','per_month','per_year','lifetime'))
),
CONSTRAINT chk_coverage_rules_limits
CHECK (
(benefit_limit_amount IS NULL OR benefit_limit_amount >= 0) AND
(benefit_limit_units IS NULL OR benefit_limit_units >= 0)
),
CONSTRAINT chk_coverage_rules_dates
CHECK (expiry_date IS NULL OR expiry_date >= effective_date)
);
COMMENT ON TABLE coverage_rules IS 'Payer/plan-specific coverage and medical necessity rules for CPT/ICD-10-AM combinations.';
ALTER TABLE coverage_rules
ADD CONSTRAINT fk_coverage_rules_payer
FOREIGN KEY (payer_id) REFERENCES payers(payer_id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT fk_coverage_rules_plan
FOREIGN KEY (plan_id) REFERENCES insurance_plans(plan_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_coverage_rules_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_coverage_rules_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE;
CREATE INDEX idx_coverage_rules_payer_plan ON coverage_rules (payer_id, plan_id);
CREATE INDEX idx_coverage_rules_active ON coverage_rules (is_active, effective_date, expiry_date);
CREATE INDEX idx_coverage_rules_type ON coverage_rules (rule_type);
Terminology Bindings
| Field |
Terminology |
Example Value |
cpt_codes |
CPT |
["70450","71250"] |
icd10_codes |
ICD-10-AM |
["E11.9","I10"] |
gender |
AdministrativeGender |
female |
FHIR Mapping
Coverage rules can be represented using CoverageEligibilityRequest/CoverageEligibilityResponse and PlanDefinition/Library for decision logic.
| Table Field |
FHIR Resource |
FHIR Path |
payer_id |
CoverageEligibilityRequest |
insurance.coverage.payor |
plan_id |
Coverage |
Coverage.class (plan) |
cpt_codes |
PlanDefinition |
action.code |
icd10_codes |
PlanDefinition |
action.condition.expression |
age_min/age_max |
PlanDefinition |
action.condition.expression |
requires_prior_auth |
CoverageEligibilityResponse |
item.authorizationRequired (extension) |
7. prior_auth_rules
Purpose: Defines prior authorization requirements per payer/plan and service category, including method, turnaround time, and documentation requirements.
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
rule_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
payer_id |
BIGINT |
NO |
— |
FK → payers.payer_id |
Payer |
plan_id |
BIGINT |
YES |
— |
FK → insurance_plans.plan_id |
Optional plan-specific |
service_category |
VARCHAR(50) |
NO |
— |
FK → service_categories.code (ref/master) |
Category (e.g. imaging, surgery) |
cpt_code_range |
VARCHAR(50) |
YES |
— |
— |
Range/pattern (e.g. 70000-79999) |
cpt_codes |
TEXT |
YES |
— |
— |
Explicit CPT list if not range |
auth_required |
BOOLEAN |
NO |
TRUE |
— |
Whether auth is required |
auth_method |
VARCHAR(30) |
YES |
— |
CHECK in ('portal','phone','fax','email','auto-approve') |
Method |
turnaround_days |
INT |
YES |
— |
≥ 0 |
Expected response time |
valid_duration_days |
INT |
YES |
— |
≥ 0 |
Validity period of approval |
documentation_required |
TEXT |
YES |
— |
— |
Required docs (clinical notes, imaging, etc.) |
requires_clinical_criteria |
BOOLEAN |
NO |
FALSE |
— |
Needs clinical criteria check |
effective_date |
DATE |
NO |
— |
— |
Start date |
expiry_date |
DATE |
YES |
— |
≥ effective_date |
End date |
is_active |
BOOLEAN |
NO |
TRUE |
— |
Active flag |
notes |
TEXT |
YES |
— |
— |
Notes |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
Creator |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Updated timestamp |
updated_by |
BIGINT |
YES |
— |
FK → users.user_id |
Last updater |
SQL DDL
SQLCREATE TABLE prior_auth_rules (
rule_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
payer_id BIGINT NOT NULL,
plan_id BIGINT,
service_category VARCHAR(50) NOT NULL,
cpt_code_range VARCHAR(50),
cpt_codes TEXT,
auth_required BOOLEAN NOT NULL DEFAULT TRUE,
auth_method VARCHAR(30),
turnaround_days INT,
valid_duration_days INT,
documentation_required TEXT,
requires_clinical_criteria BOOLEAN NOT NULL DEFAULT FALSE,
effective_date DATE NOT NULL,
expiry_date DATE,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
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 chk_prior_auth_method
CHECK (auth_method IS NULL OR auth_method IN ('portal','phone','fax','email','auto-approve')),
CONSTRAINT chk_prior_auth_turnaround
CHECK (turnaround_days IS NULL OR turnaround_days >= 0),
CONSTRAINT chk_prior_auth_valid_duration
CHECK (valid_duration_days IS NULL OR valid_duration_days >= 0),
CONSTRAINT chk_prior_auth_dates
CHECK (expiry_date IS NULL OR expiry_date >= effective_date)
);
COMMENT ON TABLE prior_auth_rules IS 'Prior authorization requirements per payer/plan and service category.';
ALTER TABLE prior_auth_rules
ADD CONSTRAINT fk_prior_auth_payer
FOREIGN KEY (payer_id) REFERENCES payers(payer_id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT fk_prior_auth_plan
FOREIGN KEY (plan_id) REFERENCES insurance_plans(plan_id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_prior_auth_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_prior_auth_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE;
CREATE INDEX idx_prior_auth_payer_plan ON prior_auth_rules (payer_id, plan_id);
CREATE INDEX idx_prior_auth_service_cat ON prior_auth_rules (service_category);
CREATE INDEX idx_prior_auth_active ON prior_auth_rules (is_active, effective_date, expiry_date);
Terminology Bindings
| Field |
Terminology |
Example Value |
service_category |
DHA/DOH service categories |
Radiology |
cpt_code_range / cpt_codes |
CPT |
70000-79999 |
FHIR Mapping
Prior auth rules influence PriorAuthorization workflows, represented via CoverageEligibilityRequest and ServiceRequest guidance.
| Table Field |
FHIR Resource |
FHIR Path |
service_category |
ServiceRequest |
ServiceRequest.category |
auth_required |
CoverageEligibilityResponse |
item.authorizationRequired (extension) |
auth_method |
CoverageEligibilityResponse |
item.authorizationSupporting (CodeableConcept) |
turnaround_days |
CoverageEligibilityResponse |
item.authorizationValidityPeriod.start (derived) |
Purpose: Stores key contact persons at each payer organization (contracting, claims, IT, etc.).
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
contact_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
payer_id |
BIGINT |
NO |
— |
FK → payers.payer_id |
Payer |
contact_name |
VARCHAR(255) |
NO |
— |
— |
Full name |
role |
VARCHAR(100) |
NO |
— |
— |
Role (e.g. Contract Manager) |
email |
VARCHAR(255) |
YES |
— |
— |
Email |
phone |
VARCHAR(50) |
YES |
— |
— |
Phone |
department |
VARCHAR(100) |
YES |
— |
— |
Department (e.g. Claims) |
is_primary |
BOOLEAN |
NO |
FALSE |
— |
Primary contact flag |
notes |
TEXT |
YES |
— |
— |
Notes |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
Creator |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Updated timestamp |
updated_by |
BIGINT |
YES |
— |
FK → users.user_id |
Last updater |
SQL DDL
SQLCREATE TABLE payer_contacts (
contact_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
payer_id BIGINT NOT NULL,
contact_name VARCHAR(255) NOT NULL,
role VARCHAR(100) NOT NULL,
email VARCHAR(255),
phone VARCHAR(50),
department VARCHAR(100),
is_primary 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 chk_payer_contacts_email_phone
CHECK (email IS NOT NULL OR phone IS NOT NULL)
);
COMMENT ON TABLE payer_contacts IS 'Key contacts at payer organizations (contracting, claims, IT, etc.).';
ALTER TABLE payer_contacts
ADD CONSTRAINT fk_payer_contacts_payer
FOREIGN KEY (payer_id) REFERENCES payers(payer_id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT fk_payer_contacts_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_payer_contacts_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE;
CREATE INDEX idx_payer_contacts_payer ON payer_contacts (payer_id);
CREATE INDEX idx_payer_contacts_primary ON payer_contacts (payer_id, is_primary);
Terminology Bindings
Internal only (no external terminology).
FHIR Mapping
Maps to Organization.contact.
| Table Field |
FHIR Resource |
FHIR Path |
payer_id |
Organization |
Organization.id |
contact_name |
Organization |
Organization.contact.name.text |
role |
Organization |
Organization.contact.purpose |
email/phone |
Organization |
Organization.contact.telecom |
9. contract_amendments
Purpose: Tracks amendments to active contracts (rate changes, scope changes, term changes) with full audit trail.
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
amendment_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
contract_id |
BIGINT |
NO |
— |
FK → contracts.contract_id |
Amended contract |
amendment_type |
VARCHAR(50) |
NO |
— |
CHECK in ('rate_change','scope_change','term_change','other') |
Type |
description |
TEXT |
YES |
— |
— |
Description |
effective_date |
DATE |
NO |
— |
— |
Amendment effective date |
old_value |
TEXT |
YES |
— |
— |
Serialized previous value (JSON/text) |
new_value |
TEXT |
YES |
— |
— |
Serialized new value |
approved_by |
BIGINT |
YES |
— |
FK → users.user_id |
Approver |
approved_date |
TIMESTAMP |
YES |
— |
— |
Approval timestamp |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
Creator |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Updated timestamp |
updated_by |
BIGINT |
YES |
— |
FK → users.user_id |
Last updater |
SQL DDL
SQLCREATE TABLE contract_amendments (
amendment_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
contract_id BIGINT NOT NULL,
amendment_type VARCHAR(50) NOT NULL,
description TEXT,
effective_date DATE NOT NULL,
old_value TEXT,
new_value TEXT,
approved_by BIGINT,
approved_date 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 chk_contract_amendments_type
CHECK (amendment_type IN ('rate_change','scope_change','term_change','other'))
);
COMMENT ON TABLE contract_amendments IS 'Amendments to contracts with old/new values for audit and PDPL accountability.';
ALTER TABLE contract_amendments
ADD CONSTRAINT fk_contract_amendments_contract
FOREIGN KEY (contract_id) REFERENCES contracts(contract_id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT fk_contract_amendments_approved_by
FOREIGN KEY (approved_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_contract_amendments_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_contract_amendments_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE;
CREATE INDEX idx_contract_amendments_contract ON contract_amendments (contract_id);
CREATE INDEX idx_contract_amendments_effective ON contract_amendments (effective_date);
Terminology Bindings
Internal only.
FHIR Mapping
Can be represented as Contract revisions or Provenance/AuditEvent.
| Table Field |
FHIR Resource |
FHIR Path |
amendment_id |
Contract |
Contract.identifier (amendment) |
contract_id |
Contract |
Contract.related (previous) |
amendment_type |
Contract |
Contract.subType |
old_value/new_value |
Provenance |
Provenance.entity (before/after) |
10. payer_networks
Purpose: Represents network participation status per payer and facility, including network tier and rate modifiers for in-/out-of-network scenarios.
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
network_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
payer_id |
BIGINT |
NO |
— |
FK → payers.payer_id |
Payer |
facility_id |
BIGINT |
NO |
— |
FK → facilities.facility_id |
Facility |
network_tier |
VARCHAR(30) |
NO |
— |
FK → network_tiers.code (ref/master) |
Tier (Tier 1, Tier 2, OON) |
effective_date |
DATE |
NO |
— |
— |
Start date |
expiry_date |
DATE |
YES |
— |
≥ effective_date |
End date |
in_network_rate_modifier |
NUMERIC(6,3) |
YES |
— |
≥ 0 |
Multiplier for in-network rates (e.g. 1.0) |
out_of_network_rate_modifier |
NUMERIC(6,3) |
YES |
— |
≥ 0 |
Multiplier for OON rates |
status |
VARCHAR(30) |
NO |
'active' |
CHECK in ('active','inactive','pending') |
Status |
notes |
TEXT |
YES |
— |
— |
Notes |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
created_by |
BIGINT |
NO |
— |
FK → users.user_id |
Creator |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Updated timestamp |
updated_by |
BIGINT |
YES |
— |
FK → users.user_id |
Last updater |
SQL DDL
SQLCREATE TABLE payer_networks (
network_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
payer_id BIGINT NOT NULL,
facility_id BIGINT NOT NULL,
network_tier VARCHAR(30) NOT NULL,
effective_date DATE NOT NULL,
expiry_date DATE,
in_network_rate_modifier NUMERIC(6,3),
out_of_network_rate_modifier NUMERIC(6,3),
status VARCHAR(30) NOT NULL DEFAULT 'active',
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_payer_networks UNIQUE (payer_id, facility_id, network_tier, effective_date),
CONSTRAINT chk_payer_networks_modifiers
CHECK (
(in_network_rate_modifier IS NULL OR in_network_rate_modifier >= 0) AND
(out_of_network_rate_modifier IS NULL OR out_of_network_rate_modifier >= 0)
),
CONSTRAINT chk_payer_networks_status
CHECK (status IN ('active','inactive','pending')),
CONSTRAINT chk_payer_networks_dates
CHECK (expiry_date IS NULL OR expiry_date >= effective_date)
);
COMMENT ON TABLE payer_networks IS 'Network participation and tier per payer/facility with rate modifiers.';
ALTER TABLE payer_networks
ADD CONSTRAINT fk_payer_networks_payer
FOREIGN KEY (payer_id) REFERENCES payers(payer_id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT fk_payer_networks_facility
FOREIGN KEY (facility_id) REFERENCES facilities(facility_id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT fk_payer_networks_created_by
FOREIGN KEY (created_by) REFERENCES users(user_id) ON UPDATE CASCADE,
ADD CONSTRAINT fk_payer_networks_updated_by
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON UPDATE CASCADE;
CREATE INDEX idx_payer_networks_payer_facility ON payer_networks (payer_id, facility_id);
CREATE INDEX idx_payer_networks_status ON payer_networks (status, effective_date, expiry_date);
Terminology Bindings
| Field |
Terminology |
Example Value |
network_tier |
Facility-defined network tiers |
Tier 1 |
FHIR Mapping
Network participation can be represented via OrganizationAffiliation.
| Table Field |
FHIR Resource |
FHIR Path |
payer_id |
OrganizationAffiliation |
OrganizationAffiliation.organization |
facility_id |
OrganizationAffiliation |
OrganizationAffiliation.participatingOrganization |
network_tier |
OrganizationAffiliation |
OrganizationAffiliation.code |
effective_date/expiry_date |
OrganizationAffiliation |
OrganizationAffiliation.period |
11. reimbursement_rates
Purpose: Aggregated metrics comparing expected vs actual reimbursement per payer/contract/CPT over a period, used for performance monitoring and underpayment detection.
Field Specification
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
rate_id |
BIGINT |
NO |
IDENTITY |
PK |
Surrogate key |
payer_id |
BIGINT |
NO |
— |
FK → payers.payer_id |
Payer |
contract_id |
BIGINT |
YES |
— |
FK → contracts.contract_id |
Contract (if known) |
cpt_code |
VARCHAR(10) |
NO |
— |
— |
CPT code |
modifier |
VARCHAR(10) |
YES |
— |
— |
CPT modifier |
expected_rate |
NUMERIC(14,2) |
YES |
— |
≥ 0 |
Expected rate (AED) |
actual_avg_rate |
NUMERIC(14,2) |
YES |
— |
≥ 0 |
Actual average paid (AED) |
variance_pct |
NUMERIC(7,2) |
YES |
— |
— |
(actual/expected)*100 |
period_start |
DATE |
NO |
— |
— |
Start of aggregation period |
period_end |
DATE |
NO |
— |
≥ period_start |
End of period |
claim_count |
INT |
NO |
0 |
≥ 0 |
Number of claims in period |
total_expected_amount |
NUMERIC(16,2) |
YES |
— |
≥ 0 |
Sum expected (AED) |
total_paid_amount |
NUMERIC(16,2) |
YES |
— |
≥ 0 |
Sum paid (AED) |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Created timestamp |
SQL DDL
SQLCREATE TABLE reimbursement_rates (
rate_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
payer_id BIGINT NOT NULL,
contract_id BIGINT,
cpt_code VARCHAR(10) NOT NULL,
modifier VARCHAR(10),
expected_rate NUMERIC(14,2),
actual_avg_rate NUMERIC(14,2),
variance_pct NUMERIC(7,2),
period_start DATE NOT NULL,
period_end DATE NOT NULL,
claim_count INT NOT NULL DEFAULT 0,
total_expected_amount NUMERIC(16,2),
total_paid_amount NUMERIC(16,2),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT chk_reimb_rates_amounts
CHECK (
(expected_rate IS NULL OR expected_rate >= 0) AND
(actual_avg_rate IS NULL OR actual_avg_rate >= 0) AND
(total_expected_amount IS NULL OR total_expected_amount >= 0) AND
(total_paid_amount IS NULL OR total_paid_amount >= 0) AND
(claim_count >= 0)
),
CONSTRAINT chk_reimb_rates_dates
CHECK (period_end >= period_start)
);
COMMENT ON TABLE reimbursement_rates IS 'Aggregated expected vs actual reimbursement metrics per payer/contract/CPT and period.';
ALTER TABLE reimbursement_rates
ADD CONSTRAINT fk_reimb_rates_payer
FOREIGN KEY (payer_id) REFERENCES payers(payer_id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT fk_reimb_rates_contract
FOREIGN KEY (contract_id) REFERENCES contracts(contract_id) ON UPDATE CASCADE ON DELETE SET NULL;
CREATE INDEX idx_reimb_rates_payer_period ON reimbursement_rates (payer_id, period_start, period_end);
CREATE INDEX idx_reimb_rates_contract_period ON reimbursement_rates (contract_id, period_start, period_end);
CREATE INDEX idx_reimb_rates_cpt_period ON reimbursement_rates (cpt_code, period_start, period_end);
Terminology Bindings
| Field |
Terminology |
Example Value |
cpt_code |
CPT |
99214 |
FHIR Mapping
Used for analytics; can be represented as MeasureReport or Observation.
| Table Field |
FHIR Resource |
FHIR Path |
payer_id |
MeasureReport |
MeasureReport.subject (Organization) |
period_start/period_end |
MeasureReport |
MeasureReport.period |
variance_pct |
Observation |
Observation.valueQuantity (code = %) |
Data Volume Estimates
Approximate volumes for a medium-to-large UAE hospital group:
| Table |
Initial Rows |
Annual Growth |
Notes |
payers |
150–250 |
+10–20 |
Payers/TPAs in UAE + international |
insurance_plans |
800–1,500 |
+100–200 |
Multiple plans per payer |
contracts |
300–600 |
+100–150 |
Includes renewals/versions |
contract_fee_schedules |
400–800 |
+150–250 |
Per contract and tariff cycle |
fee_schedule_items |
150,000–250,000 |
+20,000–40,000 |
CPT × payer combinations |
coverage_rules |
10,000–30,000 |
+5,000–10,000 |
Per payer/plan/service |
prior_auth_rules |
5,000–15,000 |
+3,000–5,000 |
High-cost services |
payer_contacts |
1,000–2,000 |
+200–300 |
Multiple contacts per payer |
contract_amendments |
1,000–3,000 |
+500–1,000 |
Depends on renegotiation frequency |
payer_networks |
1,000–3,000 |
+300–500 |
Payer × facility × tier |
reimbursement_rates |
50,000–150,000 |
+50,000–100,000 |
Aggregated monthly/quarterly |
These estimates should be used for indexing and storage planning (e.g. partitioning reimbursement_rates by year).
Data Retention Policy (UAE Context)
Retention must comply with UAE MOH, DOH, DHA requirements and UAE PDPL (data minimisation, purpose limitation). Contract and financial records typically require long-term retention (often 10+ years); confirm with local legal counsel.
Proposed minimums:
| Table |
Recommended Retention |
Rationale |
payers |
Indefinite (logical inactivation only) |
Master data; referenced by historical claims and contracts |
insurance_plans |
Indefinite (logical inactivation) |
Needed to interpret historical coverage and claims |
contracts |
At least 15 years after expiry/termination |
Contractual and financial audit, dispute resolution; aligns with long limitation periods in UAE commercial law |
contract_fee_schedules |
At least 15 years after linked contract expiry |
Required to reconstruct expected reimbursement for historical claims |
fee_schedule_items |
At least 15 years after linked schedule expiry |
Same as above; supports audits and payer disputes |
coverage_rules |
At least 10 years after rule expiry |
Needed to justify historical denial/approval decisions |
prior_auth_rules |
At least 10 years after rule expiry |
Supports clinical and financial audits of prior auth decisions |
payer_contacts |
5 years after payer relationship ends, then anonymise personal identifiers |
Contains personal data; PDPL requires no longer than necessary; keep minimal audit trail |
contract_amendments |
At least 15 years after contract expiry |
Legal evidence of changes to terms and rates |
payer_networks |
At least 10 years after status inactive |
Needed to explain in-/out-of-network billing decisions |
reimbursement_rates |
10 years |
Aggregated analytics; may be archived or summarised after 10 years |
Implementation notes:
- Use
is_active and date fields for logical deletion; avoid physical deletion of records referenced by financial/clinical data.
- For PDPL compliance, where personal data exists (e.g.
payer_contacts.email, phone), implement:
- Data minimisation (store only necessary contact details).
- Pseudonymisation/anonymisation when retention period for personal data expires but aggregate records must remain.
- Maintain immutable audit logs (e.g. via
contract_amendments, created_at/updated_at) to support DOH/DHA audits and payer disputes.