Steer-01: EHR Builder — Real-Time Record Assembly¶
Read first:
specs/sdd-mvp/05-ehr-builder.md,specs/sdd-mvp/02-event-driven-design.md,specs/sdd-mvp/03-data-architecture.md
Context & Goal¶
Build the EHR Builder service — the central system that assembles a structured patient health record from heterogeneous, asynchronous data sources (chat, documents, agents). Every new data point triggers an event and updates the record in real-time. This is the foundation that all other steer sessions write to.
Backend (curaway-ai/curaway-backend)¶
Step 1: Create EHR Builder Service¶
Create app/services/ehr_builder_service.py:
EHRBuilderServiceclass with dependency injection forfhir_service,patient_service,graph_serviceprocess_event(event: Event) -> EHRUpdateResult— main entry point, dispatches byevent_typemerge_clinical_entities(patient_id, tenant_id, entities, source, confidence) -> list[FHIRResource]— creates/updates FHIR resources with conflict detectionupdate_from_chat(patient_id, tenant_id, extracted_data, source_message_id) -> EHRUpdateResult— processes structured data from Intake Agent chat extractioncalculate_intake_progress(patient_id, tenant_id, procedure_code) -> float— returns 0.0–1.0 based on weighted category completion (demographics 0.15, medical history 0.25, procedure-specific 0.25, preferences 0.10, documents 0.15, consent 0.10)get_ehr_summary(patient_id, tenant_id) -> EHRSummary— returns complete summary for left paneldetect_conflicts(patient_id, existing, incoming) -> list[ConflictRecord]— compares against existing FHIR resources
Step 2: Merge Rules Implementation¶
Implement the four merge rules from spec: 1. Same source, newer data → update with audit trail (old value in event history) 2. Different sources, same field → prefer structured (Clinical Agent FHIR > document extraction > chat extraction > self-reported). Both stored, higher-confidence canonical. 3. Conflicting clinical data → store both with confidence scores, flag if delta > 0.3 4. Missing required fields → tracked in progress, Intake Agent asks proactively
Step 3: Intake Progress Calculator¶
Create progress calculation based on procedure-specific requirements: - Load procedure requirements from Neo4j (REQUIRES_TEST relationships) - Check each required/conditional/recommended item against patient data - Weight categories and compute total (see spec for weights) - For Aisha TKR: demographics, conditions (M17.11, E11, I10), required docs (X-ray, blood panel, ECG, HbA1c), preferences, consent
Step 4: EHR Summary Endpoint¶
Create GET /api/v1/patients/{patient_id}/ehr-summary:
- Returns structured summary grouped by category (conditions, medications, allergies, documents, progress)
- Each item includes source, confidence, created_at
- Document checklist with required/conditional/recommended status
- Total intake_progress percentage
Step 5: Event Handlers¶
Create event handlers in app/services/ehr_event_handlers.py:
- handle_clinical_entities_extracted → call merge_clinical_entities
- handle_fhir_resource_created → update Neo4j graph + Qdrant embedding
- handle_chat_data_collected → call update_from_chat
- handle_document_parsed → check for clinical content, chain to Clinical Agent if found
- handle_consent_changed → update consent status in progress calculation
- Each handler emits ehr_updated event after processing (for SSE)
Step 6: Anomaly Detection¶
Create app/services/anomaly_detector.py:
- detect_expired_documents(patient_id, procedure_code) — flag docs older than validity_days
- detect_out_of_range_labs(patient_id) — compare lab values against reference ranges
- detect_missing_required_docs(patient_id, procedure_code) — check against procedure checklist
- detect_conflicting_diagnoses(patient_id) — cross-reference conditions from different sources
- Return list of AnomalyFlag objects with severity and suggested action
Step 7: Tests¶
Write tests in tests/test_ehr_builder.py:
- Test merge rules (all 4 scenarios)
- Test progress calculation with partial data
- Test conflict detection with overlapping conditions
- Test anomaly detection (expired doc, missing required doc)
- Test event handler dispatch
- Test EHR summary endpoint returns correct structure
Backend Verification¶
# Run EHR builder tests
python -m pytest tests/test_ehr_builder.py -v
# Check new endpoint exists
curl -s http://localhost:8000/docs | grep ehr-summary
# Type check
mypy app/services/ehr_builder_service.py --strict
Frontend (curaway-ai/curaway-frontend)¶
Step 1: EHR Summary Component¶
Create src/components/ehr/EHRSummary.tsx:
- Fetches from GET /api/v1/patients/{id}/ehr-summary
- Collapsible sections: Conditions, Medications, Allergies, Documents, Preferences
- Each condition shows source badge (Agent/Chat/Document) and confidence indicator
- Progress bar at top with percentage
- Refreshes on ehr_update SSE event
Step 2: Document Checklist Component¶
Create src/components/ehr/DocumentChecklist.tsx:
- Shows required/conditional/recommended documents for current procedure
- Status icons: ✅ uploaded+analyzed, ⏳ processing, ⬜ missing, ⚠️ expired
- Clicking missing doc opens file upload dialog
- Updates via SSE document_update events
Step 3: Wire into Left Panel¶
Update the left panel (sliding 300px panel) to include:
- Tab: "EHR" → EHRSummary component
- Tab: "Docs" → DocumentChecklist component
- Both tabs auto-refresh on SSE events
Step 4: Progress Strip Update¶
Update right-side progress strip to read intake_progress from EHR summary endpoint instead of local state. Subscribe to intake_progress SSE events.
Frontend Verification¶
npm run build # must be clean
npx tsc --noEmit # type check
# Manual: verify EHR summary renders in left panel with mock data
Checklist¶
- [ ] Alembic migration (if any schema changes for anomaly flags)
- [ ] Seed data: TKR procedure requirements in Neo4j (if not already seeded)
- [ ] Error codes: EHR_MERGE_CONFLICT_001, EHR_PROGRESS_CALC_001, EHR_ANOMALY_001
- [ ] Feature flag:
ehr_anomaly_detection(Flagsmith) - [ ] Env vars: none new expected
- [ ] Swagger: new
/ehr-summaryendpoint documented - [ ] Unit tests: 8+ tests for merge rules, progress, anomalies
- [ ] PostHog: track
ehr_summary_viewed,document_checklist_interaction - [ ] Loading states: skeleton loaders for EHR summary sections
- [ ] Mobile: left panel collapses, EHR summary accessible via hamburger menu
- [ ] CLAUDE.md: update both repos with EHR Builder service description
- [ ] Rollback: EHR Builder service is additive — disable via feature flag if issues