Modernizing a live audit platform without a feature freeze
Text only: the product holds clients' financial ledgers, so there are no screenshots here.
Context
aivo is a Swiss audit SaaS based in Zurich. When I joined in June 2024, its frontend was a four-year-old React 17 app, mostly JavaScript, with three styling stacks, hand-rolled data fetching and no test suite.
It works with real client ledgers, and feature work couldn't pause while the foundations changed. So none of what follows happened in a rewrite branch. It went in module by module on the live app.
What I did
- Data-analysis workspace. I led the frontend of the product's new module for audit data work outside Excel: ledger import, validation, account mapping, pivot tables and saved views. Its structure is now the template for new features.
- Strict TypeScript, no freeze. Took the 1,500-file app from 11% to 99% strict TypeScript in six milestones while features kept shipping, and ran the React 17 to 18 upgrade.
- Tests that check the figures. Wrote about 520 of the 620 test files and most of the Playwright end-to-end suite. The import spec had 170 assertions, and not one of them checked a figure. I added a test that compares every imported account total against an independent calculation.
- Server state and design system. Moved all server state to TanStack Query, with query-key factories and inline keys banned by lint. Replaced Redux with Zustand and URL state, and merged three styling stacks into one MUI design system of about 50 components.
- API contracts. Added Zod validation on API responses and a contract test registry checked against the OpenAPI spec. It caught three places where the client had silently drifted from the API.
- Performance and accessibility. Fixed an editor render loop that hit about 400 re-renders per second, and virtualized the ledger table. In CI, axe runs on every Storybook story; the known-failure list went from 513 to 489.


