Strangler pattern, not big bang
The new platform grew around the old one. A routing layer sent each module's traffic to old or new, and modules moved one at a time: authentication first, then search, then matching, then billing. Every cutover was reversible within minutes. Customers never saw a migration.
Fix the data model first
Most of the prototype's failures traced to its schema. We designed the target model up front and made every migrated module write to it, so the rebuild paid down data debt as it went instead of carrying it across.
Search that holds under load
Candidate search moved from LIKE queries over a flat table to a properly indexed search service. Queries that timed out under modest data volumes return consistently as the candidate base grows.
Roles that mean something
The prototype's shared admin login became proper role-based access: recruiter, hiring manager, and administrator each see and can do exactly what their role allows, with an audit trail underneath.
A cutover playbook per module
Each migration followed the same routine: shadow-read both systems, sync writes, move reads, then flip the route. The playbook made the fourth cutover as boring as the first, and made rollback a routing change rather than an incident.