Case study
One platform for three pharmacy brands.
A team-built React and Next.js pharmacy platform. I've been one of its engineers since November 2023: I built its multi-brand system, made most of its accessibility fixes, and wrote its Playwright test suites.
- Role
- Senior Software Engineer
- Since
- November 2023
- Focus
- Architecture · Frontend · Accessibility
- Stack
- Next.js · React · GraphQL · Zustand · MUI
What changed
Three brands that stay one platform.

HealthWarehouse
healthwarehouse.com (opens in a new tab)
SpringMeds
springmeds.com (opens in a new tab)
PharmcoRx
TBD
A rule the team builds by
A new brand is a config file
A redesign stays in its brand
The problem
Three brands, different in real ways.
Each brand has its own colors, typefaces, corners, features, and legal copy. The easy way to handle that is to copy a page and change it. Do that often enough and you have three apps.
The rule
Fork at the smallest unit.
A difference between brands goes to the smallest place that can hold it. Config holds data only. Anything that truly differs lives in the smallest per-brand component that can carry it.
A value
A color, a feature flag, the pharmacist's hours
goes toThe brand's config
Pharmacist hours: one shared component reads each brand's hours string.
Markup
A different sentence, or a different structure
goes toThe smallest per-brand component
Shipping copy: each brand writes its opening line; the sentence they share is its own file.
Behavior
What a component does, when only its layout differs
goes toStays shared, in a hook
The header: two layouts, one hook for sign-in, the mini-cart, and sign-out.
Picked when a brand is built
Kept honest by audit
Where it bent
The rule had boundaries.
PharmcoRx needed more than small forks could carry. These are the costs I accepted, and why.
Four forks are whole components
Every build carries every version
Fonts one brand uses
One build per brand
The test
PharmcoRx was the test.
It arrived in June 2026 as a config file, env files, and build scripts, with no structural change. Its redesign in September needed its own typefaces, corners, header, footer, and homepage, and the other two brands had to come out unchanged.
- 0 · Baseline
- 1 · Design system
- 2 · Header and footer
- 3 · Homepage
- 4 · Interior pages
- 5 · Content
- 6 · Re-measure
Big swings in the sweep were re-run on their own before I trusted them, and none held up. One gap was real, and it predated the redesign: in that measurement, PharmcoRx's mobile homepage took about 7 seconds to show its main image, against a 2.5-second target. The cause was placeholder photos, then still waiting on licensed ones.
Accessibility
What screen readers were actually told.
Audits kept finding markup that looked fine and told a screen reader something wrong. Two examples, from the fixes themselves.
The cart drawer, before and after
Before: four dialogs for one drawer
dialog“Shopping cart”
dialogno name
dialog“Your Shopping Cart”
dialognamed by a label that doesn’t exist
After: one dialog, named once
dialog“Shopping cart”
the cart’s heading and items
The menu's instructions, second attempt
Tried
Announce it when the menu opens
A live region spoke the keyboard instructions as the submenu opened.
Why it failed
Focus moved at the same moment
Focus jumping into the submenu raced the announcement, and JAWS and NVDA dropped it.
Shipped
Describe each item on focus
Each top-level menu item points to hidden instructions with aria-describedby, read on focus, before anything opens: “Press Enter or Space to open…”
Checked by tests, run by hand.
Playwright and axe-core scan every listed route, plus the states people reach through forms, dialogs, and checkout. The suites run by hand, not in CI, and the route script exits successfully even when a scan fails. Today they report problems; they don't block them.
The HealthWarehouse site also carries a third-party WCAG 2.2 accessibility seal.
- 42routes scanned by axe-core, in five browser and device profiles
- 210 / 210scans clean in the last recorded run, September 2026
- 83routes in the SEO regression suite
Next
What I'd change now.
Each of these was a deliberate call at the time. With another pass:
- Gate the suitesRun the accessibility suites in CI, and make the route script fail when a scan does.
- Cover every brandSpringMeds has no accessibility script of its own yet.
- Ship each brand only its own codeResolve per-brand components by filename at build time, the step deferred above.
- Fix the landmarksThe header and footer sit inside the main content area, so no brand exposes them as banner and footer landmarks. Found while adding tests; left for its own change.
Role
What was mine
- Builtthe brand system: the configs and the per-brand component helper.
- Establishedthe smallest-unit rule, which the team now follows when adding brand differences.
- RanPharmcoRx's redesign in seven measured phases.
- Movedthe app from the Pages Router to the App Router.
- Wrotethe Playwright and axe-core suites: routes, interaction flows, keyboard, and SEO.
- Fixedmost of the accessibility issues audits found; the form-error announcements were shared work with two teammates.
- Didmost of the frontend work on checkout and payments.
- Designedgovernance for AI-assisted development: repository contracts, decision logs, lifecycle hooks, and approval checkpoints.