Kulcare Docs
DeveloperPatient

Offline Mode Schema Design

Status: Analysis & Design Phase Created: 2025-12-29 Purpose: Database schema additions to support offline-capable healthcare applications

Executive Summary

Many healthcare facilities, especially in India and GCC regions, operate in areas with unreliable internet connectivity. This document describes the database schema additions needed to support offline mode in the new architecture.

Key capabilities:

  • Clinical data can be created/modified while offline
  • Changes sync reliably when connectivity returns
  • Conflicts are detected and resolved appropriately
  • Complete audit trail is maintained for compliance

How Offline Sync Works

Important: PostgreSQL and Offline Mode

PostgreSQL is a server-side database and does not have native offline sync capabilities. Offline sync is an application-layer concern, not a database feature.

+---------------------+                      +---------------------+
|       CLIENT        |                      |       SERVER        |
+---------------------+                      +---------------------+
|                     |                      |                     |
|  IndexedDB          |<--- HTTP/API ------->|  PostgreSQL         |
|  (local database)   |    sync protocol     |  (source of truth)  |
|                     |                      |                     |
+---------------------+                      +---------------------+

What Each Layer Does

Client-Side (Browser/App):

  • IndexedDB stores data locally for offline access
  • Service Worker intercepts network requests
  • Background Sync API queues mutations when offline
  • Application logic handles conflict detection

Server-Side (PostgreSQL):

  • Remains the source of truth
  • The schema additions in this document track sync state
  • Handles conflict resolution when data syncs back
  • Maintains audit trail for compliance

What This Schema Provides

The tables documented here enable the server to:

  1. Track sync state - What was synced, when, from which device
  2. Detect conflicts - Using version columns and timestamps
  3. Resolve conflicts - Per-entity resolution strategies
  4. Audit offline activity - Complete trail for compliance
  5. Manage devices - Authorize and revoke offline access

Schema Additions Overview

SchemaNew EntityPurpose
auditOfflineSyncLogTrack all offline operations and sync status
auditOfflineDeviceAuthorized devices for offline access
auditSyncBatchGroup operations for atomic sync
clinicalOfflinePrescriptionReview workflow for offline prescriptions
clinicalOfflineEncounterTrack offline encounter modifications
identityFacilityOfflineSettingsPer-facility offline configuration

Total New Tables: 6


Audit Schema: Offline Sync Tracking

Entity: OfflineSyncLog

Purpose: Track all operations performed offline and their sync status

Attributes:

AttributeTypeRequiredDescription
idUUIDYesPrimary identifier
tenant_idUUIDYesTenant reference
facility_idUUIDYesFacility where operation occurred
user_idUUIDYesUser who performed operation
device_idStringYesUnique device identifier
device_nameStringNoDevice display name
operation_typeEnumYescreate, update, delete
resource_schemaStringYesSchema name (clinical, billing)
resource_typeStringYesTable/entity name
resource_idUUIDYesResource identifier
offline_idUUIDNoClient-generated temp ID (for creates)
payloadJSONBYesFull operation payload
client_timestampTimestampYesWhen created on client
received_atTimestampNoWhen received by server
processed_atTimestampNoWhen processed by server
sync_statusEnumYesqueued, received, processing, synced, conflict, failed
conflict_typeEnumNoversion_mismatch, deleted_resource, validation_error, business_rule
conflict_dataJSONBNoServer state at conflict time
resolution_strategyEnumNoclient_wins, server_wins, merged, manual
resolved_byUUIDNoUser who resolved conflict
resolved_atTimestampNoWhen conflict was resolved
error_messageTextNoError details if failed
retry_countIntegerNoNumber of sync attempts

Sync Status Values:

StatusDescription
queuedWaiting in client queue
receivedReceived by server, not yet processed
processingCurrently being processed
syncedSuccessfully synced
conflictConflict detected, needs resolution
failedPermanently failed (after retries)

Conflict Type Values:

TypeDescription
version_mismatchResource was modified by another user
deleted_resourceResource was deleted on server
validation_errorData fails server validation
business_ruleBusiness rule violation

Relationships:

  • Belongs to: Tenant, Facility, User
  • References: OfflineDevice (via device_id)

Entity: OfflineDevice

Purpose: Track authorized devices for offline access

Attributes:

