Physician Portal & Mobile App Data Specifications
Shared Entity References
This module references the following shared entities defined in their owning modules. It 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, patient_demographics, patient_identifiers |
patients.patient_id |
| Providers |
ehr-patient-mgmt |
providers, provider_credentials |
providers.provider_id |
| Users & Auth |
ehr-patient-mgmt |
users, roles, permissions |
users.user_id |
| Encounters |
scheduling |
encounters, encounter_details |
encounters.encounter_id |
| Appointments |
scheduling |
appointments |
appointments.appointment_id |
| Facilities |
ehr-patient-mgmt |
facilities, departments, locations |
facilities.facility_id |
| Departments |
ehr-patient-mgmt |
departments |
departments.department_id |
| Allergies |
ehr-patient-mgmt |
patient_allergies |
patient_allergies.allergy_id |
| Problems |
ehr-patient-mgmt |
patient_problems |
patient_problems.problem_id |
| Clinical Notes |
ehr-patient-mgmt |
clinical_notes |
clinical_notes.note_id |
| Lab Results |
lis |
lab_results |
lab_results.result_id |
| Radiology |
ris |
radiology_reports |
radiology_reports.report_id |
| Pharmacy |
pis |
pharmacy_orders |
pharmacy_orders.order_id |
| Patient Portal Messages |
patient-portal |
portal_messages |
portal_messages.message_id |
Entity Relationship Diagram
erDiagram
providers ||--o{ physician_portal_accounts : "has"
users ||--o{ physician_portal_accounts : "linked to"
physician_portal_accounts ||--o{ physician_portal_sessions : "creates"
physician_portal_accounts ||--o{ physician_preferences : "has"
providers ||--o{ physician_favorites : "owns"
providers ||--o{ clinical_task_lists : "owns"
clinical_task_lists ||--o{ clinical_task_items : "contains"
patients ||--o{ clinical_task_items : "for"
patients ||--o{ handoff_communications : "for"
encounters ||--o{ handoff_communications : "during"
providers ||--o{ handoff_communications : "outgoing"
providers ||--o{ handoff_communications : "incoming"
providers ||--o{ physician_inbox_items : "receives"
patients ||--o{ physician_inbox_items : "about"
lab_results ||--o{ physician_inbox_items : "referenced by"
radiology_reports ||--o{ physician_inbox_items : "referenced by"
pharmacy_orders ||--o{ physician_inbox_items : "referenced by"
portal_messages ||--o{ physician_inbox_items : "referenced by"
clinical_notes ||--o{ physician_inbox_items : "referenced by"
physician_portal_accounts {
bigint account_id PK
bigint provider_id FK
bigint user_id FK
}
physician_portal_sessions {
bigint session_id PK
bigint account_id FK
}
physician_inbox_items {
bigint item_id PK
bigint provider_id FK
bigint patient_id FK
bigint ack_user_id FK
}
physician_preferences {
bigint preference_id PK
bigint account_id FK
}
physician_favorites {
bigint favorite_id PK
bigint provider_id FK
}
clinical_task_lists {
bigint list_id PK
bigint provider_id FK
bigint owning_department_id FK
}
clinical_task_items {
bigint task_item_id PK
bigint list_id FK
bigint patient_id FK
bigint encounter_id FK
bigint delegated_to FK
}
handoff_communications {
bigint handoff_id PK
bigint patient_id FK
bigint encounter_id FK
bigint outgoing_provider_id FK
bigint incoming_provider_id FK
}
Table Definitions
1. physician_portal_accounts
Purpose
Stores portal/mobile account records for physicians and clinical staff, linking provider identities to user accounts and capturing mobile-specific settings (MFA, device tokens, offline access). Supports UAE PDPL-compliant access control and auditability.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
account_id |
BIGINT |
NO |
IDENTITY |
PK |
Unique portal account ID |
provider_id |
BIGINT |
NO |
— |
FK → providers.provider_id |
Linked provider record |
user_id |
BIGINT |
NO |
— |
FK → users.user_id |
Linked authentication user |
activation_status |
VARCHAR(20) |
NO |
'pending' |
IN ('pending','active','suspended','revoked') |
Lifecycle status |
activation_datetime |
TIMESTAMP |
YES |
— |
— |
When account was activated |
deactivation_datetime |
TIMESTAMP |
YES |
— |
— |
When account was deactivated/suspended |
last_login |
TIMESTAMP |
YES |
— |
— |
Last successful login |
mfa_method |
VARCHAR(30) |
NO |
'biometric' |
IN ('biometric','otp_sms','otp_email','auth_app','none') |
Preferred MFA method (per PDPL/ADHICS) |
device_tokens |
JSONB |
YES |
— |
— |
Encrypted APNS/FCM tokens per device |
offline_access_enabled |
BOOLEAN |
NO |
FALSE |
— |
Allow offline caching of critical data |
is_active |
BOOLEAN |
NO |
TRUE |
— |
Soft-active flag (for quick disable) |
preferred_language |
VARCHAR(10) |
YES |
— |
e.g. ar, en, ar-AE |
UI language |
emirate_code |
VARCHAR(3) |
YES |
— |
IN ('DXB','AUH','SHJ','AJM','RAK','UAQ','Fuj') |
Primary practice emirate |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Record creation time |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Last update time |
SQL DDL
SQLCREATE TABLE physician_portal_accounts (
account_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
provider_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
activation_status VARCHAR(20) NOT NULL DEFAULT 'pending',
activation_datetime TIMESTAMP NULL,
deactivation_datetime TIMESTAMP NULL,
last_login TIMESTAMP NULL,
mfa_method VARCHAR(30) NOT NULL DEFAULT 'biometric',
device_tokens JSONB NULL,
offline_access_enabled BOOLEAN NOT NULL DEFAULT FALSE,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
preferred_language VARCHAR(10) NULL,
emirate_code VARCHAR(3) NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_phys_portal_accounts_provider UNIQUE (provider_id),
CONSTRAINT uq_phys_portal_accounts_user UNIQUE (user_id),
CONSTRAINT chk_phys_portal_activation_status
CHECK (activation_status IN ('pending','active','suspended','revoked')),
CONSTRAINT chk_phys_portal_mfa_method
CHECK (mfa_method IN ('biometric','otp_sms','otp_email','auth_app','none')),
CONSTRAINT chk_phys_portal_emirate_code
CHECK (emirate_code IS NULL OR emirate_code IN ('DXB','AUH','SHJ','AJM','RAK','UAQ','Fuj')),
CONSTRAINT fk_phys_portal_provider
FOREIGN KEY (provider_id) REFERENCES providers(provider_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
CONSTRAINT fk_phys_portal_user
FOREIGN KEY (user_id) REFERENCES users(user_id)
ON UPDATE CASCADE ON DELETE RESTRICT
);
CREATE INDEX idx_phys_portal_accounts_status
ON physician_portal_accounts (activation_status, is_active);
CREATE INDEX idx_phys_portal_accounts_last_login
ON physician_portal_accounts (last_login DESC);
CREATE INDEX idx_phys_portal_accounts_emirate
ON physician_portal_accounts (emirate_code);
Terminology Bindings
| Field |
Terminology |
Example Value |
emirate_code |
Local UAE Emirate Code Set |
DXB (Dubai), AUH (Abu Dhabi) |
preferred_language |
IETF BCP-47 |
ar-AE, en |
FHIR Resource Mapping
| Table Field |
FHIR Resource |
FHIR Path |
provider_id |
Practitioner |
Practitioner.id |
user_id |
PractitionerRole |
PractitionerRole.practitioner.reference |
activation_status |
PractitionerRole |
PractitionerRole.active (derived) |
emirate_code |
PractitionerRole |
PractitionerRole.location (Organization/Location in emirate) |
preferred_language |
Practitioner |
Practitioner.communication.language |
2. physician_portal_sessions
Purpose
Tracks web and mobile sessions for security auditing, usage analytics (e.g., Mobile MAU KPI), and anomaly detection in line with ADHICS/DHA security expectations.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
session_id |
BIGINT |
NO |
IDENTITY |
PK |
Unique session identifier |
account_id |
BIGINT |
NO |
— |
FK → physician_portal_accounts.account_id |
Owning portal account |
login_datetime |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Login time |
logout_datetime |
TIMESTAMP |
YES |
— |
≥ login_datetime |
Logout time |
device_type |
VARCHAR(20) |
NO |
— |
IN ('ios','android','web','tablet') |
Device category |
device_os |
VARCHAR(50) |
YES |
— |
— |
OS version (e.g. iOS 18.1) |
app_version |
VARCHAR(20) |
YES |
— |
— |
Mobile app version |
ip_address |
INET |
YES |
— |
— |
Source IP (per PDPL logging) |
auth_method |
VARCHAR(30) |
NO |
— |
IN ('password','biometric','sso','otp') |
Primary auth method |
is_mobile |
BOOLEAN |
NO |
FALSE |
— |
True for iOS/Android |
session_status |
VARCHAR(20) |
NO |
'active' |
IN ('active','terminated','expired') |
Current status |
push_token_hash |
VARCHAR(128) |
YES |
— |
— |
Hashed push token used in session |
last_activity_datetime |
TIMESTAMP |
YES |
— |
— |
Last API interaction time |
session_metadata |
JSONB |
YES |
— |
— |
Additional telemetry (locale, device model) |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Record creation time |
SQL DDL
SQLCREATE TABLE physician_portal_sessions (
session_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
account_id BIGINT NOT NULL,
login_datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
logout_datetime TIMESTAMP NULL,
device_type VARCHAR(20) NOT NULL,
device_os VARCHAR(50) NULL,
app_version VARCHAR(20) NULL,
ip_address INET NULL,
auth_method VARCHAR(30) NOT NULL,
is_mobile BOOLEAN NOT NULL DEFAULT FALSE,
session_status VARCHAR(20) NOT NULL DEFAULT 'active',
push_token_hash VARCHAR(128) NULL,
last_activity_datetime TIMESTAMP NULL,
session_metadata JSONB NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_phys_sessions_account
FOREIGN KEY (account_id) REFERENCES physician_portal_accounts(account_id)
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT chk_phys_sessions_device_type
CHECK (device_type IN ('ios','android','web','tablet')),
CONSTRAINT chk_phys_sessions_auth_method
CHECK (auth_method IN ('password','biometric','sso','otp')),
CONSTRAINT chk_phys_sessions_status
CHECK (session_status IN ('active','terminated','expired')),
CONSTRAINT chk_phys_sessions_logout_after_login
CHECK (logout_datetime IS NULL OR logout_datetime >= login_datetime)
);
CREATE INDEX idx_phys_sessions_account
ON physician_portal_sessions (account_id, login_datetime DESC);
CREATE INDEX idx_phys_sessions_mobile
ON physician_portal_sessions (is_mobile, login_datetime DESC);
CREATE INDEX idx_phys_sessions_status
ON physician_portal_sessions (session_status);
CREATE INDEX idx_phys_sessions_last_activity
ON physician_portal_sessions (last_activity_datetime);
Terminology Bindings
| Field |
Terminology |
Example Value |
device_type |
Local code set |
ios, android, web |
auth_method |
Local code set |
biometric |
FHIR Resource Mapping
Session data is not directly represented in core FHIR resources. For audit/export:
| Table Field |
FHIR Resource |
FHIR Path |
session_id |
AuditEvent |
AuditEvent.id |
account_id |
AuditEvent |
AuditEvent.agent.who (PractitionerRole) |
login_datetime |
AuditEvent |
AuditEvent.recorded (login event) |
ip_address |
AuditEvent |
AuditEvent.source.observer (extension for IP) |
device_type |
AuditEvent |
AuditEvent.agent.network.type |
3. physician_inbox_items
Purpose
Unified inbox items for each provider, aggregating patient messages, provider messages, system alerts, lab/radiology results, critical notifications, and task-related alerts. Drives KPIs like Critical Result Acknowledgment via Portal and Patient Message Response Time.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
item_id |
BIGINT |
NO |
IDENTITY |
PK |
Inbox item ID |
provider_id |
BIGINT |
NO |
— |
FK → providers.provider_id |
Recipient provider |
item_type |
VARCHAR(30) |
NO |
— |
IN ('patient_message','provider_message','lab_result','radiology_result','critical_result','system_alert','task') |
Type of inbox item |
source_module |
VARCHAR(30) |
NO |
— |
e.g. lis,ris,patient_portal,cpoe |
Originating module |
source_id |
BIGINT |
YES |
— |
— |
ID in source module (lab_results.result_id, etc.) |
patient_id |
BIGINT |
YES |
— |
FK → patients.patient_id |
Related patient (if any) |
subject |
VARCHAR(255) |
NO |
— |
— |
Short subject line |
preview_text |
TEXT |
YES |
— |
— |
Preview snippet |
priority |
VARCHAR(20) |
NO |
'normal' |
IN ('low','normal','high','critical') |
Display priority |
status |
VARCHAR(20) |
NO |
'unread' |
IN ('unread','read','actioned','archived') |
Inbox status |
received_datetime |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
When item created |
read_datetime |
TIMESTAMP |
YES |
— |
≥ received_datetime |
When first read |
actioned_datetime |
TIMESTAMP |
YES |
— |
≥ received_datetime |
When action completed |
action_taken |
VARCHAR(100) |
YES |
— |
e.g. acknowledged,replied,forwarded |
Summary of action |
is_critical |
BOOLEAN |
NO |
FALSE |
— |
Critical flag (e.g., critical lab) |
requires_ack |
BOOLEAN |
NO |
FALSE |
— |
Explicit acknowledgment required |
ack_datetime |
TIMESTAMP |
YES |
— |
≥ received_datetime |
When acknowledged |
ack_user_id |
BIGINT |
YES |
— |
FK → users.user_id |
User who acknowledged |
routing_metadata |
JSONB |
YES |
— |
— |
Delegation, CC list, escalation info |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Creation time |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Last update |
SQL DDL
SQLCREATE TABLE physician_inbox_items (
item_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
provider_id BIGINT NOT NULL,
item_type VARCHAR(30) NOT NULL,
source_module VARCHAR(30) NOT NULL,
source_id BIGINT NULL,
patient_id BIGINT NULL,
subject VARCHAR(255) NOT NULL,
preview_text TEXT NULL,
priority VARCHAR(20) NOT NULL DEFAULT 'normal',
status VARCHAR(20) NOT NULL DEFAULT 'unread',
received_datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
read_datetime TIMESTAMP NULL,
actioned_datetime TIMESTAMP NULL,
action_taken VARCHAR(100) NULL,
is_critical BOOLEAN NOT NULL DEFAULT FALSE,
requires_ack BOOLEAN NOT NULL DEFAULT FALSE,
ack_datetime TIMESTAMP NULL,
ack_user_id BIGINT NULL,
routing_metadata JSONB NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_inbox_provider
FOREIGN KEY (provider_id) REFERENCES providers(provider_id)
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT fk_inbox_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id)
ON UPDATE CASCADE ON DELETE SET NULL,
CONSTRAINT fk_inbox_ack_user
FOREIGN KEY (ack_user_id) REFERENCES users(user_id)
ON UPDATE CASCADE ON DELETE SET NULL,
CONSTRAINT chk_inbox_item_type
CHECK (item_type IN (
'patient_message','provider_message','lab_result',
'radiology_result','critical_result','system_alert','task'
)),
CONSTRAINT chk_inbox_priority
CHECK (priority IN ('low','normal','high','critical')),
CONSTRAINT chk_inbox_status
CHECK (status IN ('unread','read','actioned','archived')),
CONSTRAINT chk_inbox_read_after_received
CHECK (read_datetime IS NULL OR read_datetime >= received_datetime),
CONSTRAINT chk_inbox_action_after_received
CHECK (actioned_datetime IS NULL OR actioned_datetime >= received_datetime),
CONSTRAINT chk_inbox_ack_after_received
CHECK (ack_datetime IS NULL OR ack_datetime >= received_datetime),
CONSTRAINT chk_inbox_ack_required
CHECK (requires_ack = FALSE OR is_critical = TRUE)
);
CREATE INDEX idx_inbox_provider_status
ON physician_inbox_items (provider_id, status, priority DESC, received_datetime DESC);
CREATE INDEX idx_inbox_provider_type
ON physician_inbox_items (provider_id, item_type, received_datetime DESC);
CREATE INDEX idx_inbox_patient
ON physician_inbox_items (patient_id, received_datetime DESC);
CREATE INDEX idx_inbox_requires_ack
ON physician_inbox_items (requires_ack, is_critical, received_datetime);
Terminology Bindings
| Field |
Terminology |
Example Value |
item_type |
Local code set |
lab_result, patient_message |
priority |
HL7 v3 ObservationInterpretation (mapped) / local |
critical |
action_taken |
Local code set |
acknowledged, replied |
FHIR Resource Mapping
Depending on item_type, items map to different FHIR resources:
| Table Field |
FHIR Resource |
FHIR Path |
item_id |
Communication |
Communication.id |
provider_id |
Practitioner |
Communication.recipient |
patient_id |
Patient |
Communication.subject |
subject |
Communication |
Communication.payload.contentString (summary) |
preview_text |
Communication |
Communication.note.text |
received_datetime |
Communication |
Communication.sent / received |
is_critical |
Communication |
Communication.priority ('stat' if true) |
requires_ack/ack_datetime |
Task |
Task.status / Task.executionPeriod.end (for acknowledgment tasks) |
4. physician_preferences
Purpose
Stores per-account notification and display preferences, including quiet hours and mobile layout, to support configurable push notifications and personalized dashboards while complying with UAE PDPL consent and minimization principles.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
preference_id |
BIGINT |
NO |
IDENTITY |
PK |
Preference record ID |
account_id |
BIGINT |
NO |
— |
FK → physician_portal_accounts.account_id |
Owning account |
notification_critical_results |
BOOLEAN |
NO |
TRUE |
— |
Receive critical result alerts |
notification_new_messages |
BOOLEAN |
NO |
TRUE |
— |
Receive new message alerts |
notification_schedule_changes |
BOOLEAN |
NO |
TRUE |
— |
Receive schedule change alerts |
notification_abnormal_results |
BOOLEAN |
NO |
TRUE |
— |
Receive abnormal (non-critical) results |
notification_handoff |
BOOLEAN |
NO |
TRUE |
— |
Receive handoff notifications |
notification_task_updates |
BOOLEAN |
NO |
TRUE |
— |
Receive task assignment/updates |
display_theme |
VARCHAR(20) |
NO |
'light' |
IN ('light','dark','system') |
UI theme |
default_patient_list |
VARCHAR(50) |
YES |
— |
e.g. my_inpatients |
Default list key |
result_sort_preference |
VARCHAR(20) |
NO |
'abnormal_first' |
IN ('abnormal_first','chronological','by_type') |
Result sorting |
language |
VARCHAR(10) |
YES |
— |
BCP-47 |
Preferred language |
time_zone |
VARCHAR(40) |
YES |
'Asia/Dubai' |
— |
Time zone |
notification_quiet_hours |
JSONB |
YES |
— |
— |
Quiet hours config (start/end, days) |
mobile_layout_settings |
JSONB |
YES |
— |
— |
Per-screen layout preferences |
favorite_views |
JSONB |
YES |
— |
— |
Saved filters/views |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Creation time |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Last update |
SQL DDL
SQLCREATE TABLE physician_preferences (
preference_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
account_id BIGINT NOT NULL,
notification_critical_results BOOLEAN NOT NULL DEFAULT TRUE,
notification_new_messages BOOLEAN NOT NULL DEFAULT TRUE,
notification_schedule_changes BOOLEAN NOT NULL DEFAULT TRUE,
notification_abnormal_results BOOLEAN NOT NULL DEFAULT TRUE,
notification_handoff BOOLEAN NOT NULL DEFAULT TRUE,
notification_task_updates BOOLEAN NOT NULL DEFAULT TRUE,
display_theme VARCHAR(20) NOT NULL DEFAULT 'light',
default_patient_list VARCHAR(50) NULL,
result_sort_preference VARCHAR(20) NOT NULL DEFAULT 'abnormal_first',
language VARCHAR(10) NULL,
time_zone VARCHAR(40) NULL DEFAULT 'Asia/Dubai',
notification_quiet_hours JSONB NULL,
mobile_layout_settings JSONB NULL,
favorite_views JSONB NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_phys_prefs_account
FOREIGN KEY (account_id) REFERENCES physician_portal_accounts(account_id)
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT uq_phys_prefs_account UNIQUE (account_id),
CONSTRAINT chk_phys_prefs_theme
CHECK (display_theme IN ('light','dark','system')),
CONSTRAINT chk_phys_prefs_result_sort
CHECK (result_sort_preference IN ('abnormal_first','chronological','by_type'))
);
CREATE INDEX idx_phys_prefs_account
ON physician_preferences (account_id);
Terminology Bindings
| Field |
Terminology |
Example Value |
language |
IETF BCP-47 |
ar-AE, en |
time_zone |
IANA Time Zone |
Asia/Dubai |
FHIR Resource Mapping
Preferences are not first-class FHIR resources; they can be represented via extensions:
| Table Field |
FHIR Resource |
FHIR Path |
account_id |
Practitioner |
Practitioner.extension[notificationPreferences] |
language |
Practitioner |
Practitioner.communication.language |
notification_* |
Practitioner |
Extension on Practitioner/PractitionerRole |
5. physician_favorites
Purpose
Stores provider-specific favorites for quick access (patients, orders, order sets, note templates, etc.) to optimize mobile workflows (order entry, documentation).
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
favorite_id |
BIGINT |
NO |
IDENTITY |
PK |
Favorite record ID |
provider_id |
BIGINT |
NO |
— |
FK → providers.provider_id |
Owner provider |
favorite_type |
VARCHAR(30) |
NO |
— |
IN ('patient','order','order_set','note_template','diagnosis') |
Type of favorite |
item_id |
BIGINT |
YES |
— |
— |
ID in referenced table (context-dependent) |
item_name |
VARCHAR(255) |
NO |
— |
— |
Display name |
item_code |
VARCHAR(50) |
YES |
— |
— |
Code (e.g., LOINC, CPT, SNOMED) |
item_context |
VARCHAR(50) |
YES |
— |
e.g. lab_order,imaging_order |
Context for item_id |
display_order |
INT |
NO |
0 |
≥ 0 |
Ordering in UI |
is_active |
BOOLEAN |
NO |
TRUE |
— |
Soft delete flag |
created_datetime |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Creation time |
updated_datetime |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Last update |
SQL DDL
SQLCREATE TABLE physician_favorites (
favorite_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
provider_id BIGINT NOT NULL,
favorite_type VARCHAR(30) NOT NULL,
item_id BIGINT NULL,
item_name VARCHAR(255) NOT NULL,
item_code VARCHAR(50) NULL,
item_context VARCHAR(50) NULL,
display_order INT NOT NULL DEFAULT 0,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_phys_fav_provider
FOREIGN KEY (provider_id) REFERENCES providers(provider_id)
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT chk_phys_fav_type
CHECK (favorite_type IN ('patient','order','order_set','note_template','diagnosis')),
CONSTRAINT chk_phys_fav_display_order
CHECK (display_order >= 0)
);
CREATE INDEX idx_phys_fav_provider_type
ON physician_favorites (provider_id, favorite_type, is_active, display_order);
CREATE INDEX idx_phys_fav_item
ON physician_favorites (favorite_type, item_context, item_id);
Terminology Bindings
| Field |
Terminology |
Example Value |
item_code (lab order) |
LOINC |
718-7 (Hemoglobin) |
item_code (imaging) |
CPT |
71045 (Chest X-ray) |
item_code (diagnosis) |
ICD-10-AM |
E11.9 |
item_code (clinical concept) |
SNOMED CT |
44054006 (Diabetes mellitus type 2) |
FHIR Resource Mapping
| Table Field |
FHIR Resource |
FHIR Path |
favorite_id |
List |
List.id |
provider_id |
Practitioner |
List.source |
favorite_type |
List |
List.code (type of list) |
item_id/item_context |
Various |
List.entry.item.reference (e.g., ServiceRequest, Condition, Patient) |
display_order |
List |
List.entry.extension[order] |
6. clinical_task_lists
Purpose
Defines logical task lists for providers (e.g., “My Tasks”, “Ward 3A Tasks”), including shared lists at department level. Supports Clinical Task Management workflow and Task Completion Rate KPI.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
list_id |
BIGINT |
NO |
IDENTITY |
PK |
Task list ID |
provider_id |
BIGINT |
NO |
— |
FK → providers.provider_id |
Owner provider (for personal lists) |
list_name |
VARCHAR(100) |
NO |
— |
— |
Display name |
list_type |
VARCHAR(30) |
NO |
'personal' |
IN ('personal','shared_department','on_call') |
Type of list |
is_default |
BOOLEAN |
NO |
FALSE |
— |
Default list for provider |
is_shared |
BOOLEAN |
NO |
FALSE |
— |
Shared with team |
owning_department_id |
BIGINT |
YES |
— |
FK → departments.department_id |
Department for shared lists |
created_datetime |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Creation time |
updated_datetime |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Last update |
SQL DDL
SQLCREATE TABLE clinical_task_lists (
list_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
provider_id BIGINT NOT NULL,
list_name VARCHAR(100) NOT NULL,
list_type VARCHAR(30) NOT NULL DEFAULT 'personal',
is_default BOOLEAN NOT NULL DEFAULT FALSE,
is_shared BOOLEAN NOT NULL DEFAULT FALSE,
owning_department_id BIGINT NULL,
created_datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_task_lists_provider
FOREIGN KEY (provider_id) REFERENCES providers(provider_id)
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT fk_task_lists_department
FOREIGN KEY (owning_department_id) REFERENCES departments(department_id)
ON UPDATE CASCADE ON DELETE SET NULL,
CONSTRAINT chk_task_lists_type
CHECK (list_type IN ('personal','shared_department','on_call')),
CONSTRAINT chk_task_lists_default
CHECK (is_default = FALSE OR list_type = 'personal')
);
CREATE INDEX idx_task_lists_provider
ON clinical_task_lists (provider_id, list_type);
CREATE INDEX idx_task_lists_department
ON clinical_task_lists (owning_department_id);
Terminology Bindings
Local only (no external coding).
FHIR Resource Mapping
| Table Field |
FHIR Resource |
FHIR Path |
list_id |
Task (grouping) or List |
List.id |
list_name |
List |
List.title |
provider_id |
Practitioner |
List.source |
list_type |
List |
List.code (e.g., “on-call list”) |
7. clinical_task_items
Purpose
Stores individual clinical tasks (auto-generated or manual) associated with patients and providers, including delegation and escalation metadata. Drives Clinical Task Management workflow and Task Completion Rate KPI.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
task_item_id |
BIGINT |
NO |
IDENTITY |
PK |
Task ID |
list_id |
BIGINT |
NO |
— |
FK → clinical_task_lists.list_id |
Parent list |
patient_id |
BIGINT |
YES |
— |
FK → patients.patient_id |
Related patient |
encounter_id |
BIGINT |
YES |
— |
FK → encounters.encounter_id |
Encounter context |
task_description |
VARCHAR(500) |
NO |
— |
— |
Human-readable description |
task_type |
VARCHAR(50) |
NO |
— |
IN ('result_review','order_sign','follow_up','message_reply','manual') |
Task category |
source_module |
VARCHAR(30) |
YES |
— |
e.g. cpoe,lis,patient_portal |
Originating module |
source_id |
BIGINT |
YES |
— |
— |
ID in source module |
priority |
VARCHAR(20) |
NO |
'normal' |
IN ('low','normal','high','critical') |
Task priority |
due_datetime |
TIMESTAMP |
YES |
— |
— |
Due date/time |
status |
VARCHAR(20) |
NO |
'open' |
IN ('open','in_progress','completed','cancelled','overdue') |
Task status |
created_datetime |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Creation time |
completed_datetime |
TIMESTAMP |
YES |
— |
≥ created_datetime |
Completion time |
delegated_to |
BIGINT |
YES |
— |
FK → providers.provider_id |
Delegated provider |
notes |
TEXT |
YES |
— |
— |
Free-text notes |
escalation_flag |
BOOLEAN |
NO |
FALSE |
— |
Escalated due to overdue/critical |
escalated_datetime |
TIMESTAMP |
YES |
— |
— |
When escalated |
task_metadata |
JSONB |
YES |
— |
— |
Additional structured data |
SQL DDL
SQLCREATE TABLE clinical_task_items (
task_item_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
list_id BIGINT NOT NULL,
patient_id BIGINT NULL,
encounter_id BIGINT NULL,
task_description VARCHAR(500) NOT NULL,
task_type VARCHAR(50) NOT NULL,
source_module VARCHAR(30) NULL,
source_id BIGINT NULL,
priority VARCHAR(20) NOT NULL DEFAULT 'normal',
due_datetime TIMESTAMP NULL,
status VARCHAR(20) NOT NULL DEFAULT 'open',
created_datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
completed_datetime TIMESTAMP NULL,
delegated_to BIGINT NULL,
notes TEXT NULL,
escalation_flag BOOLEAN NOT NULL DEFAULT FALSE,
escalated_datetime TIMESTAMP NULL,
task_metadata JSONB NULL,
CONSTRAINT fk_tasks_list
FOREIGN KEY (list_id) REFERENCES clinical_task_lists(list_id)
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT fk_tasks_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id)
ON UPDATE CASCADE ON DELETE SET NULL,
CONSTRAINT fk_tasks_encounter
FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id)
ON UPDATE CASCADE ON DELETE SET NULL,
CONSTRAINT fk_tasks_delegated_to
FOREIGN KEY (delegated_to) REFERENCES providers(provider_id)
ON UPDATE CASCADE ON DELETE SET NULL,
CONSTRAINT chk_tasks_type
CHECK (task_type IN ('result_review','order_sign','follow_up','message_reply','manual')),
CONSTRAINT chk_tasks_priority
CHECK (priority IN ('low','normal','high','critical')),
CONSTRAINT chk_tasks_status
CHECK (status IN ('open','in_progress','completed','cancelled','overdue')),
CONSTRAINT chk_tasks_completed_after_created
CHECK (completed_datetime IS NULL OR completed_datetime >= created_datetime)
);
CREATE INDEX idx_tasks_list_status
ON clinical_task_items (list_id, status, priority DESC, due_datetime);
CREATE INDEX idx_tasks_patient
ON clinical_task_items (patient_id, status, due_datetime);
CREATE INDEX idx_tasks_delegated
ON clinical_task_items (delegated_to, status, priority DESC);
CREATE INDEX idx_tasks_source
ON clinical_task_items (source_module, source_id);
Terminology Bindings
| Field |
Terminology |
Example Value |
task_type |
Local code set |
result_review |
priority |
Local / mapped to FHIR Task.priority |
high |
FHIR Resource Mapping
| Table Field |
FHIR Resource |
FHIR Path |
task_item_id |
Task |
Task.id |
task_description |
Task |
Task.description |
patient_id |
Task |
Task.for (Patient reference) |
encounter_id |
Task |
Task.encounter |
priority |
Task |
Task.priority |
status |
Task |
Task.status (mapped from local) |
due_datetime |
Task |
Task.executionPeriod.end |
created_datetime |
Task |
Task.authoredOn |
completed_datetime |
Task |
Task.lastModified |
delegated_to |
Task |
Task.owner (Practitioner) |
8. handoff_communications
Purpose
Captures structured I-PASS handoff communications between outgoing and incoming physicians, including acknowledgment and critical item flags. Supports Clinical Handoff workflow and Handoff Completion Rate KPI, and provides medico-legal traceability per UAE regulations.
Field Specifications
| Field |
Type |
Nullable |
Default |
Constraint |
Description |
handoff_id |
BIGINT |
NO |
IDENTITY |
PK |
Handoff record ID |
patient_id |
BIGINT |
NO |
— |
FK → patients.patient_id |
Patient being handed off |
encounter_id |
BIGINT |
YES |
— |
FK → encounters.encounter_id |
Encounter context |
outgoing_provider_id |
BIGINT |
NO |
— |
FK → providers.provider_id |
Sending physician |
incoming_provider_id |
BIGINT |
NO |
— |
FK → providers.provider_id |
Receiving physician |
illness_severity |
VARCHAR(20) |
NO |
— |
IN ('stable','watcher','unstable') |
I-PASS severity |
patient_summary |
TEXT |
NO |
— |
— |
I-PASS “P” summary |
action_list |
TEXT |
NO |
— |
— |
I-PASS “A” action list |
situation_awareness |
TEXT |
YES |
— |
— |
I-PASS “S” situation awareness |
contingency_plan |
TEXT |
YES |
— |
— |
I-PASS “S” contingency plan |
handoff_datetime |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
When handoff sent |
acknowledged_datetime |
TIMESTAMP |
YES |
— |
≥ handoff_datetime |
When incoming acknowledged |
status |
VARCHAR(20) |
NO |
'pending' |
IN ('pending','acknowledged','superseded','cancelled') |
Handoff status |
includes_critical_items |
BOOLEAN |
NO |
FALSE |
— |
Contains critical issues |
handoff_metadata |
JSONB |
YES |
— |
— |
Additional structured data (e.g., I-PASS template ID) |
created_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Creation time |
updated_at |
TIMESTAMP |
NO |
CURRENT_TIMESTAMP |
— |
Last update |
SQL DDL
SQLCREATE TABLE handoff_communications (
handoff_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
patient_id BIGINT NOT NULL,
encounter_id BIGINT NULL,
outgoing_provider_id BIGINT NOT NULL,
incoming_provider_id BIGINT NOT NULL,
illness_severity VARCHAR(20) NOT NULL,
patient_summary TEXT NOT NULL,
action_list TEXT NOT NULL,
situation_awareness TEXT NULL,
contingency_plan TEXT NULL,
handoff_datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
acknowledged_datetime TIMESTAMP NULL,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
includes_critical_items BOOLEAN NOT NULL DEFAULT FALSE,
handoff_metadata JSONB NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_handoff_patient
FOREIGN KEY (patient_id) REFERENCES patients(patient_id)
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT fk_handoff_encounter
FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id)
ON UPDATE CASCADE ON DELETE SET NULL,
CONSTRAINT fk_handoff_outgoing_provider
FOREIGN KEY (outgoing_provider_id) REFERENCES providers(provider_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
CONSTRAINT fk_handoff_incoming_provider
FOREIGN KEY (incoming_provider_id) REFERENCES providers(provider_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
CONSTRAINT chk_handoff_illness_severity
CHECK (illness_severity IN ('stable','watcher','unstable')),
CONSTRAINT chk_handoff_status
CHECK (status IN ('pending','acknowledged','superseded','cancelled')),
CONSTRAINT chk_handoff_ack_after_handoff
CHECK (acknowledged_datetime IS NULL OR acknowledged_datetime >= handoff_datetime)
);
CREATE INDEX idx_handoff_patient
ON handoff_communications (patient_id, handoff_datetime DESC);
CREATE INDEX idx_handoff_incoming_status
ON handoff_communications (incoming_provider_id, status, handoff_datetime DESC);
CREATE INDEX idx_handoff_outgoing
ON handoff_communications (outgoing_provider_id, handoff_datetime DESC);
Terminology Bindings
| Field |
Terminology |
Example Value |
illness_severity |
I-PASS standard |
watcher |
status |
Local / mapped to FHIR Task.status |
acknowledged |
FHIR Resource Mapping
| Table Field |
FHIR Resource |
FHIR Path |
handoff_id |
Communication |
Communication.id |
patient_id |
Communication |
Communication.subject |
outgoing_provider_id |
Practitioner |
Communication.sender |
incoming_provider_id |
Practitioner |
Communication.recipient |
patient_summary |
Communication |
Communication.payload.contentString (summary) |
action_list |
Task |
Task.description (follow-up tasks) |
illness_severity |
Condition / Observation |
Extension or Observation.valueCodeableConcept |
Data Volume Estimates
Estimates are for a 300-bed UAE hospital with ~250 active physicians and mixed inpatient/outpatient services.
| Table |
Initial Rows (Go-Live) |
Annual Growth |
Notes |
physician_portal_accounts |
~300 |
+50/year |
One per provider/NP/PA; low churn |
physician_portal_sessions |
0 |
~1,000,000/year |
Assuming ~3,000 logins/day across web/mobile |
physician_inbox_items |
0 |
~2,000,000/year |
Results, messages, alerts; heavy use |
physician_preferences |
~300 |
+50/year |
One per account |
physician_favorites |
~15,000 |
+3,000/year |
~50 favorites per provider |
clinical_task_lists |
~400 |
+50/year |
Personal + shared lists |
clinical_task_items |
0 |
~3,000,000/year |
Auto + manual tasks |
handoff_communications |
0 |
~150,000/year |
Assuming ~400 handoffs/day across services |
Capacity planning should size storage and indices for at least 7–10 years of data, especially for high-volume tables (physician_portal_sessions, physician_inbox_items, clinical_task_items).
Data Retention Policy (UAE Context)
Retention must align with UAE MOH, DOH, DHA regulations and UAE PDPL (Federal Decree-Law No. 45/2021). Clinical records are typically retained for at least 25 years from last encounter; audit/security logs may have shorter but still substantial retention.
| Table |
Recommended Retention |
Rationale / Notes |
physician_portal_accounts |
Life of provider + 10 years after deactivation |
Needed for medico-legal traceability of access and actions. Deactivation rather than deletion; PDPL “storage limitation” satisfied via archival. |
physician_portal_sessions |
7–10 years |
Security/audit logs per ADHICS/DHA guidelines; older sessions can be aggregated/anonymized for analytics. |
physician_inbox_items |
Align with patient record: ≥25 years from last patient encounter or 10 years after provider leaves (whichever is later) |
Inbox items often represent part of clinical decision-making (e.g., critical result acknowledgment) and should be retained as part of the legal medical record. |
physician_preferences |
Until 2 years after account deactivation |
Purely preference data; can be deleted earlier per PDPL data minimization and data subject request. |
physician_favorites |
Until 2 years after provider deactivation |
Operational convenience only; can be purged earlier if requested. |
clinical_task_lists |
≥10 years |
Metadata for tasks; not strictly clinical content but supports reconstruction of workflow for incident review. |
clinical_task_items |
Align with patient record: ≥25 years from last related encounter |
Tasks often reference clinical actions (result review, follow-up) and may be needed in medico-legal cases. |
handoff_communications |
Align with patient record: ≥25 years from last encounter |
Handoff content is clinical documentation of responsibility transfer; treat as part of the medical record. |
Implementation Notes
- Use logical deletion/archival rather than physical deletion for clinical tables (
physician_inbox_items, clinical_task_items, handoff_communications) to preserve referential integrity with EHR modules.
- For high-volume audit tables (
physician_portal_sessions), implement:
- Partitioning by year/month.
- Archival to cheaper storage after 2–3 years, with online access to recent partitions.
- Support PDPL data subject rights:
- Preferences and favorites should be deletable or anonymizable on request without impacting clinical safety.
- Clinical content (handoffs, tasks, inbox items linked to care) may be exempt from deletion where required for patient safety and legal obligations; system should document this in consent/notice.