Case Study

FHIR Integration for Clinical Data: Access Policies and a Local Message Queue

A FHIR-based application backend with record access policies, version history and links to existing clinical systems.

This FHIR integration case study links clinical apps to the hospital systems already in place. A backend stores the FHIR R4 resources. The apps call its record and access services, while an on-site agent takes in HL7 v2 messages over MLLP and supports DICOM links too.

Automation on the server can turn incoming HL7 content into the same resource model the app already uses.

The challenge

Updating a clinical record touches more than its main fields. The same change also moves its searchable fields, its version history and its access metadata. All of those have to stay in step. A caller who edits an older version needs a clear refusal once another update has already changed the record.

Incoming hospital messages bring a different risk. The link to the backend may be down, so the agent has to hold the work nearby until it can send it on.

What we built

The data service creates, updates and searches resources. It also returns their history and handles the transaction bundles a caller submits. Policies can limit resource types, hide certain fields or mark them read-only for a given caller. Project and compartment details then feed those access decisions.

After a save succeeds, a subscription can trigger automation or send a webhook. The apps sign in through OAuth2 and OpenID Connect, with SMART on FHIR and multifactor support in place.

Save the record and its history together

The write path checks access, validates the resource and attaches version metadata. PostgreSQL then saves the resource, its history entry and the search entries in one transaction. A conditional update supplies the version the caller expects. If the versions differ, the caller gets a precondition failure and the stored record stays as it was.

Read-only values are restored from the stored record before the final check. An incoming payload therefore cannot change them along that path. FHIR searches read from dedicated resource tables, backed by lookup tables for values such as names and codes.

Hold incoming messages locally

The agent writes the original and prepared message data to SQLite before sending, using write-ahead logging. Channel and message-control identifiers let it spot duplicates. On a sequenced channel, adding the message and advancing its counter share one transaction. A failed insert leaves the sequence number free for the next try.

Saved messages stay queued while the backend link is down, and the agent reconnects as soon as it can. Automation may call an external function runtime. The built-in VM suits trusted code, and it is not treated as an isolation boundary for arbitrary code.

Project success

Edits from the client's software and changes from the integrations run through the same access and version checks. Earlier resource versions stay available to inspect. The local queue holds any messages still waiting to be sent. The client can now link its clinical app to existing systems, and no single screen has to receive messages or manage record history itself.

Technology stack

Application

TypeScript, Node.js, Express

Clinical interface

FHIR R4, GraphQL

Main data store

PostgreSQL

Local message queue

SQLite, write-ahead logging

Background processing

Redis, BullMQ

Application components

React

Integration standards

HL7 v2, MLLP, DICOM

Recognize the pattern?

If one of these looks like your situation, the discovery call is where we find out how close.