EHR Ingestion Log
Route: /reports/ehr-ingestion
File: src/reports/EhrIngestionLogPage.tsx
The EHR Ingestion Log gives admins a full audit trail of every FHIR resource received from an external EHR during sync. It shows what was received, whether it was stored successfully, how long it took, and the raw payload side-by-side with what was stored in ChartChat.
Navigation — Three drill-down levels
The page is structured as three levels. Breadcrumbs at the top let you navigate back.
Connections → Patient / Resource Type Summary → Individual Log Records
Level 1 — Connections
Lists all PatientEHRConnection resources across all patients. Each row represents one patient's connection to one EHR.
Summary chips (clickable filters):
| Chip | Filter |
|---|---|
| Total | All connections |
| Active | status = active |
| Token Expired | status = token_expired |
| Inactive | Any other status |
Clicking a chip filters the table to that status. Clicking again clears the filter.
Table columns:
| Column | Description |
|---|---|
| Patient | Avatar + full name + UUID |
| Hospital | EHR provider name or hospital endpoint name |
| Status | active (green) / token_expired (orange) / other (gray) |
| Last Sync | Timestamp of the last completed sync |
Search: Free-text search by patient name, hospital name, or status.
Sorting: All columns are sortable (asc/desc) by clicking the column header.
Pagination: 20 connections per page.
Data fetching: Streams all PatientEHRConnection resources via searchResourcePages with _count=50&_sort=-_lastUpdated. Hospital names for UUID-based ehrProvider values are resolved by looking up the corresponding Endpoint resource.
Clicking any row drills into Level 2 for that connection.
Level 2 — Resource Type Summary
Shows a breakdown of all EhrIngestionLog records for the selected connection, grouped by FHIR resource type.
Patient summary bar at the top shows:
- Patient name + avatar
- Connection status badge
- Hospital name
- Last sync timestamp
- Stats: total sync runs, total resources ingested, total failed
Table columns:
| Column | Description |
|---|---|
| Resource Type | FHIR resource type (e.g. Condition, Observation) |
| Total | Total records ingested for this type |
| Synced | Count with status = success |
| Failed | Count with status = failed — shown as red badge if > 0 |
| Success Rate | Percentage, with a colour-coded progress bar (green ≥ 100%, orange ≥ 80%, red < 80%) |
| Last Synced | Most recent receivedAt timestamp for this type |
| View Bundle | Opens a modal showing all raw EHR payloads for this type as a FHIR Bundle |
View Bundle modal: Assembles all ehrData.payload values for the resource type into a single FHIR Bundle (type: searchset) and displays it as formatted JSON. Includes a copy-to-clipboard button.
Data fetching: Streams all EhrIngestionLog records for the connection using the connection search parameter:
EhrIngestionLog?connection=PatientEHRConnection/{id}&_count=100&_sort=-_lastUpdated
Clicking a resource type row drills into Level 3.
Level 3 — Individual Log Records
Shows the paginated list of individual EhrIngestionLog entries for one resource type within the selected connection.
Table columns:
| Column | Description |
|---|---|
| Received At | Timestamp when the resource arrived |
| Stored Resource | Reference to the stored FHIR resource (e.g. Condition/abc-123) or — if failed |
| Duration | Processing time in milliseconds |
| Error | Error message (first line, truncated) if ingestion failed |
Pagination: 25 records per page.
Clicking any row opens the Detail Modal.
Detail Modal
Opens when clicking an individual log record at Level 3. Shows a complete side-by-side comparison:
Header metadata:
| Field | Description |
|---|---|
| Patient | Name or UUID |
| Hospital | EHR name |
| Resource Type | FHIR type |
| Received At | Timestamp |
| Duration | Processing time in ms |
| Source Endpoint | Full EHR FHIR endpoint URL |
Error block: Shown in red if outcome.error is present.
Raw vs Stored (side by side):
| Left panel | Right panel |
|---|---|
Raw from EHR — ehrData.payload formatted as JSON | Stored in ChartChat — fetched live via medplum.readReference(storedResource) |
The stored resource is fetched on-demand when the modal opens. If the ingestion failed, the right panel shows "No stored resource (ingestion failed)".
EhrIngestionLog FHIR Resource
Each row in the table corresponds to one EhrIngestionLog resource. See EHR Import — Ingestion Logging for the full field reference.
Key fields used by this page:
| Field | Used for |
|---|---|
connection | Filtering logs by EHR connection (search param) |
sourceResourceType | Grouping by resource type (Level 2) |
status | Success/failed counts and row highlighting |
syncBatch | Counting distinct sync runs |
ehrData.payload | Raw EHR data in Detail Modal and Bundle viewer |
storedResource | Fetching the stored FHIR resource in Detail Modal |
timing.durationMs | Duration column |
outcome.error.message | Error column and modal error block |