Raj Ostawal/Patient Portal

Product design and frontend · Patient portal

Merging 3 hospital record systems into 1 patient portal

How AdventHealth moved 250,000 patients onto a single health record across web, iOS and Android, without anyone losing access mid-migration.

Role
Product Designer
Partner
AdventHealth × Purple Rock Scissors
Platforms
Web, iOS, Android
Timeline
Jan 2025 to Mar 2026

The challenge

Three record systems, one experience, zero room for error

After a system-wide rebrand, AdventHealth needed to move its entire patient portal onto Epic, the largest electronic health record platform in the US, while three legacy systems (NextGen, Cerner, Athena) were still live.

The hard part was continuity. Patients had to keep reaching their records, bills and appointments throughout a multi-year, region by region cutover. I worked inside the AdventHealth team alongside the agency, owning design for the patient-facing flows where data from different systems had to feel like one product, and building the frontend components those flows ran on.

250KOnline patients on the platform
3 in 1EHR systems consolidated into one
40+New portal features designed and built
3Platforms: web, iOS, Android

The core problem

A patient does not care which system their data lives in

Behind the portal, a single patient's records could be split across multiple record systems, with duplicate entries, overlapping appointments, and bills grouped differently in each one.

My job was to hide that complexity. The design had to present one clear timeline of visits, one consolidated set of bills, and one accurate record, even while the data underneath was being de-duplicated and migrated.

Design principle: the patient should never see the seams between systems.

Billing overview with grouped billing accounts, alongside past visits and a most recent vitals card showing heart rate, blood pressure and weight.
Consolidated billing and health data, pulled from multiple source systems into one view.

Ideation and information architecture

Reducing a sprawling portal to four jobs

Early on, the portal risked becoming a dumping ground, every feature the three legacy systems offered, bolted together. Before designing screens, I worked with product owners to map what patients actually came to do, and collapsed dozens of scattered entry points into four core jobs that became the backbone of the information architecture.

See my healthRecords, vitals, results, medications, all consolidated
Get careFind a doctor, see a provider, start a video visit
Manage visitsConfirm, reschedule and prepare for appointments
Handle billingGrouped bills, payment plans, financing
Map jobs, not featuresWe sorted every legacy feature against a real patient task. Anything that did not map to a job was cut or merged.
One IA across platformsThe same four-job structure had to hold on a phone and a desktop, so navigation stayed predictable everywhere.

Wireframing

Pressure-testing the structure in low fidelity first

Before any visual design, I wireframed the highest-stakes flows to test hierarchy and confirm each screen worked with incomplete or still-syncing data. The goal was to settle structure cheaply, so high-fidelity design could focus on clarity and trust.

Low fidelity wireframes for billing, visits and health data on mobile, plus a patient portal home layout for desktop.
Each screen had to answer four questions before it earned any visual polish: what is this, what matters first, what can I do, and what happens when the data is missing.

The approach

Design for backward compatibility first

Because regions cut over to Epic at different times, the portal had to run on all systems at once during the transition. Every screen had to render correctly whether a patient's data came from Epic or a legacy system, and surface the right data as regions switched over.

The unified portal home on desktop and mobile, with logos for Epic, athenahealth, Cerner and NextGen beneath.
The unified home on web and mobile, drawing from four record systems during the rolling migration.

Building it

The seam had to be closed in code, not just in the mockup

A design principle like "never show the seams" only survives contact with production if the frontend enforces it. Alongside the design work I built the component layer these flows ran on, which meant the normalization problem landed on my side of the stack too.

Four record systems returned the same clinical concept in four shapes: different field names, different date formats, different identifiers for the same human being. Rather than let that leak into components, every source was mapped to one internal view model at the boundary, so a card rendering a visit never had to know where the visit came from.

That single decision is what made the four-job architecture hold. Components stayed dumb and reusable, and the messy part stayed in one testable place.

Diagram showing NextGen, Cerner, Athena and Epic feeding a normalization layer of record matching, feature rules and cutover logic, which outputs unified portal surfaces.
Four sources, one normalization layer, one set of portal surfaces.
A component layer built for reuse

