Case study · Global Healthcare division of a multinational pharma client

Four years, three regulated platforms, the features other people route around.

Across four years at a global pharmaceutical client (via 3|Share) I delivered the complex frontend on three regulated healthcare platforms built on AEM and Vue: a patient-facing clinical-trial finder; an HCP medical-information portal; and an adverse-event reporting system. Delivery-heavy contracting in established, compliance-bound codebases — where the hard part is the constraints, not the framework.

Role
Senior frontend, primary hands-on engineer (via 3|Share)
Stage
2021–2025
Scale
3 platforms · ~400 tickets on the patient platform alone
Stack
Vue 2/3, Pinia, Vuetify, Lit, AEM, Solr, AWS

·

Search across three contexts that didn't want to agree

On the HCP medical-information portal I owned search and discovery: a Solr-backed single-page search with faceted filtering across publications, clinical trials, congress programmes and medical information. The catch was that three separate search contexts shared one navigation UI, each with its own result counts and parameters. I reconciled them through a redesigned Vuex state with deep-linkable parameters, so a filtered search is a shareable URL and the counts stay honest as a user moves between contexts.

A strict CSP that broke Vue's compiler

The adverse-event reporting system ran under an enterprise Content Security Policy that banned eval and new Function — which is exactly how Vue's default build compiles templates at runtime. The app simply wouldn't run. I refactored it to the runtime-only build with regex-based label handling and webpack code-splitting, and migrated the whole system Vue 2 to Vue 3 in the same effort, with zero functionality lost. This is the kind of constraint that doesn't show up in a job spec but decides whether the thing ships.

Why these are the interesting ones: none of them are "build a component". They're a search domain with three masters, a security policy at war with the framework, and an accessibility bar set by a regulator. The framework is the easy part.

An accessible mirror of a component I couldn't replace

The patient platform used a third-party Select2 control that announced blank or duplicated entries in NVDA — a real barrier on a patient-facing healthcare product, and one I couldn't fix by swapping the library out. So I built a parallel, ARIA-correct listbox that mirrored the Select2 state plus a live region to announce changes properly. The visible control stayed; the accessibility tree became correct underneath it.

Authenticated bookmarking on a legacy store

Patients needed to save clinical trials across sessions. I wired the platform's legacy Vuex store to AWS DynamoDB and Cognito, with event-driven state sync so a bookmark made on one page is consistent everywhere without a full reload. Dual-branded across the parent and a US partner brand, multi-country, so the same flow had to behave under several configurations.

oneDataLayer: analytics without per-component JavaScript

The global pharmaceutical client's global clinical-trials platform needed consistent analytics across page views, clicks, scroll depth, search and OneTrust consent. Rather than scatter tracking through every component, I built oneDataLayer: a single TypeScript class that AEM components opt into via one data attribute. No per-component JS, a flat client footprint at scale, and one place to reason about consent. It's my go-to architecture-decision story for a reason — it traded a thousand small integrations for one contract.

  • Vue 2 / Vue 3
  • Pinia / Vuex
  • Vuetify 3
  • Lit atoms
  • TypeScript
  • AEM
  • Solr
  • AWS DynamoDB
  • AWS Cognito
  • OneTrust
  • WCAG 2.2 AA
  • NVDA / VoiceOver
  • axe-core
  • GitLab CI
  • reCAPTCHA v2

Accessibility you can defend to a regulator

I led WCAG remediation across the three platforms ahead of the June 2025 EU Accessibility Act deadline, as the primary hands-on engineer working alongside an external accessibility auditor. That meant reusable modal focus-traps, a WAI-ARIA combobox built from scratch with dual live regions and managed aria-activedescendant, NVDA-specific fixes, and skip links — validated against real screen readers, not just lint rules. It's one credential among several here, but it's the one with a legal deadline attached.

Back to selected work  ·  See: the enterprise SaaS codegen pipeline  ·  Talk to me about a similar project