The first mistake I see teams make is treating FHIR like a document format. They try to cram the whole chart into one place and then act surprised when every downstream workflow starts lying. The second mistake is more subtle: they model the current state correctly, but they throw away the path that got them there. In healthcare, the path matters. A medication was prescribed, then discontinued, then restarted. A problem was suspected, then ruled out, then re-entered by another source. If you only keep the latest value, you lose the clinical story.
That is why I design a longitudinal patient record around a few immovable rules: identity must be stable, history must be append-first, provenance must travel with the data, and every update must preserve the previous fact instead of silently replacing it. FHIR gives you the pieces, but it does not force the architecture. You have to decide which resource owns truth for each slice of the record and how those slices bind together over time.
At AST, this comes up constantly when we are integrating HL7v2 feeds, EHR exports, and FHIR APIs into the same clinical timeline. The trap is always the same: one source says the patient has hypertension, another says the diagnosis was removed, and a third source reasserts it six months later. If your design assumes one master record per concept with no lineage, you lose the ability to say which source introduced the fact and when it changed.
My rule is simple: never confuse presentation with record architecture. A patient chart can present as one timeline, but under the hood it should be a set of linked resources that can be merged, superseded, and queried by context. That means I can show a clinician the latest medication list while still preserving the exact MedicationRequest that originally justified it, the stop order that discontinued it, and the provenance that shows where each event came from.
How I model the patient spine
The spine starts with Patient, but it does not end there. Patient is the identity anchor, not the chart itself. I use it to hold demographic truth that changes slowly: identifiers, name history, birth date, gender, communication preferences, and links to external MRNs or enterprise MPI references. I do not store volatile clinical state there. That is where designs go to die.
From there, I bind the rest of the record to the patient through references and temporal context:
- Encounter for bounded moments of care, including where and when the interaction happened.
- Observation for measurements, results, and point-in-time clinical facts.
- Condition for problem list semantics and persistence over time.
- MedicationRequest for intended therapy and clinician order intent.
- MedicationStatement for what the patient is actually taking or reporting.
- Procedure for done events with operational or clinical significance.
- DocumentReference for source artifacts that should not be flattened away.
- Provenance for who asserted the data, from what source, and through what transform.
The important part is not the list. It is the relationship discipline. I want each resource to answer one question cleanly. If a lab result changes later, I do not mutate the original Observation in place and pretend nothing happened. I create a new version, keep a timestamped chain, and make it possible to explain why the visible state changed. This is where FHIR’s versioning and provenance support become architectural tools instead of theoretical features.
Design the timeline around state transitions
The timeline is where longitudinal design either works or collapses. I do not model time as a display concern. I model it as the primary organizing principle for the resources. Every resource that represents a clinical fact should have a clear answer to one of three questions: when was this observed, when was it in effect, or when was it asserted?
That distinction matters more than people think. An Observation has an effectiveDateTime or period because it describes what was true at a moment. A Condition has onset and abatement because it persists across a span. A MedicationRequest captures when intent began, while a MedicationStatement can show adherence or use over time. If you flatten those into one generic date field, you will eventually break reporting, reconciliation, or both.
In practice, I create a timeline engine that can sort resources by semantic time, not just by resource create timestamp. That means the UI can show:
- Observed time when the clinical fact was measured or noticed.
- Effective time when the fact mattered clinically.
- Recorded time when the system learned of the fact.
- Version time when the fact changed inside the record.
This sounds academic until you have a discharge med list arrive three days late, or a lab interface resend a corrected result after a provisional value was already displayed. Then the difference becomes everything. If you do not preserve both timing and lineage, the chart looks neat and is medically wrong.
What I use for identity, merges, and duplicates
Identity is where longitudinal records get ugly. Every real integration ends up with duplicates, near-duplicates, temporary IDs, legacy MRNs, and cross-system person records that never agree perfectly. I have watched teams pretend this is a front-end problem. It is not. If you cannot resolve identity cleanly, every downstream patient timeline becomes a probabilistic guess.
Here is how I approach it:
- Use one internal canonical patient identifier and map external identifiers onto it instead of letting every source become a competing authority.
- Keep every source identifier in Patient.identifier with system scoping so the record stays traceable.
- Track merges explicitly and preserve the old identifiers as historical references rather than deleting them.
- Do not collapse uncertain matches too early; hold them in review until the match confidence and operational policy both support the merge.
- Emit Provenance for identity changes so downstream consumers know whether a merge was manual, algorithmic, or source-driven.
The friction point here is that clean identity feels slower at first. Teams want a fast match and a pretty chart. I have seen that shortcut create a worse problem: a bad merge that spreads everywhere and is painful to unwind. One wrong patient link can poison allergies, meds, results, and billing-facing exports all at once. That is not an edge case. That is the business.
At AST, when we wire FHIR into live clinical workflows, we treat merge events like data migrations, not casual updates. If an MPI decision changes the canonical patient, we preserve the before state, record the after state, and make the change machine-readable. The chart should show continuity, but the system should never forget that an identity transition happened.
Resource patterns that actually hold up
There are a few patterns I keep using because they survive real production traffic better than cleverness.
| Need | Resource pattern | Why it works |
|---|---|---|
| Current problem list | Condition with status and history | Keeps active vs resolved separate and supports chronology |
| Medication history | MedicationRequest plus MedicationStatement | Separates prescriber intent from patient-reported use |
| Lab timeline | Observation with versions and provenance | Lets provisional, corrected, and final results coexist |
| Source artifact retention | DocumentReference with linked resources | Preserves original clinical context without flattening |
| Trust and traceability | Provenance plus AuditEvent | Shows who changed what, when, and through which path |
The table is the architecture. The exact implementation depends on your source systems, but the pattern does not change. If a clinical fact is something that can be corrected later, I expect versioning. If it is something that should be visible in the chart but not treated as canonical evidence, I keep the source artifact and link it rather than normalize it beyond recognition.
That last point is where teams overcook the design. They want every item to become a perfect normalized record. That is a mistake. Some things are better preserved as source documents with a link into the longitudinal graph. FHIR can do both, and the best systems use both.
How AST structures the ingestion path
When AST builds a longitudinal record pipeline, I keep the transformation layers boring on purpose. That is a compliment. Boring pipelines survive. We usually land on a pattern where source interfaces flow into a canonical FHIR R4 core, then downstream services project the data for charting, analytics, exchange, or workflow triggers. The canonical layer is where the record discipline lives.
The biggest mistake I made early on was trying to normalize too much at ingest time. I wanted every inbound message to be perfect before it touched the core. That sounds responsible. It is not. It makes the system brittle, slows the pipeline, and hides source truth. Now I prefer a two-step approach:
- Land the source as-is Keep the raw message, payload, or document reference so you can explain the origin later.
- Map into canonical FHIR Convert to the narrowest valid resource set that represents the clinical fact without inventing meaning.
- Attach provenance immediately Record source system, transform logic, timestamps, and actor context before anything is displayed.
- Version explicitly Create new versions for corrected or superseding facts instead of editing history away.
- Project views from the graph Build patient charts, registries, and feeds from the underlying record instead of mutating the core for each use case.
This is also where FHIR endpoints, HL7v2 feeds, and vendor APIs need to coexist cleanly. I have had to bridge older admissions/discharge feeds into a longitudinal record that also listens to modern FHIR updates and file-based imports. If the architecture assumes one transport forever, it will crack the first time a vendor changes how they expose a data class. The record cannot be hostage to transport fashion.
If you want a deeper view of how we think about these integrations, I keep the FHIR side anchored around integration architecture instead of one-off interfaces. That distinction matters. One-off interfaces solve today. Architecture survives the next vendor change.
What I refuse to compromise on
There are four things I will not trade away in a longitudinal record:
- Traceability Every important fact needs a source and a path.
- Temporal honesty Time should mean the same thing everywhere in the model.
- Historical visibility Old values should remain explainable, not discarded.
- Bounded responsibility Each resource should own a specific clinical truth, not all truths.
That keeps the record usable by clinicians, integration engines, and analytics teams. It also keeps you out of the trap where the chart is easy to read but impossible to trust. I have lived through both versions. The second one is always more expensive.
If you are designing this in a live EHR integration stack, I would start with the questions the chart must answer under pressure, not with the resource list. Once the failure modes are clear, the FHIR model gets much easier. If you want to see how AST approaches this kind of production integration work, our guides are the right place to start.
Build a FHIR record that tells the truth over time
If your longitudinal record cannot explain merges, corrections, provenance, and source context, it will fail the first real reconciliation. I build these systems to survive live feeds, messy identities, and changing clinical facts without flattening the history away.





Comments
Comments are warming up. Live, no-sign-in discussion will appear here shortly.
Have a question now? Email info@allstartech.net.