AttributeTypeRequiredDescription
idUUIDYesPrimary identifier
tenant_idUUIDYesTenant reference
facility_idUUIDYesAuthorized facility
user_idUUIDYesDevice owner
device_idStringYesUnique device fingerprint
device_nameStringNoUser-friendly name
device_typeEnumYesdesktop, tablet, mobile
os_infoStringNoOperating system
browser_infoStringNoBrowser/app info
authorized_atTimestampYesWhen authorized
authorized_byUUIDNoAdmin who authorized
last_sync_atTimestampNoLast successful sync
last_seen_atTimestampNoLast activity
offline_tokenStringNoEncrypted offline auth token
token_expires_atTimestampNoToken expiration
max_offline_hoursIntegerNoMax offline duration allowed
statusEnumYesactive, suspended, revoked
revoked_atTimestampNoWhen revoked
revoked_byUUIDNoWho revoked
revoked_reasonStringNoRevocation reason

Device Status Values:

StatusDescription
activeDevice can operate offline
suspendedTemporarily disabled (e.g., security concern)
revokedPermanently disabled

Relationships:

  • Belongs to: Tenant, Facility, User
  • Has many: OfflineSyncLogs

Entity: SyncBatch

Purpose: Group related offline operations for atomic sync

Attributes:

AttributeTypeRequiredDescription
idUUIDYesPrimary identifier
tenant_idUUIDYesTenant reference
device_idStringYesOriginating device
user_idUUIDYesUser who created batch
batch_numberIntegerYesSequential batch number per device
operation_countIntegerYesNumber of operations in batch
created_atTimestampYesClient creation time
received_atTimestampNoServer receive time
completed_atTimestampNoAll operations processed
statusEnumYespending, processing, completed, partial, failed
sync_logsUUID[]NoArray of sync_log IDs in batch

Batch Status Values:

StatusDescription
pendingBatch received, not yet processed
processingCurrently processing operations
completedAll operations successfully synced
partialSome operations failed or have conflicts
failedBatch processing failed

Relationships:

  • Belongs to: Tenant, User, OfflineDevice
  • Has many: OfflineSyncLogs

Clinical Schema: Offline-Aware Extensions

Entity: OfflinePrescription

Purpose: Track prescriptions created offline for mandatory review workflow

Prescriptions created offline require clinical review because they may have been created without access to the latest patient data (allergies, current medications, recent lab results).

Attributes:

AttributeTypeRequiredDescription
idUUIDYesPrimary identifier
tenant_idUUIDYesTenant reference
prescription_idUUIDYesLink to clinical.medication_requests
offline_idUUIDYesClient-generated ID
device_idStringYesDevice that created it
created_offlineBooleanYesAlways true for this table
created_atTimestampYesOffline creation time
synced_atTimestampNoWhen synced to server
review_statusEnumYespending_review, reviewed, flagged
reviewed_byUUIDNoPractitioner who reviewed
reviewed_atTimestampNoReview timestamp
review_notesTextNoReviewer comments
flagged_reasonStringNoIf flagged for concern

Review Status Values:

StatusDescription
pending_reviewAwaiting clinical review
reviewedReviewed and approved
flaggedFlagged for concern (drug interaction, allergy, etc.)

Clinical Workflow:

Offline Creation --> Sync --> pending_review --> reviewed/flagged
                                   |
                                   +--> Drug interaction check
                                   +--> Allergy check
                                   +--> Formulary check

Relationships:

  • Belongs to: Tenant, MedicationRequest

Entity: OfflineEncounter

Purpose: Track encounters created or modified offline

Attributes:

AttributeTypeRequiredDescription
idUUIDYesPrimary identifier
tenant_idUUIDYesTenant reference
encounter_idUUIDYesLink to clinical.encounters
offline_idUUIDYesClient-generated ID
device_idStringYesDevice used
started_offlineBooleanYesEncounter started offline
ended_offlineBooleanNoEncounter ended offline
synced_atTimestampNoInitial sync time
last_offline_updateTimestampNoLast offline modification
offline_duration_minsIntegerNoTotal offline time during encounter

Relationships:

  • Belongs to: Tenant, Encounter

Identity Schema: Facility Offline Settings

Entity: FacilityOfflineSettings

Purpose: Configure offline capabilities per facility

Attributes:

