Engineering a Care Coordination Platform: Architecture, EMR Integration, and Real-Time Alerting
Care coordination software sits at the intersection of HL7 messaging, HIPAA compliance, real-time clinical alerting, and complex state machines for patient workflows. This is what the architecture looks like when you build it for production.

Care coordination platforms do one deceptively simple thing: make sure the right clinician knows about the right patient at the right time. In practice, this means processing real-time events from multiple EMR systems, maintaining patient state across care episodes, routing alerts to the appropriate care team members, and doing all of this in a way that is HIPAA-compliant and reliable enough that clinicians trust it with actual patient care.
This post walks through the architecture of a care coordination platform — the kind of system we built for CareCoordinations to manage post-acute care workflows, which involved integrating with HCHB (home health EMR), managing patient state across care episodes, and delivering real-time alerts to care coordinators and field clinicians.
The domain model
Care coordination has a specific domain vocabulary that needs to be reflected in the data model:
- Patient: The person receiving care. Has demographics, insurance, diagnoses, and care history.
- Care episode: A bounded period of care with a specific goal (post-surgical recovery, chronic disease management, hospice). A patient may have multiple sequential or overlapping episodes.
- Care team: The set of clinicians assigned to a patient during an episode. Includes a care coordinator (typically a nurse or social worker), a primary physician, and various specialists and field clinicians.
- Care plan: The structured set of interventions, visit schedules, and goals for a care episode.
- Clinical event: Something that happens to or about a patient — a visit, a lab result, a vital sign, a medication change, a hospitalization, a discharge.
- Alert: A notification generated by a clinical event that requires action from a care team member.
- Task: A specific action item assigned to a care team member, with a due date and completion tracking.
EMR integration architecture
Care coordination platforms must integrate with the EMR systems that record clinical activity. For home health care coordination, the primary integration is with a home health EMR — HCHB in the system we built. This integration is HL7 v2, not FHIR, because HCHB's real-time event notification capability is built on HL7 v2 ADT messaging.
The MLLP listener
We run a dedicated MLLP listener service that receives HL7 v2 messages from HCHB on a persistent TCP connection. The listener handles the low-level MLLP framing and acknowledgment protocol, then publishes normalized events to an internal queue.
// MLLP server — handles the raw TCP framing
const server = net.createServer((socket) => {
let buffer = Buffer.alloc(0)
socket.on('data', (data) => {
buffer = Buffer.concat([buffer, data])
while (true) {
const startIdx = buffer.indexOf(0x0B) // MLLP start block
const endIdx = buffer.indexOf(Buffer.from([0x1C, 0x0D])) // MLLP end block
if (startIdx === -1 || endIdx === -1) break
const messageBytes = buffer.slice(startIdx + 1, endIdx)
const messageText = messageBytes.toString('utf-8')
// Send ACK
socket.write(Buffer.from([0x0B]))
socket.write(buildAck(messageText, 'AA'))
socket.write(Buffer.from([0x1C, 0x0D]))
// Publish to queue for processing
queue.add('process-hl7-message', { raw: messageText })
buffer = buffer.slice(endIdx + 2)
}
})
})
server.listen(HL7_PORT, () => {
logger.info({ port: HL7_PORT }, 'MLLP listener started')
})
HL7 v2 message processing
The queue worker parses each HL7 v2 message and routes it based on message type and trigger event:
queue.process('process-hl7-message', async (job) => {
const segments = parseHL7v2(job.data.raw)
const msh = extractMSH(segments)
const messageType = \`\${msh.messageType}^{msh.triggerEvent}\`
// Log raw message for audit trail
await db.hl7MessageLog.create({
data: {
messageId: msh.messageControlId,
messageType,
sendingFacility: msh.sendingFacility,
receivedAt: new Date(),
rawMessage: job.data.raw,
}
})
switch (messageType) {
case 'ADT^A01': // Admit
return handleAdmit(segments)
case 'ADT^A03': // Discharge
return handleDischarge(segments)
case 'ADT^A08': // Update patient info
return handlePatientUpdate(segments)
case 'ADT^A11': // Cancel admit
return handleCancelAdmit(segments)
case 'ADT^A13': // Cancel discharge
return handleCancelDischarge(segments)
case 'ORU^R01': // Observation result (lab, vitals)
return handleObservationResult(segments)
default:
logger.warn({ messageType }, 'Unhandled HL7 message type')
}
})
Patient matching
The most technically challenging part of the EMR integration: mapping between the EMR's patient identifiers and the care coordination platform's patient records. EMRs use Medical Record Numbers (MRN) that are internal to the EMR system. The care coordination platform has its own patient IDs. The mapping must handle:
- New patients — first time the EMR sends a message for this patient
- Returning patients — patient was previously seen, needs to match to existing record
- Merged patients — EMR has merged two patient records, one of which may exist in our system
- Demographic updates — patient's name, DOB, or address has changed in the EMR
async function matchOrCreatePatient(pid: HL7PID): Promise {
// 1. Try exact MRN match from this EMR facility
const byMrn = await db.patientIdentifiers.findFirst({
where: { identifierType: 'MRN', identifierValue: pid.patientId, facility: pid.facilityId },
})
if (byMrn) return byMrn.patientId
// 2. Try demographic fuzzy match (name + DOB + last 4 SSN if present)
const candidates = await findByDemographics(pid)
if (candidates.length === 1) {
// Confident single match — link the MRN
await db.patientIdentifiers.create({
data: { patientId: candidates[0].id, identifierType: 'MRN', identifierValue: pid.patientId, facility: pid.facilityId }
})
return candidates[0].id
}
if (candidates.length > 1) {
// Multiple matches — flag for manual review
await flagForPatientMatchReview(pid, candidates)
return createStagingPatient(pid) // create a staging record pending review
}
// 3. No match — create new patient
const patient = await db.patients.create({ data: mapPIDtoPatient(pid) })
await db.patientIdentifiers.create({
data: { patientId: patient.id, identifierType: 'MRN', identifierValue: pid.patientId, facility: pid.facilityId }
})
return patient.id
}
The alert engine
Clinical alerting is the core value proposition of a care coordination platform. The alert engine evaluates clinical events against a set of alert rules and determines who needs to know, how urgently, and through what channel.
Alert rules
interface AlertRule {
id: string
name: string
trigger: (event: ClinicalEvent, patient: Patient) => boolean
severity: 'critical' | 'high' | 'medium' | 'low'
recipients: (patient: Patient, careTeam: CareTeamMember[]) => CareTeamMember[]
channels: AlertChannel[]
escalationDelayMinutes: number // if not acknowledged, escalate after this many minutes
message: (event: ClinicalEvent, patient: Patient) => string
}
const ALERT_RULES: AlertRule[] = [
{
id: 'readmission-risk',
name: 'Readmission within 30 days of discharge',
trigger: (event, patient) =>
event.type === 'ADT^A01' &&
patient.lastDischargeDate &&
daysDiff(patient.lastDischargeDate, event.occurredAt) <= 30,
severity: 'critical',
recipients: (patient, careTeam) =>
careTeam.filter(m => m.role === 'care-coordinator' || m.role === 'primary-physician'),
channels: ['push', 'sms', 'in-app'],
escalationDelayMinutes: 15,
message: (event, patient) =>
\`READMISSION: \${patient.firstName} \${patient.lastName} admitted to \${event.facility} — \${daysDiff(patient.lastDischargeDate!, event.occurredAt)} days post-discharge\`,
},
// ... more rules
]
Alert delivery and escalation
async function processAlert(rule: AlertRule, event: ClinicalEvent, patient: Patient): Promise {
const careTeam = await getCareTeam(patient.id)
const recipients = rule.recipients(patient, careTeam)
const message = rule.message(event, patient)
const alert = await db.alerts.create({
data: {
patientId: patient.id,
ruleId: rule.id,
severity: rule.severity,
message,
status: 'pending',
generatedAt: new Date(),
}
})
// Deliver to each recipient
for (const recipient of recipients) {
await deliverAlert(alert, recipient, rule.channels)
}
// Schedule escalation if not acknowledged
await queue.add(
'check-alert-acknowledgment',
{ alertId: alert.id },
{ delay: rule.escalationDelayMinutes * 60 * 1000 }
)
}
queue.process('check-alert-acknowledgment', async (job) => {
const alert = await db.alerts.findUnique({ where: { id: job.data.alertId } })
if (!alert || alert.status === 'acknowledged') return
// Escalate — route to next level
const escalationRule = ESCALATION_RULES[alert.ruleId]
if (escalationRule) {
await escalateAlert(alert, escalationRule)
}
})
Real-time updates with WebSockets
Care coordinators monitor patient dashboards that need to update in real time as clinical events arrive. A coordinator watching 40 patients should see a new alert appear on the dashboard within seconds of the HL7 message arriving — not on the next page refresh.
We use Server-Sent Events (SSE) for the care coordinator dashboard real-time feed. SSE is simpler than WebSockets for one-directional server-to-client push, and the care coordinator interface is read-mostly with writes happening through explicit user actions.
// SSE endpoint — one connection per care coordinator
export async function GET(req: Request) {
const coordinatorId = await getAuthenticatedCoordinator(req)
if (!coordinatorId) return new Response('Unauthorized', { status: 401 })
const stream = new ReadableStream({
start(controller) {
const subscription = eventBus.subscribe(coordinatorId, (event) => {
controller.enqueue(\`data: \${JSON.stringify(event)}\n\n\`)
})
req.signal.addEventListener('abort', () => {
subscription.unsubscribe()
controller.close()
})
}
})
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
}
})
}

HIPAA-specific implementation details
Every piece of the care coordination platform operates under HIPAA's technical safeguards requirements. In practice for this specific system:
- All HL7 v2 messages are logged with the raw content for audit purposes, retained for 6 years
- Every alert delivery is logged with recipient, channel, timestamp, and whether it was acknowledged
- Patient records are only visible to care team members assigned to that patient — the system enforces this at the API layer, not just the UI layer
- All ePHI in transit is encrypted (TLS 1.3), all ePHI at rest is encrypted (AES-256 via RDS)
- Session tokens expire after 15 minutes of inactivity
- The HL7 message log is append-only and stored in a separate S3 bucket from operational data
Care coordination software at the level of reliability that clinical workflows require is genuinely complex to build. If you are planning a care coordination platform or a home health management system and want to understand the architecture before you start building, we have done this work and can help you get the foundation right.
Related service
Healthcare Software Development
HIPAA-compliant platforms, EMR integration, and care coordination tools for US home health agencies.
Written by
Founder & CEO
Gaurang Ghinaiya is the Founder & CEO of Nexios Technologies. He is passionate about building innovative software solutions that drive business growth. With years of experience in technology leadership, he guides teams toward excellence.
