Why the x70 App Collapsed Onto One Realtime Data Boundary
Moving authentication and application state onto Convex reduced the number of persistence systems in the x70 App, but the real lesson was to migrate boundaries and call sites—not just schemas.
In June, the x70 App still carried two different persistence stories.
Authentication had one database package and generated client. Application data had another. Some dashboard state arrived through server actions while newer features were already using Convex. The repository could build, but every new feature had to answer unnecessary questions about which client, schema, and runtime owned the data.
I moved Better Auth onto its Convex component, switched the live todo flow to Convex hooks, and removed the remaining Prisma packages and migrations from the active workspace.
This was a codebase migration, not evidence of a production-data migration. The interesting part is the boundary it created.
One platform does not mean one table
Collapsing onto Convex was not about putting authentication records and product objects into an undifferentiated schema.
Better Auth still owns users, sessions, memberships, and organization identity. The application owns leads and other product-domain records linked to that identity. Their adapters and application functions now share one operational data platform and one set of deployment assumptions.
That removes an entire class of seams:
- no separate Prisma client lifecycle in the application;
- no second migration directory to keep aligned;
- no hidden choice between a request/response mutation and a realtime query;
- fewer environment variables and local bootstrap steps;
- one place to reason about server functions and subscriptions.
Fewer systems do not automatically create a good domain model. They do make the remaining domain boundaries easier to see.
The todo list was a useful tracer
A small todo list is not the reason to redesign a persistence layer. It is a good tracer for whether the new path is real.
The old version could update through actions and refresh local state. The Convex version reads through a query hook and updates through mutations, so the UI is subscribed to the canonical result rather than maintaining a parallel client copy.
That exposed practical questions before more important objects moved:
- What does an empty query return while authentication resolves?
- Which mutations require an authenticated identity?
- How do optimistic interactions behave when the server rejects a change?
- Which provider must wrap the application before a hook can run?
A migration that moves schemas but leaves every consumer on an adapter shim is not finished. The tracer forced the UI to cross the new boundary.
Authentication is an application dependency
Auth migrations are often described as infrastructure changes. They are also product changes because identity shapes every owned record.
The session has to be understandable to Convex functions. Onboarding has to create the right user and organization state. Email verification and recovery still need their provider configuration. Existing route guards and trusted origins must agree with the new adapter.
Moving the storage layer without checking those journeys would only relocate the schema. The useful unit of work is the whole identity path: request, session, server validation, application query, and visible error state.
Deletion was part of the migration
The cleanup removed the legacy auth package, generated Prisma client, migrations, seed code, and local-service scripts that no longer described the active application.
That matters. Leaving dead persistence code in place preserves optionality only on paper. In practice it tells the next person that two paths may still be valid. They will spend time maintaining both or choose the wrong one.
Deletion makes an architectural decision legible.
It also raises the verification bar. A smaller tree is valuable only if the workspace still installs, generates required Convex types, authenticates, and builds without relying on a deleted artifact. A large negative diff is not a success metric by itself.
The lesson was about seams
The x70 App has evolved far beyond that June snapshot, but this migration set a useful rule: new application state should have one canonical owner, one typed server boundary, and a UI that observes that truth directly.
The goal was not “use Convex everywhere” as a slogan. It was to stop making each feature bridge two persistence systems before it could solve a product problem.