AttributeTypeRequiredDescription
idUUIDYesPrimary identifier
tenant_idUUIDYesTenant reference
facility_idUUIDYesFacility reference
offline_enabledBooleanYesOffline mode enabled
max_offline_hoursIntegerNoMax offline duration (default: 48)
max_devices_per_userIntegerNoDevice limit per user (default: 3)
auto_approve_devicesBooleanNoAuto-approve new devices
require_admin_approvalBooleanNoAdmin must approve devices
allowed_offline_featuresJSONBNoFeature flags for offline
sync_priority_rulesJSONBNoPriority rules for sync queue
conflict_default_strategyEnumNoDefault conflict resolution
data_retention_daysIntegerNoDays to keep offline data
require_sync_on_loginBooleanNoForce sync before new session
updated_atTimestampYesLast update
updated_byUUIDNoWho updated

Allowed Offline Features Structure:

{
  "queue_management": true,
  "patient_checkin": true,
  "view_patient_records": true,
  "create_prescriptions": true,
  "create_appointments": false,
  "billing_invoices": true,
  "lab_orders": false
}

Sync Priority Rules Structure:

{
  "priority_order": [
    { "resource": "encounters", "priority": 1 },
    { "resource": "prescriptions", "priority": 2 },
    { "resource": "appointments", "priority": 3 },
    { "resource": "invoices", "priority": 4 }
  ],
  "batch_size": 50,
  "retry_intervals_seconds": [30, 60, 300, 900, 3600]
}

Conflict Default Strategy Values:

StrategyDescription
client_winsClient changes always win
server_winsServer state always wins
manualRequire manual resolution

Relationships:

  • Belongs to: Tenant, Facility

Version Tracking for Conflict Detection

All offline-syncable entities need version tracking columns for optimistic locking.

Version Tracking Columns

Add these columns to offline-syncable tables in clinical.* and billing.* schemas:

ColumnTypeDescription
versionIntegerIncremented on each update
updated_atTimestampLast modification time
updated_byUUIDUser who last modified
offline_createdBooleanWas created offline
offline_modifiedBooleanWas last modified offline

Optimistic Locking Pattern

Client State                    Server State
-------------                   ------------
version: 5                      version: 5
data: {...}                     data: {...}

Client edits offline            Server receives another update
version: 5 (unchanged)          version: 6 (incremented)

Client syncs with version: 5
Server detects: 5 < 6
--> CONFLICT (version_mismatch)

Conflict Resolution Patterns

Different data types require different conflict resolution strategies based on clinical safety and business rules.

Pattern 1: Last-Write-Wins (Optimistic)

Use for: Queue position, check-in status, non-critical metadata

Server version: N
Client sends: version N, changes
Result: Accept if server still at N, reject if N+1

Rationale: Low-risk data where latest state is most important.


Pattern 2: Server-Authoritative

Use for: Appointments, slot availability, financial transactions

Conflict detected
Result: Server state wins, client notified of rejection

Rationale: Consistency critical - can't double-book appointments or create duplicate payments.


Pattern 3: Client-Wins with Mandatory Review

Use for: Prescriptions, clinical notes, diagnoses

Conflict detected
Result: Client state applied, flagged for clinical review

Rationale: Clinical data entered during patient encounter should be preserved, but requires review for safety.


Pattern 4: Merge with Manual Resolution

Use for: Patient demographics, contact information

Conflict detected
Result: Both versions preserved, user resolves via UI

Rationale: Both updates may contain valid information that should be merged.


Resolution Strategy by Entity

EntityDefault StrategyRationale
Queue PositionLast-Write-WinsReal-time state
Patient Check-inLast-Write-WinsReal-time state
AppointmentServer-AuthoritativeNo double-booking
EncounterClient-Wins + ReviewClinical data preservation
PrescriptionClient-Wins + ReviewClinical safety
Vitals/ObservationsClient-WinsClinical data preservation
InvoiceServer-AuthoritativeFinancial integrity
PaymentServer-AuthoritativeFinancial integrity
Patient DemographicsManual MergeMay need human judgment

Schema Diagram

