Client
A workers' compensation carrier
Year
2023—25
Role
Software Engineer II
Stack
- React Native
- Expo
- TypeScript
- Tamagui
- TanStack Query
- Codemagic
- CodePush
- Sentry
A workers' compensation carrier whose employees did everything by phone call and paper form. I was one of two core engineers on the mobile app that replaced it — accident reports, direct deposit, timesheets, payroll history, in English or Spanish — and on the white-label platform it became, shipping as a separate branded app for each carrier on it.
3 brands
shipped from one codebase
29 months
continuous delivery
EN / ES
fully localized
Replacing the phone call
Every workflow in this app used to be a call to an office, or a PDF someone printed, signed, scanned, and emailed. Accident reports. ACH authorizations. Direct deposit changes. Separation notices. Certificate requests. Timesheets.
Each one is a small form and a large amount of care — these are documents with legal weight, filed by people who are often having a bad day when they file them. The accident report especially: someone is hurt, on a job site, on a phone, and the form has to be finishable in that state. That constraint drove more decisions than any technical one.
One codebase, three storefronts
The product isn't one app. It's a platform that ships as a separately branded app for each carrier — its own name, icon, bundle identifier, push project, and App Store listing. The obvious way to do that is to fork per client, and the obvious way is how you end up maintaining three divergent codebases and fixing every bug three times.
So brand identity is build configuration, not source. The app manifest is a template — app name, slug, scheme, iOS bundle identifier, Android package — and the CI pipeline substitutes each carrier's values at build time, injecting that brand's Firebase config and signing with that brand's certificates. Three release workflows, one repository, no forks.
The practical result is that adding a carrier is a pipeline configuration, not an engineering project. And a fix written once ships to every brand — which is the entire argument for building it this way, and the thing a fork quietly takes away from you six months later.
Bilingual from the data model out
The workforce is substantially Spanish-speaking, so localization wasn't a translation pass at the end — it was a property of the system from the start. Every string, every date format, every validation message, both languages, with language preference stored per user rather than inferred from the device.
Users can also belong to more than one company and switch between them in-app, each with its own roster, payroll history, and benefits. That multi-tenancy runs through the whole data model rather than being a filter applied at the screen.
Twenty-nine months of shipping
I worked on this app from its first production release in 2023 until the end of 2025 — two and a half years on the same codebase, in a core team of two. That length of engagement changes the job: you stop building features and start living with your decisions.
Over-the-air updates mean a fix reaches a hurt worker's phone in minutes rather than waiting on app review — and reaches every brand at once. Sentry catches what testing didn't, which on React Native is always something. End-to-end tests cover the flows that would be catastrophic to break silently.
The measure of this one isn't a launch. It's that it kept working — in two languages, across three brands, two platforms, and two and a half years of OS releases — without a rewrite.
Next project
BridgePoint
A HIPAA CRM, and 126,000 records that had to survive the move.