DeveloperCare plansCare planBackend
Longitudinal Health Records (LHR) System Design
Overview
This document outlines the system design for implementing FHIR-compliant Longitudinal Health Records while maintaining backward compatibility with the existing Kulcare platform.
Frontend Integration: LHR UI exists at /cms/careplan/patient/:patientId with complete dashboard implementation expecting specific API structure.
Current System Analysis
Existing Architecture
- Current "Careplan": Actually a prescription + lab order system, will be renamed to
prescriptions - Patient History Log: Polymorphic tracking system capturing all patient events
- Patient Medicines: Active medication tracking copied from prescription_medicines
- Document Architecture: Medical records with background document generation
- Frontend LHR: Complete implementation with aggregation service expecting longitudinal data
Key Insights
- Current system works well for encounter-based care delivery
- Patient History Log already captures comprehensive event tracking
- Need to add patient-level problem tracking for true LHR
- Existing patient_medicines provides current medication status
FHIR-Compliant Architecture Design
Healthcare Data Hierarchy
Patient
├── Encounters (Appointments)
│ ├── Clinical Impressions (Diagnosis + Observations)
│ ├── Medication Requests (Individual Prescriptions)
│ └── Service Requests (Lab Tests/Procedures)
├── Problems (Patient-Level Conditions)
├── Care Plans (Aggregated Care Plans)
└── Longitudinal Summary (Aggregated View)Core Entities
1. Encounters (Existing Appointments)
- Purpose: Represents patient visits/consultations
- Status: No changes needed - appointments already serve this role
- Enhancement: Add clinical_impression field for structured diagnosis
2. Prescriptions (Renamed Careplans)
- Purpose: Maintains current prescription + lab order workflow
- Status: Rename from "careplan" to "prescriptions" for simplicity
- Enhancement: Add links to individual FHIR resources
- Independence: May or may not belong to an appointment (encounter)
3. Clinical Impressions (New)
- Purpose: FHIR-compliant clinical assessment and diagnosis
- Source: Generated from prescription diagnosis + observations
- Features: Structured diagnosis with ICD-10 codes, clinical reasoning
4. Medication Requests (New)
- Purpose: Individual FHIR-compliant medication orders
- Source: Generated from prescription medicines
- Features: Separate document generation, status tracking
5. Service Requests (New)
- Purpose: Individual FHIR-compliant service orders (labs, imaging)
- Source: Generated from prescription tests
- Features: Separate document generation, status tracking
6. Patient Problems (New)
- Purpose: Patient-level problem/condition tracking
- Scope: Aggregated across all encounters within clinic
- Integration: Links to encounters and medication requests
7. Care Plans (New - True FHIR)
- Purpose: High-level care coordination plans
- Scope: Aggregated view of patient care across encounters
- Content: Goals, care team, active problems, care activities
Data Flow Architecture
1. Encounter Creation Flow
Doctor creates Prescription
└── Background Jobs Trigger
├── Generate Clinical Impression record
├── Generate Medication Request records
├── Generate Service Request records
├── Update Patient Problems
├── Generate individual documents
└── Update Care Plan aggregation2. LHR Data Aggregation
Patient LHR Request
├── Current Medications (from patient_medicines)
├── Problem List (from patient_problems + encounter history)
├── Encounter History (from appointments + prescriptions)
├── Clinical Assessments (from clinical_impressions)
├── Medication History (from medication_requests)
├── Test History (from service_requests)
└── Care Plans (from care_plans)3. Document Generation Strategy
Following existing medical_records architecture:
- Prescription: Full prescription document (current behavior)
- Clinical Impression: Clinical assessment and diagnosis document
- Medication Request: Individual medication-specific document
- Service Request: Individual lab/test order document
- Care Plan: Care plan summary document
Database Schema Changes
New Tables
clinical_impressions
CREATE TABLE clinical_impressions (
id BIGSERIAL PRIMARY KEY,
clinic_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
doctor_id BIGINT NOT NULL,
encounter_id BIGINT, -- nullable - prescriptions may not belong to appointment
prescription_id BIGINT NOT NULL,
-- FHIR ClinicalImpression fields
status VARCHAR(20) DEFAULT 'completed',
subject_reference VARCHAR(255),
assessment_date TIMESTAMP,
-- Clinical assessment
summary TEXT,
finding_codes JSONB DEFAULT '[]', -- ICD-10 codes array
finding_display JSONB DEFAULT '[]', -- Human-readable diagnoses
clinical_notes TEXT,
-- Outcome and recommendations
prognostic_reference TEXT,
plan_reference TEXT,
-- Links to other resources
supports_prescriptions BIGINT[], -- references to prescription ids
-- Document generation
document_generated BOOLEAN DEFAULT FALSE,
document_url TEXT,
metadata JSONB DEFAULT '{}',
deleted BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL
);medication_requests
CREATE TABLE medication_requests (
id BIGSERIAL PRIMARY KEY,
clinic_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
doctor_id BIGINT NOT NULL,
encounter_id BIGINT NOT NULL, -- links to appointment
prescription_id BIGINT NOT NULL,
-- FHIR fields
status VARCHAR(20) DEFAULT 'active',
intent VARCHAR(20) DEFAULT 'order',
medication_name VARCHAR(255) NOT NULL,
dosage_instruction TEXT,
frequency VARCHAR(100),
duration_value INTEGER,
duration_unit VARCHAR(20),
instructions TEXT,
-- Document generation
document_generated BOOLEAN DEFAULT FALSE,
document_url TEXT,
deleted BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL
);service_requests
CREATE TABLE service_requests (
id BIGSERIAL PRIMARY KEY,
clinic_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
doctor_id BIGINT NOT NULL,
encounter_id BIGINT NOT NULL,
prescription_id BIGINT NOT NULL,
-- FHIR fields
status VARCHAR(20) DEFAULT 'active',
intent VARCHAR(20) DEFAULT 'order',
service_type VARCHAR(50), -- 'lab_test', 'imaging', 'procedure'
service_name VARCHAR(255) NOT NULL,
service_code VARCHAR(50),
instructions TEXT,
-- Document generation
document_generated BOOLEAN DEFAULT FALSE,
document_url TEXT,
deleted BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL
);patient_problems
CREATE TABLE patient_problems (
id BIGSERIAL PRIMARY KEY,
clinic_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
doctor_id BIGINT NOT NULL,
-- Problem details
problem_code VARCHAR(50), -- ICD-10 code
problem_name VARCHAR(255) NOT NULL,
problem_category VARCHAR(100),
severity VARCHAR(20),
-- Timeline
onset_date DATE,
resolved_date DATE,
status VARCHAR(20) DEFAULT 'active', -- active, resolved, chronic
-- Clinical context
first_encounter_id BIGINT, -- first appointment where identified
last_encounter_id BIGINT, -- last appointment where addressed
-- Notes
clinical_notes TEXT,
deleted BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL
);care_plans
CREATE TABLE care_plans (
id BIGSERIAL PRIMARY KEY,
clinic_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
doctor_id BIGINT NOT NULL,
-- FHIR CarePlan fields
status VARCHAR(20) DEFAULT 'active',
intent VARCHAR(20) DEFAULT 'plan',
title VARCHAR(255),
description TEXT,
-- Timeline
period_start DATE,
period_end DATE,
-- Care coordination
goals JSONB DEFAULT '{}',
activities JSONB DEFAULT '{}',
care_team JSONB DEFAULT '[]',
-- Problem references
addresses_problems BIGINT[], -- array of patient_problem ids
deleted BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL
);API Design
LHR Endpoints
# GET /api/patients/:patient_id/longitudinal_health_record
{
patient: { ... },
current_problems: [...],
current_medications: [...],
encounter_history: [...],
clinical_assessments: [...],
medication_history: [...],
test_history: [...],
care_plans: [...],
health_trends: { ... }
}New FHIR Resource Endpoints
# Clinical assessment management
GET /api/clinical_impressions
POST /api/clinical_impressions
PUT /api/clinical_impressions/:id
DELETE /api/clinical_impressions/:id
# Medication management
GET /api/medication_requests
POST /api/medication_requests
PUT /api/medication_requests/:id
DELETE /api/medication_requests/:id
# Service management
GET /api/service_requests
POST /api/service_requests
PUT /api/service_requests/:id
DELETE /api/service_requests/:id
# Problem management
GET /api/patient_problems
POST /api/patient_problems
PUT /api/patient_problems/:id
DELETE /api/patient_problems/:id
# Care plan management
GET /api/care_plans
POST /api/care_plans
PUT /api/care_plans/:id
DELETE /api/care_plans/:idIntegration Points
1. Patient History Log Integration
- ClinicalImpression, MedicationRequest, ServiceRequest, and CarePlan will automatically log to patient_history_logs
- Use existing trackable polymorphic pattern
- Maintain existing filtering and search capabilities
2. Document Generation Integration
- Follow existing medical_records + documents pattern
- Background jobs for individual document generation
- Maintain combined prescription document for pharmacy workflow
3. Real-time Updates Integration
- Use existing Pusher channels for real-time prescription updates
- Add new channels for medication/service request status changes
- Maintain existing queue management integration
Security & Privacy
Access Control
- Maintain existing Pundit authorization patterns
- Clinic-scoped data access for all new entities
- Doctor-patient relationship validation for all operations
FHIR Compliance
- Follow FHIR R4 standard for resource definitions
- Maintain required FHIR fields and terminology
- Support FHIR Bundle export for ABDM integration
Data Retention
- Follow existing soft delete patterns
- Maintain audit trails for all medical data changes
- Support data export for patient portability
Performance Considerations
Indexing Strategy
-- Core performance indices
CREATE INDEX idx_medication_requests_patient ON medication_requests(patient_id, status);
CREATE INDEX idx_service_requests_patient ON service_requests(patient_id, status);
CREATE INDEX idx_patient_problems_clinic ON patient_problems(clinic_id, patient_id, status);
CREATE INDEX idx_care_plans_patient ON care_plans(patient_id, status);
-- LHR aggregation indices
CREATE INDEX idx_patient_problems_active ON patient_problems(patient_id) WHERE status = 'active';
CREATE INDEX idx_medication_requests_active ON medication_requests(patient_id) WHERE status = 'active';Caching Strategy
- Redis caching for frequently accessed LHR data
- Cache patient problem lists and current medications
- Invalidate cache on medical record updates
Background Processing
- Use existing Sidekiq infrastructure
- Separate queues for document generation vs. data aggregation
- Retry logic for failed document generation
Migration Approach
Backward Compatibility
- Phase 1: Add new tables alongside existing careplan table
- Phase 2: Rename careplan to prescription with aliases
- Phase 3: Update frontend gradually with feature flags
- Phase 4: Remove aliases after full migration
Data Migration Strategy
- No data loss - existing careplans become prescriptions
- Generate MedicationRequest/ServiceRequest records from existing data
- Create initial patient_problems from historical diagnosis data
- Build care_plans from aggregated encounter data
Success Metrics
Technical Metrics
- API response time < 200ms for LHR endpoints
- Document generation completion rate > 99%
- Zero data loss during migration
- Backward compatibility maintained for 30 days
Business Metrics
- No disruption to existing prescription workflow
- Enhanced patient care coordination capabilities
- Improved medication adherence tracking
- Better care plan compliance monitoring