+------------------------------------------------------------------+
|  AUDIT SCHEMA - Offline Support                                   |
+------------------------------------------------------------------+
|                                                                    |
|  +------------------+       +------------------+                   |
|  | offline_devices  |------>| offline_sync_    |                   |
|  +------------------+       | logs             |                   |
|         |                   +------------------+                   |
|         |                          |                               |
|         v                          v                               |
|  +------------------+       +------------------+                   |
|  | sync_batches     |       | (links to any    |                   |
|  +------------------+       |  synced entity)  |                   |
|                             +------------------+                   |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|  CLINICAL SCHEMA - Offline Extensions                             |
+------------------------------------------------------------------+
|                                                                    |
|  +------------------+       +------------------+                   |
|  | offline_         |       | offline_         |                   |
|  | prescriptions    |       | encounters       |                   |
|  +------------------+       +------------------+                   |
|         |                          |                               |
|         v                          v                               |
|  +------------------+       +------------------+                   |
|  | medication_      |       | encounters       |                   |
|  | requests         |       |                  |                   |
|  +------------------+       +------------------+                   |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|  IDENTITY SCHEMA - Offline Configuration                          |
+------------------------------------------------------------------+
|                                                                    |
|  +------------------+                                              |
|  | facility_offline |                                              |
|  | _settings        |                                              |
|  +------------------+                                              |
|         |                                                          |
|         v                                                          |
|  +------------------+                                              |
|  | facilities       |                                              |
|  +------------------+                                              |
+------------------------------------------------------------------+

RLS Policies

All offline tables use tenant-based Row-Level Security:

-- OfflineSyncLog: tenant isolation
CREATE POLICY tenant_isolation ON audit.offline_sync_logs
    USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

-- OfflineDevice: tenant isolation
CREATE POLICY tenant_isolation ON audit.offline_devices
    USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

-- SyncBatch: tenant isolation
CREATE POLICY tenant_isolation ON audit.sync_batches
    USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

-- OfflinePrescription: tenant isolation
CREATE POLICY tenant_isolation ON clinical.offline_prescriptions
    USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

-- OfflineEncounter: tenant isolation
CREATE POLICY tenant_isolation ON clinical.offline_encounters
    USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

-- FacilityOfflineSettings: tenant isolation
CREATE POLICY tenant_isolation ON identity.facility_offline_settings
    USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

Security Considerations

Device Authorization

  1. Explicit Authorization: Offline devices must be explicitly authorized per facility
  2. Admin Approval Option: Facilities can require admin approval for new devices
  3. Device Limits: Configurable max devices per user (default: 3)

Token Management

  1. Token Expiry: Offline tokens have configurable expiry (default: 48 hours)
  2. Force Sync: Can require sync before new session starts
  3. Remote Revocation: Devices can be remotely revoked, forcing re-authentication

Data Protection

  1. Client Encryption: Client-side storage must encrypt PHI at rest (application responsibility)
  2. Minimal Data: Only sync data needed for offline functionality
  3. Retention Limits: Configurable data retention on client

Audit Trail

  1. Complete Logging: All offline operations logged with device and timestamp
  2. Conflict Tracking: All conflicts and resolutions tracked
  3. Device History: Full device authorization/revocation history

Compliance Considerations

HIPAA (USA)

  • PHI access logged in audit.offline_sync_logs
  • Device authorization tracked for access control
  • Conflict resolution audited for data integrity

DPDP (India)

  • Consent for offline data storage (application layer)
  • Data retention limits enforced via data_retention_days
  • Right to erasure supported via device revocation

General

  • All offline activity creates audit trail
  • Conflict resolution traceable
  • Device lifecycle fully documented

Client-Side Technology Options

While this document focuses on the server-side schema, here are the client technologies that work with this design:

TechnologyPurposeNotes
IndexedDBLocal databaseStore offline data
Service WorkerNetwork proxyIntercept requests, serve cached data
Background Sync APIQueue mutationsSync when online
WorkboxService Worker toolkitSimplifies implementation
Dexie.jsIndexedDB wrapperEasier IndexedDB API

Alternative: Postgres-Native Sync

If custom sync is too complex, consider:

OptionDescriptionTrade-offs
PowerSyncPostgres sync serviceCommercial, production-ready
ElectricSQLPostgres-native syncOpen source, newer

These add a sync layer between PostgreSQL and the client, potentially simplifying implementation.


Entity Summary

SchemaEntityPurposeRLS
auditOfflineSyncLogTrack offline operationsYes
auditOfflineDeviceAuthorized devicesYes
auditSyncBatchAtomic sync groupsYes
clinicalOfflinePrescriptionPrescription review workflowYes
clinicalOfflineEncounterEncounter offline trackingYes
identityFacilityOfflineSettingsPer-facility configurationYes

On this page