Open-Nursing-Validator / PHASE2_FHIR.md
NurseCitizenDeveloper's picture
Deploy Open Nursing Validator (Docker)
6d12932 verified
# Phase 2.3: EHR/FHIR Integration
## Overview
**Phase 2.3** integrates the application with Electronic Health Record (EHR) systems through:
- **FHIR APIs** (Fast Healthcare Interoperability Resources)
- **HL7 v2 messaging** (legacy EHR systems)
- **Real patient data** from hospital systems
- **Bi-directional data sync**
**Prerequisites:**
- Phase 2.1 (PostgreSQL Database)
- Phase 2.2 (Analytics) - optional
---
## Features
### 1. **FHIR API Integration**
#### Patient Data Retrieval
```python
from ehr_integration import FHIRAPIClient
client = FHIRAPIClient("https://fhir.hospital.com")
# Get patient demographics
patient = client.get_patient("12345")
# Get patient's conditions
conditions = client.get_patient_conditions("12345")
# Get vital signs and labs
observations = client.get_patient_observations("12345")
# Get active care plans
care_plans = client.get_patient_care_plans("12345")
# Get patient goals
goals = client.get_patient_goals("12345")
```
#### Data Submission
```python
# Create new observation (e.g., blood pressure reading)
obs_id = client.create_observation("12345", {
"code": {"coding": [{"code": "85354-9"}]}, # BP
"valueQuantity": {"value": 120, "unit": "mmHg"}
})
# Update care plan
client.update_care_plan("cp-123", updated_data)
```
### 2. **HL7 v2 Messaging**
For integration with legacy EHR systems:
```python
from ehr_integration import HL7Parser
parser = HL7Parser()
# Parse incoming HL7 message
message = """MSH|^~\\&|APP|FAC|APP|FAC|20251129...
PID|||12345||Doe^John||19800101|M
OBX|1|NM|85354-9||120||80-120|N"""
parsed = parser.parse_hl7_message(message)
# Returns: {
# "patient": {"id": "12345", "name": "Doe^John", ...},
# "observations": [{"type": "85354-9", "value": "120", ...}]
# }
```
### 3. **FHIR Resource Building**
Helper functions to create standardized FHIR resources:
```python
from ehr_integration import FHIRResourceBuilder
builder = FHIRResourceBuilder()
# Create condition
condition = builder.build_condition(
patient_id="12345",
code="80891009", # SNOMED code for type 2 diabetes
display="Type 2 Diabetes Mellitus",
onset_date="2020-01-15"
)
# Create observation (lab result)
observation = builder.build_observation(
patient_id="12345",
code="2345-7", # Glucose
value=125,
unit="mg/dL",
reference_range=(70, 100)
)
# Create goal
goal = builder.build_goal(
patient_id="12345",
description="Achieve HbA1c < 7%",
status="in-progress",
target_date="2026-01-15"
)
```
### 4. **EHR Integration Manager**
Comprehensive manager for all EHR operations:
```python
from ehr_integration import EHRIntegrationManager
manager = EHRIntegrationManager(
fhir_url="https://fhir.hospital.com",
api_key="your-api-key"
)
# Sync all patient data
patient_record = manager.sync_patient_data("12345")
# Returns complete record with:
# - Patient demographics
# - Conditions
# - Observations
# - Care plans
# - Goals
# Send observation to EHR
obs_id = manager.send_observation_to_ehr("12345", observation)
# Process incoming HL7
parsed = manager.process_hl7_message(hl7_message)
```
---
## Setup Instructions
### 1. Prerequisites
```bash
# Install FHIR libraries
pip install fhir-parser requests
# Or add to requirements.txt
fhir-parser==1.2.0
requests==2.28.0
```
### 2. Configure FHIR Server Connection
```bash
# Update .env.production
EHR_FHIR_URL=https://fhir.hospital.com
EHR_API_KEY=your_api_key
EHR_TIMEOUT=10
EHR_VERIFY_SSL=true
EHR_SYNC_INTERVAL=3600 # seconds
```
### 3. Register with FHIR Server
Most FHIR servers require:
1. **OAuth 2.0 credentials** or **API key**
2. **Client registration** (get client_id, client_secret)
3. **Scope permissions** (read, write, admin)
Example (Azure Health Data Services):
```bash
# Register application
az ad app create \
--display-name "Nursing Validator" \
--reply-urls "http://localhost:8501"
# Get credentials
AZURE_AD_TENANT_ID=your-tenant-id
AZURE_AD_CLIENT_ID=your-client-id
AZURE_AD_CLIENT_SECRET=your-secret
```
### 4. Initialize EHR Integration
```python
from ehr_integration import EHRIntegrationManager
import os
manager = EHRIntegrationManager(
fhir_url=os.getenv("EHR_FHIR_URL"),
api_key=os.getenv("EHR_API_KEY")
)
# Verify connection
patient = manager.fhir_client.get_patient("test-patient-id")
if patient:
print("✅ Connected to FHIR server")
else:
print("❌ Failed to connect")
```
---
## FHIR Resources Supported
### Patient
- Demographics
- Contact information
- Insurance information
### Condition
- Diagnoses
- Problems
- Chronic conditions
### Observation
- Vital signs (BP, temp, O2)
- Lab results
- Assessment findings
### Goal
- Clinical goals
- Patient goals
- Progress tracking
### CarePlan
- Nursing care plans
- Treatment protocols
- Intervention activities
### Medication
- Current medications
- Dosage information
- Allergies
### Procedure
- Surgical procedures
- Clinical procedures
- Completed interventions
### Appointment
- Scheduled visits
- Follow-ups
- Clinic appointments
---
## Data Synchronization
### Real-time Sync
```python
# Background task to sync patient data
import asyncio
import time
async def sync_patient_data_loop(patient_id, interval=3600):
"""Continuously sync patient data."""
while True:
patient_data = manager.sync_patient_data(patient_id)
# Save to database
from database import save_patient_record
save_patient_record(patient_id, patient_data)
await asyncio.sleep(interval)
# Run in background
asyncio.create_task(sync_patient_data_loop("12345"))
```
### Event-Driven Sync
```python
# Listen for EHR events (webhook)
@st.streamlit_route("/ehr-webhook", methods=["POST"])
def receive_ehr_update(request):
data = request.json
patient_id = data["patient_id"]
# Sync on update
patient_data = manager.sync_patient_data(patient_id)
return {"status": "updated"}
```
---
## HL7 v2 Message Types
### ADT (Admission/Discharge/Transfer)
```
MSH|^~\&|SENDAPP|SENDFAC|RECAPP|RECFAC|20251129120000||ADT^A01
PID|1||12345||Doe^John
```
### ORM (Order Message)
```
MSH|^~\&|SENDAPP|SENDFAC|RECAPP|RECFAC|20251129120000||ORM^O01
ORC|NW|123456
OBX|1|NM|85354-9||120||80-120|N
```
### ORU (Observation/Result - Lab)
```
MSH|^~\&|LAB|HOSPITAL|APP|FACILITY|20251129120000||ORU^R01
OBX|1|NM|2345-7||125||70-100|N
```
---
## Security Considerations
### HIPAA Compliance
- ✅ Encryption in transit (HTTPS/TLS)
- ✅ Encryption at rest (database encryption)
- ✅ API key management
- ✅ Audit logging
- ✅ Access controls
- ✅ Data anonymization
- ✅ Consent management
### OAuth 2.0 Implementation
```python
from oauthlib.oauth2 import WebApplicationClient
client_id = os.getenv("AZURE_AD_CLIENT_ID")
client_secret = os.getenv("AZURE_AD_CLIENT_SECRET")
client = WebApplicationClient(client_id)
# Get authorization URL
authorization_url, state = client.prepare_request_uri(
"https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
)
# Exchange code for token
token = client.prepare_refresh_token_request_body(
refresh_token, client_id, client_secret
)
```
### Certificate Pinning
```python
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context
class SSLAdapter(HTTPAdapter):
def init_poolmanager(self, *args, **kwargs):
ctx = create_urllib3_context()
ctx.load_verify_locations('hospital_ca.pem')
kwargs['ssl_context'] = ctx
return super().init_poolmanager(*args, **kwargs)
session = requests.Session()
session.mount('https://', SSLAdapter())
```
---
## Troubleshooting
### Connection Errors
```python
# Test connection
try:
patient = client.get_patient("test-id")
if patient:
print("✅ Connection successful")
else:
print("❌ Invalid patient ID")
except Exception as e:
print(f"❌ Connection failed: {e}")
```
### Authentication Issues
```bash
# Verify API key is valid
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://fhir.hospital.com/Patient/test-id
# Check token expiry
# Refresh token if needed
```
### FHIR Server Compatibility
Some common FHIR servers:
- **Azure Health Data Services**: FHIR R4
- **Cerner**: FHIR R4 (with extensions)
- **Epic**: FHIR R4 (limited)
- **InterSystems**: FHIR R3/R4
- **HAPI FHIR**: Full FHIR support
Verify server's FHIR version:
```bash
curl https://fhir.hospital.com/metadata
```
---
## Integration with Main App
### Add Patient Context to Chat
```python
# In app_phase2.py
if st.session_state.get("patient_id"):
manager = EHRIntegrationManager(ehr_fhir_url, api_key)
patient_data = manager.sync_patient_data(patient_id)
# Use in chat context
context = f"""
Patient: {patient_data['patient']['name']}
Conditions: {', '.join([c['code']['text'] for c in patient_data['conditions']])}
"""
# Include in LLM prompt
qa = RetrievalQA.from_chain_type(
llm=AzureOpenAI(),
chain_type="stuff",
retriever=vector_db.as_retriever(),
return_source_documents=True,
)
response = qa.run(f"{context}\n\nQuestion: {user_input}")
```
### Save Assessments Back to EHR
```python
# After nursing assessment
assessment_observation = builder.build_observation(
patient_id=st.session_state.patient_id,
code="84811-6", # Nursing assessment
value="Assessment complete",
unit="text"
)
obs_id = manager.send_observation_to_ehr(
st.session_state.patient_id,
assessment_observation
)
st.success(f"Assessment saved to EHR: {obs_id}")
```
---
## Performance Optimization
### Caching
```python
import streamlit as st
from functools import lru_cache
@st.cache_data(ttl=3600)
def get_patient_data(patient_id):
return manager.sync_patient_data(patient_id)
```
### Batch Operations
```python
# Sync multiple patients
patient_ids = ["123", "456", "789"]
for patient_id in patient_ids:
patient_data = manager.sync_patient_data(patient_id)
# Process...
```
### Pagination
```python
# Most FHIR servers support _count and _offset
url = f"{self.base_url}/Observation?subject=Patient/{patient_id}&_count=100&_offset=0"
```
---
## Next Steps
1. **Get FHIR server credentials** from your EHR vendor
2. **Test connection** to FHIR server
3. **Configure patient sync** frequency
4. **Implement UI** for patient selection
5. **Add audit logging** for all data access
6. **Deploy to staging** and test with real data
7. **Proceed to Phase 2.4** - Mobile App
---
## Files Created/Modified
**New Files:**
- `ehr_integration.py` (400+ lines)
**Integration Points:**
- Update `app_phase2.py` for patient selection
- Add `save_patient_record()` to database.py
- Update requirements.txt with fhir-parser
**Documentation:**
- `PHASE2_FHIR.md` (this file)
---
## References
- [FHIR Specification](http://hl7.org/fhir/R4/)
- [HL7 v2 Reference](http://www.hl7.org/implement/standards/product_brief.cfm?product_id=20)
- [SMART on FHIR](http://docs.smarthealthit.org/)
- [Azure Health Data Services](https://learn.microsoft.com/en-us/azure/healthcare-apis/)
---
*Phase 2.3 Implementation - November 29, 2025*