Skip to main content

Longitudinal Patient Case Tracking

Many clinical scenarios span multiple visits over weeks, months, or years. A patient managing type 2 diabetes, for example, will have quarterly check-ups, lab orders, specialist referrals, and lifestyle interventions that all belong to the same ongoing case. A single Encounter captures one visit, but it cannot represent the full arc of care.

FHIR provides two complementary resources for grouping this longitudinal activity: EpisodeOfCare for administrative encounter grouping, and CarePlan for clinical planning. Together, they give you both the temporal grouping you need and the rich goal and activity context you want.

Key Concepts

EpisodeOfCare is intentionally lightweight. Its job is purely administrative grouping — it acts as an umbrella that encounters attach to. It tracks which organization is responsible for a patient's care during a period, and which conditions are being addressed. It does not capture clinical planning details like goals, activities, or care team assignments.

CarePlan handles the clinical layer. It defines treatment goals, scheduled activities, conditions being addressed, and care team members. A CarePlan sits alongside an EpisodeOfCare and provides the planning context that the episode intentionally omits.

A patient can have multiple concurrent episodes and care plans. For instance, one episode for diabetes management and another for a weight loss program, each with its own CarePlan. A single encounter (like a quarterly check-up) can be linked to multiple episodes through Encounter.episodeOfCare, which accepts an array of references.

Resource Overview

ResourceRoleDescription
EpisodeOfCareAdministrative groupingGroups encounters into a named care episode for a specific condition
CarePlanClinical protocolDefines goals, activities, and conditions for the treatment plan
EncounterVisit recordIndividual visit linked to one or more episodes
ConditionProblem / diagnosisThe clinical problem being tracked across the episode
GoalTreatment objectiveMeasurable target within a care plan

How the Resources Fit Together

All resources below reference the Patient. The diagram omits those references to focus on the relationships that matter for longitudinal tracking.

The key relationships are:

  • Encounters link to their episode via Encounter.episodeOfCare
  • Both EpisodeOfCare and CarePlan reference the same Condition resources, creating an implicit link through shared diagnoses
  • CarePlan.supportingInfo explicitly references the EpisodeOfCare, providing a direct link from plan to episode
  • Goal resources are referenced from the CarePlan via CarePlan.goal
Navigating between EpisodeOfCare and CarePlan

The supportingInfo link is one-directional: you can follow it from CarePlan to EpisodeOfCare, but there is no field on EpisodeOfCare that points back to a CarePlan. To navigate in the reverse direction (episode to plan), query by the shared Condition: CarePlan?condition=Condition/{id}. This is the natural clinical query — "show me all plans addressing this diagnosis" — and works regardless of how many episodes or plans reference that condition.

Creating an Episode of Care

An EpisodeOfCare represents an administrative period of care for a specific concern. Create one when a patient begins a new care episode, such as starting chronic disease management or entering a treatment program.

Key fields:

FieldPurpose
statusLifecycle state: planned, waitlist, active, onhold, finished, cancelled
patientReference to the patient
typeCategory of care being provided
diagnosisConditions being addressed, with optional role (chief complaint, comorbidity)
periodStart and optional end date of the episode
managingOrganizationOrganization responsible for the episode
const episode = await medplum.createResource({
resourceType: 'EpisodeOfCare',
status: 'active',
patient: {
reference: 'Patient/homer-simpson',
display: 'Homer Simpson',
},
type: [
{
coding: [
{
system: 'http://terminology.hl7.org/CodeSystem/episodeofcare-type',
code: 'hacc',
display: 'Home and Community Care',
},
],
},
],
diagnosis: [
{
condition: {
reference: 'Condition/diabetes-type-2',
display: 'Type 2 Diabetes Mellitus',
},
role: {
coding: [
{
system: 'http://terminology.hl7.org/CodeSystem/diagnosis-role',
code: 'CC',
display: 'Chief complaint',
},
],
},
},
],
period: {
start: '2024-01-15',
},
managingOrganization: {
reference: 'Organization/springfield-clinic',
display: 'Springfield Medical Clinic',
},
});
console.log(episode);

Linking Encounters to an Episode

When a patient has a visit related to an ongoing care episode, link the Encounter to the episode via Encounter.episodeOfCare. This field is an array, so a single encounter can belong to multiple episodes simultaneously. This is useful when a visit addresses more than one ongoing concern.

const encounter = await medplum.createResource({
resourceType: 'Encounter',
status: 'finished',
class: {
system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode',
code: 'AMB',
display: 'ambulatory',
},
subject: {
reference: 'Patient/homer-simpson',
display: 'Homer Simpson',
},
episodeOfCare: [{ reference: 'EpisodeOfCare/diabetes-episode' }, { reference: 'EpisodeOfCare/weight-loss-episode' }],
period: {
start: '2024-06-01T09:00:00Z',
end: '2024-06-01T09:30:00Z',
},
});
console.log(encounter);

In this example, the encounter is linked to both a diabetes episode and a weight loss episode, reflecting that both concerns were addressed during the same visit.

