Background
Nina and her co-founder had been shipping ReviewKit for 18 months. The product worked, customers paid, but the engineering quality had accumulated debt. New features sometimes broke old ones because the codebase had grown organically without consistent patterns. Auth lived in three places. API routes had different error handling styles. Some components fetched their own data; others received it as props. Code review was slow because reviewers couldn't predict how new code would behave.
The challenge
The team needed to migrate to a foundation with consistent patterns without losing the product progress they'd made. The new foundation had to be clear enough that both engineers could predict where new code belonged, consistent enough that code review was fast and reliable, and opinionated enough that the team didn't relitigate architecture decisions on every feature.
How they built it
Migration sprint: preserve features, adopt patterns
Nina's team spent one sprint migrating ReviewKit's core features onto ShipAI's foundation. They kept the product logic and replaced the infrastructure layer. Auth moved to Better Auth, billing moved to the Stripe integration, API routes adopted the consistent error handling pattern. The migration surfaced six latent bugs — inconsistencies in the old codebase that the new patterns made visible.
One clear pattern for API routes
ShipAI's API routes follow a consistent structure: input validation, auth check, business logic, error handling. After the migration, every API route in ReviewKit followed the same pattern. Code review for new API routes dropped from 30–45 minutes to 10–15 minutes because reviewers knew exactly what to look for.
Component data flow made explicit
The UI components in ShipAI follow clear data flow patterns — server components fetch data, client components receive it as props or use specific data-fetching hooks. ReviewKit's previous inconsistency (some components did their own fetching, others didn't) was a source of unexpected side effects. After migration, the pattern was uniform and predictable.
Drizzle ORM as the single database layer
ReviewKit had previously used both raw SQL queries and an ORM in different parts of the codebase. ShipAI's use of Drizzle ORM exclusively meant the team standardized on one database access pattern. Type-safe queries caught several category of bug that had previously reached the QA stage.
Outcomes
QA pass rate 70% → 91%
First-review QA pass rate improved from 70% to 91% in the two months following migration — a 30% reduction in features requiring rework.
Code review time halved
Average code review time dropped from 35 minutes to 17 minutes per feature PR, attributed to predictable patterns and consistent API route structure.
6 latent bugs found during migration
The migration to consistent patterns surfaced six bugs that existed in the old codebase but hadn't yet manifested for customers.
Zero architecture debates since migration
In four months since migration, the team has had zero discussions about where new code should go — the structure makes the decision obvious.
In their own words
The hidden cost of inconsistent architecture is slow code review and unexpected regressions. You don't see it in any single sprint but it's there every week. ShipAI's consistency made both of those things better at the same time. Code review is faster because both engineers know the patterns. Regressions are fewer because the patterns prevent the class of bugs that came from inconsistency.
“We're a two-person team and we cannot afford regressions. The architecture's predictability means our QA pass rate went from about 70% on first review to over 90%. New features follow the same patterns as old ones, which makes code review fast and merge confidence high.”
— Nina Kozlova
Frequently asked questions
How long did the migration from a custom stack take?
One sprint (2 weeks) to migrate the core features. Nina notes that most of the time was spent on the database migration to Drizzle ORM — the auth and billing migrations were faster because the patterns were more standardized.
What's the biggest pattern-consistency benefit in the codebase?
Nina cites the API route structure. Every API route: validates input with Zod, checks authentication using the same middleware pattern, executes business logic, and handles errors with the same response format. 'Once you know one route, you know all of them.'
Did the migration break any existing functionality?
Three minor issues surfaced during migration that required fixes. All three were caught in internal testing before reaching customers. Nina notes this was fewer breaking changes than expected given the scope of the migration.