A platform that logs why each value changed and checks permissions on every service call.
This patient data management case study describes a data layer for clinical records. The records stay usable as forms and programmes change. A shared concept dictionary sets out what each form and observation captures, so each programme can use its own terms inside the shared model. Clinician screens and API modules call those same services.
The challenge
Correcting an observation should leave behind a record of exactly what was changed and why. If the service simply overwrote the value, the original entry would be lost. A second interface brings its own risk. Permissions checked on the first screen do not cover a request that arrives through a module.
What we built
The platform holds patient identities and the links between them. The clinical record itself covers visits and encounters, with the observations and orders logged during each one.
Saving an encounter checks edit rights, assigns a visit when one is needed, and stores the related orders and observations. Inherited patient, date and location values stay in line with the encounter they belong to. An inbound HL7 queue accepts laboratory and admission messages.
A correction creates a record
An existing observation cannot be saved without a change message. When the clinical value changes, the service adds a replacement and voids the earlier observation, keeping the reason on record. Both versions stay in the encounter history. Interceptors block direct edits that try to skip this path, and orders use linked revisions.
Permissions belong to the operation
Service calls enforce roles and privileges. Object-level rules add finer control, and masking can show that a record was withheld rather than leaving an unexplained gap. An external interface still needs its own check on the service path.
Committed changes remain available to integrations
Entity events are saved as outbox records in the same database transaction as the clinical data. A later process publishes them through the configured integration. If it halts after the commit, the outbox keeps the pending work.
Each deployment uses one database, where location and record permissions organise access without creating separate customer tenants.
Project success
A reviewer can tell an original observation from its correction and read the recorded reason. Modules can call the same patient and encounter operations, permission checks included. Each programme still defines the terms it needs. Through the outbox, integrations receive the recorded change and can act on it in their own flow.
Technology stack
Application
Java, Spring
Persistence
Hibernate, Envers, Liquibase
Database
MariaDB with supported deployment alternatives
Runtime and scheduling
Tomcat, JobRunr
Supporting services
Infinispan, local or S3 storage, HL7 v2
Other engagements
Recognize the pattern?
If one of these looks like your situation, the discovery call is where we find out how close.