You are not limited to encounters that already took place. Link future visits to an episode by creating encounters in advance and pointing Encounter.episodeOfCare at the EpisodeOfCare. Use Encounter.status (for example planned) to record that the encounter is scheduled or not yet started, in line with FHIR’s encounter lifecycle.

Creating a Care Plan with Goals

While the EpisodeOfCare groups encounters, the CarePlan captures what should happen clinically. Start by creating Goal resources for the treatment objectives, then reference them from the CarePlan.

Creating a Goal

const goal = await medplum.createResource({
resourceType: 'Goal',
lifecycleStatus: 'active',
description: {
text: 'Maintain HbA1c below 7%',
},
subject: {
reference: 'Patient/homer-simpson',
display: 'Homer Simpson',
},
target: [
{
measure: {
coding: [
{
system: 'http://loinc.org',
code: '4548-4',
display: 'Hemoglobin A1c/Hemoglobin.total in Blood',
},
],
},
detailQuantity: {
value: 7,
unit: '%',
system: 'http://unitsofmeasure.org',
code: '%',
},
},
],
});
console.log(goal);

Creating the Care Plan

The CarePlan brings together the condition being addressed, the goals to achieve, scheduled activities, and a reference to the associated EpisodeOfCare via supportingInfo.

const carePlan = await medplum.createResource({
resourceType: 'CarePlan',
status: 'active',
intent: 'plan',
title: 'Diabetes Management Plan',
subject: {
reference: 'Patient/homer-simpson',
display: 'Homer Simpson',
},
addresses: [
{
reference: 'Condition/diabetes-type-2',
display: 'Type 2 Diabetes Mellitus',
},
],
goal: [
{
reference: 'Goal/hba1c-goal',
display: 'Maintain HbA1c below 7%',
},
],
activity: [
{
detail: {
kind: 'ServiceRequest',
code: {
coding: [
{
system: 'http://loinc.org',
code: '4548-4',
display: 'Hemoglobin A1c',
},
],
},
description: 'Quarterly HbA1c lab test',
status: 'scheduled',
scheduledPeriod: {
start: '2024-07-01',
},
},
},
],
supportingInfo: [
{
reference: 'EpisodeOfCare/diabetes-episode',
display: 'Diabetes Management Episode',
},
],
});
console.log(carePlan);
tip

CarePlan.supportingInfo accepts Reference<Resource>[], making it flexible enough to reference an EpisodeOfCare, related documents, or any other supporting resource.

Cross-Linking EpisodeOfCare and CarePlan

FHIR R4 does not provide a direct field on EpisodeOfCare that points to a CarePlan, so the link between them is asymmetric. The recommended pattern uses two complementary strategies:

  1. CarePlan.supportingInfo directly references the EpisodeOfCare. This gives you an explicit, unambiguous pointer when reading a CarePlan — follow supportingInfo to find the episode it belongs to.
  2. Both resources reference the same Condition resources (EpisodeOfCare.diagnosis.condition and CarePlan.addresses). This shared condition serves as the queryable link in the reverse direction: starting from an EpisodeOfCare, read its conditions and then search CarePlan?condition=Condition/{id} to find the associated plans.
DirectionHow to navigate
CarePlan → EpisodeOfCareFollow CarePlan.supportingInfo directly
EpisodeOfCare → CarePlanQuery CarePlan?condition={shared-condition-id}

Together, these two strategies cover both navigation directions. The supportingInfo pointer is explicit and fast for single-resource reads; the shared Condition query handles the reverse direction and is the natural clinical question ("what plans address this diagnosis?").

Querying Longitudinal Data

Finding All Encounters for an Episode

Retrieve every visit associated with a care episode using the episode-of-care search parameter on Encounter.

const encounters = await medplum.searchResources('Encounter', 'episode-of-care=EpisodeOfCare/diabetes-episode');
console.log(encounters);

Finding Care Plans for a Condition

Find all care plans addressing a specific condition for a patient.

const carePlans = await medplum.searchResources(
'CarePlan',
'patient=Patient/homer-simpson&condition=Condition/diabetes-type-2'
);
console.log(carePlans);

Finding All Episodes for a Patient

List all active care episodes for a patient to see their ongoing cases at a glance.

const episodes = await medplum.searchResources('EpisodeOfCare', 'patient=Patient/homer-simpson&status=active');
console.log(episodes);

Example: Concurrent Care Episodes

Consider a patient, Homer Simpson, who is managing two ongoing concerns: type 2 diabetes and a weight loss program. Each concern has its own EpisodeOfCare and CarePlan, but some visits address both.

All resources reference Patient: Homer Simpson. Those references are omitted below to keep the diagram focused.

In this setup:

  • Each concern has its own EpisodeOfCare, Condition, CarePlan, and Goal
  • The Q2 check-up Encounter is linked to both episodes because both concerns were addressed during that visit
  • To get the full picture of Homer's diabetes care, query Encounter?episode-of-care=EpisodeOfCare/diabetes-episode for all visits, and CarePlan?condition=Condition/diabetes-type-2 for the treatment plan
  • To see all of Homer's active cases, query EpisodeOfCare?patient=Patient/homer-simpson&status=active

See Also