Skip to content
← All work

FHIR R4 interoperability hub & SMART on FHIR clinician platform

Syndeora

A Java 21 / Spring Boot 3 healthcare integration hub that turns HL7 v2 feeds and C-CDA documents into validated FHIR R4 records, with patient matching, consent, CDS alerts and SMART apps.

My role: Healthcare integration and platform engineer: architecture, Java microservices, security and React apps

Discuss a similar project
  • Java 21
  • Spring Boot 3
  • HAPI FHIR R4
  • HL7 v2
  • Keycloak
Screenshot of Syndeora, fhir r4 interoperability hub & smart on fhir clinician platform, built by Anshuman Verma

Overview

Health systems run on fragmented data: emergency admissions arrive as legacy HL7 v2 messages over MLLP sockets, discharge summaries as C-CDA XML, and modern clinical apps expect SMART on FHIR R4 APIs. Syndeora ingests the legacy feeds and documents, normalises vocabularies, resolves patient identity with a probabilistic Master Patient Index, enforces consent with an audited break-the-glass override, and exposes one FHIR R4 record to SMART clinician apps and CDS Hooks decision support.

The challenge

Hospitals rarely have one clean source of patient data. Admissions and lab results arrive as HL7 v2 messages over raw TCP sockets, discharge summaries as C-CDA XML documents, and each system uses its own codes and patient identifiers. Clinicians end up with partial records, duplicate patients and no reliable view of where a fact came from.

Syndeora had to accept all of those feeds safely, work out which records belong to the same person without ever wrongly merging two people, respect each patient's consent while still allowing emergency access, and present one trustworthy FHIR R4 record to clinician apps and decision support.

How it works

  1. 1HL7 v2 / C-CDA / FHIR in
  2. 2Interface engine & importer
  3. 3Terminology mapping
  4. 4Master Patient Index
  5. 5FHIR R4 store (consent, audit)
  6. 6SMART apps + CDS Hooks

Architecture

The platform is a set of Java 21 / Spring Boot 3 microservices around a HAPI FHIR R4 JPA server on PostgreSQL 16. The interface engine is a Netty server on TCP 2575 that frames MLLP messages, replies with HL7 ACK or NACK matched to the control ID, maps admission, discharge, update, merge and lab-result messages, and sends anything malformed to a RabbitMQ dead-letter queue that operators can replay. The C-CDA importer parses R2.1 documents with XPath into Conditions, Medications, Allergies and Observations, deduplicating with SHA-256 fingerprints of the clinical content.

Every inbound record passes through a terminology service ($translate and $lookup to LOINC, SNOMED CT, ICD-10 and RxNorm, with Jaccard suggestions for unmapped codes) and a Master Patient Index that applies Fellegi-Sunter weights across national ID, phone, birth date and phonetically normalised names. Scores of 70 and above link automatically, 40 to 70 go to a human review queue, and lower scores create a new identity. Inside the FHIR server, custom profiles validate resources, a provenance engine records where each fact came from, a consent interceptor enforces purpose-of-use rules, and an AuditEvent interceptor writes a tamper-evident log, including every break-the-glass override.

Keycloak 24 provides OAuth2 and SMART App Launch 2.0 with patient-compartment scopes. A CDS Hooks v1.0 service returns hyperkalemia and drug-allergy cards, and an AI assistant extracts FHIR resources from dictated notes with confidence scores and evidence quotes. Two React 18 TypeScript apps serve clinicians (timeline, lab trends, provenance, break-the-glass) and integration engineers (live MLLP monitor, message inspector and replay, terminology approval, MPI review). Fourteen containers run under Docker Compose with health probes, Prometheus and Grafana.

What I built

HL7 v2 MLLP interface engine

A Netty socket server on TCP 2575 handles MLLP framing, returns ACK/NACK matched to the inbound control ID, maps ADT^A01/A03/A04/A08/A40 and ORU^R01, and routes malformed messages to a RabbitMQ poison queue with replay.

Probabilistic Master Patient Index

Fellegi-Sunter record linkage with DoubleMetaphone and Jaro-Winkler handles transliterations and typos, with auto-link, human-review and new-identity tiers; integration tests show zero false auto-links.

Terminology and C-CDA import

$translate and $lookup map local codes to LOINC, SNOMED CT, ICD-10 and RxNorm with Jaccard suggestions for unmapped codes; an XPath C-CDA R2.1 importer uses SHA-256 clinical fingerprints so re-imports never duplicate records.

Consent and break-the-glass

An interceptor enforces patient Consent by purpose (treatment vs research) and sensitivity; clinicians can override in an emergency with a stated reason, recorded as an elevated FHIR AuditEvent.

CDS Hooks decision support

A CDS Hooks v1.0 service raises critical cards for hyperkalemia (potassium above 6.0 mmol/L) and checks proposed medication orders against recorded allergies.

SMART apps and AI assistant

React 18 clinician and operations apps with a longitudinal timeline, LOINC lab trends, provenance drawer, MLLP monitor and MPI review queue; an AI assistant turns dictated notes into FHIR resources with confidence scores and evidence quotes.

Engineering decisions

  • Acknowledge every HL7 message immediately and divert anything unparseable to a poison queue, so one bad message never blocks a hospital feed.
  • Send ambiguous patient matches to human review rather than auto-linking, because a wrong merge in healthcare is worse than a duplicate.
  • Fingerprint clinical content with SHA-256 so re-imported documents are idempotent.
  • Allow emergency access but make it explicit and audited, rather than blocking care or silently bypassing consent.

Results

  • Zero false patient auto-links across the MPI integration test suite.
  • Idempotent C-CDA re-imports through SHA-256 clinical fingerprints.
  • All 9 Maven modules passing, with strict TypeScript in both frontends.
  • 11 architectural decisions documented, across a 14-container deployment.

Stack

Backend
Java 21, Spring Boot 3.3, HAPI FHIR R4 7.4, Spring Security 6
Messaging
Netty 4 (MLLP), RabbitMQ 3.13 dead-letter queues
Data
PostgreSQL 16, Spring Data JPA, Hibernate 6
Security
Keycloak 24, OAuth2 / OIDC, SMART App Launch 2.0, Consent and AuditEvent interceptors
Frontend
React 18, TypeScript, Vite, Tailwind CSS
Ops
Docker Compose (14 containers), Prometheus, Grafana, Spring Boot Actuator; 9 Maven modules passing

Related services

Need something like this?

I can build a version of this for your product, your data and your stack.

Start a project