Reusable adaptive components backed a shared frontend system spanning 1,200 facilities. New features extended existing patterns instead of introducing new ones, which is the only way 40+ features ship without the product fragmenting.

States as a first-class concern

Mid-migration data is rarely clean. Every component handled loading, partially synced, missing, duplicated and permission-restricted states explicitly, because an empty field in a health record reads as alarming rather than merely absent.

Parity across three platforms

The same mental model had to hold on web, iOS and Android. Shared patterns and a single source of truth for layout rules kept the platforms from drifting as teams shipped in parallel.

Accessibility checked, not assumed

Contrast, focus order, tap targets and keyboard behaviour were verified against WCAG 2.1 AA during handoff and design QA, on flows where a misread number is a safety problem.

typescriptillustrative
// Every source system resolved to one shape before it reached a component,
// so a VisitCard never had to branch on where the visit came from.
type Source = "epic" | "cerner" | "athena" | "nextgen";

type Visit = {
  id: string;
  date: Date;
  provider: { name: string; specialty?: string };
  location: string;
  source: Source;              // kept, because provenance is trust
  status: "confirmed" | "pending" | "syncing" | "unavailable";
};

export function toVisit(raw: unknown, source: Source): Visit | null {
  const parsed = adapters[source].safeParse(raw);
  if (!parsed.success) return null;   // drop it, never half-render it
  return { ...parsed.data, source };
}

// De-duplication ran on the normalized shape, not per source.
export const dedupe = (visits: Visit[]) =>
  [...new Map(visits.map((v) => [visitKey(v), preferEpic(v)])).values()];

Production code from a healthcare platform is not mine to publish. This is the pattern reconstructed, to show the shape of the problem rather than the original source.

The work

40+ features, designed to feel like one product

Mobile screens for health data, care team, appointment detail and medication refills.
Health data, care team, appointment detail and medication refills across the mobile portal.

I designed and built flows across the portal's core jobs: consolidated health data, care-team management, appointment confirm and reschedule, and medication refills.

Each had to handle the messy reality underneath, missing fields, data still syncing, records from different sources, with clear states so patients always knew what was current.

Share My RecordProxy access, visit summaries, radiology reports
Bill PayGrouped bills, payment plans, paperless, financing

A closer look

Making the next step obvious, whatever the need

"Get Care" was the portal's front door for action. The challenge was reducing a sprawling set of options, find a doctor, see a provider, start a video visit, schedule tests, into a few clear, confident entry points.

I designed these as a simple decision layer with strong visual hierarchy, then carried the same pattern across web and mobile for consistency.

Working within an established design system meant every new feature extended existing patterns rather than reinventing them.

Get Care entry points showing find a doctor, see your doctor and video visit options alongside the care team.
Get Care entry points: find a doctor, see your provider, or start a video visit.

Working at scale

Design across 20 business units, six product owners, one system

This was a program, not a project. Designing inside it meant keeping patient-facing flows consistent while engineering rewired the data layer underneath, across a multi-year, region by region rollout.

20KProject hours across the program
25Team members across design and engineering
20Business units coordinated
6Product owners with independent workstreams

Impact

A portal that held together through a multi-year migration

The redesigned portal launched across AdventHealth's regions on a rolling, two-year timeline, giving 250,000 patients continuous access to records, billing and appointments while three legacy systems consolidated into Epic behind the scenes. Behavioural data from more than 50,000 sessions fed back into onboarding, which started from a 171 second baseline.

What I took away

The hardest problems here were invisible to the patient by design. Working at the scale of a live migration taught me that in regulated, high-stakes systems the best design decision is often the one that makes complexity disappear: clear states, consistent patterns, and a single source of truth the user can trust. It also taught me that a principle like "hide the seams" is a frontend commitment as much as a design one. Designing for data that is mid-migration is a discipline I now carry into every data-heavy product, including the agent interfaces I build today.

Next project
Turning 796 hospital websites into one place to find care

Public project metrics and scope are based on the published AdventHealth Epic case study. Screens shown are from project materials. The code sample is illustrative, written to show the pattern rather than reproduce proprietary source.