
01 · Context and stakes
The client is a US manufacturer of large machinery: heavy equipment with engine, mechanical and electrical systems, and the logistics to deliver it. They run a few factories with a couple of hundred people on the floor, on revenue above $100M a year, and the MES has hundreds of daily users.
No off-the-shelf manufacturing execution system (MES) fit how they build, so their team built a prototype in Lovable, an AI app builder, with a React front end and a Supabase backend. It went into production, and every crew and manager came to rely on it daily.
The prototype did its job, then outgrew its platform. The app became hard to change safely, had no architecture the client's IT could own, was not built for production security, and used password sign-in. It ran fine until it didn't, and the client decided to migrate.
When the MES is down, crews lose their work orders and managers lose sight of production. The whole migration cost less than the business would lose in a short outage of the MES. That was the real comparison: not migration against doing nothing, but migration against the next failure.
02 · Constraints
- Nothing could change for the floor. People knew the screens; a new UI meant retraining across a few factories.
- The system had to stay up throughout.
- Development could not stop. The client team kept fixing bugs and shipping small features in Lovable while we worked.
- It had to fit the client's Microsoft environment, from sign-in to where the data lives.
03 · Architecture
Before: the React app generated in Lovable, calling a Supabase project (Postgres, password auth, server functions) directly from the browser.
After: the same React UI, talking to a proper API instead of the database. The API is a Next.js server running as a containerized web app on Azure App Service (Web App for Containers), with Prisma over a managed Azure SQL database. The Supabase functions became API endpoints, and sign-in moved to Microsoft Entra ID. Azure DevOps pipelines build, test and deploy every change, and the system runs with high availability and backups.
Before: prototype platform
Browser
React app
Generated in Lovable
Down to Supabase, via: Password sign-in, database calls from the browser
Supabase
Postgres
Auth
Server functions
After: Azure, Microsoft sign-in
Browser
React UI
The same UI as before
Down to API, via: Microsoft Entra ID single sign-on
API
Next.js server
Container on Azure App Service. Role check on every endpoint.
Down to Data, via: Prisma
Data
Azure SQLManaged
High availability, automated backups
After: reporting
Product manager
Claude
With a reporting skill
Down to Access.
Access
MCP serverRead-only
Authorization, roles, query validation
Down to Data.
Data
Azure SQL
The same database as the app
During the migration: code
Source
Lovable code
Down to Migration.
Migration
Migration tool
Run by our engineers, with coordinated AI agents, skills and PRDs
Down to Checks, in order.
Checks, in order
Pull request
Tests
Engineer review
Down to Release.
Release
Azure DevOps pipeline
Deploy
During the migration: data
From
Supabase
Prototype data
Down to To, via: One-way sync script
To
Azure SQL
The prototype platform before, the Azure platform after (app and reporting), and how code and data moved across during the migration. 04 · Decisions
Keep the UI exactly as it was
- Considered
- A redesign during the rebuild; keeping the React UI.
- Chose
- The same React UI, with every change behind it.
- Why
- Crews across a few factories knew the screens. No retraining, and a cutover the floor would not notice.
- Trade-off
- We inherited front-end structure we would have designed differently. UI improvements became a separate, later decision.
A repeatable migration tool, not a manual rewrite
- Considered
- Freezing Lovable and rewriting by hand; unsupervised AI agents; a tool our engineers operate, with coordinated agents and reviewed output.
- Chose
- A hybrid tool run by our engineers: coordinated AI agents rewrite from our PRDs and skills, and engineers review every pull request.
- Why
- Development in Lovable could not stop. A tool can rerun on every change the client team made; a one-off rewrite cannot.
- Trade-off
- The tool, PRDs and skills had to exist before the first migrated screen, and every output still needs an engineer's review.
One-way mirror, then a single cutover
- Considered
- Two-way sync with a gradual move; factory-by-factory phases; a one-way mirror and one hard switch.
- Chose
- One-way sync from Supabase into Azure SQL during a couple of weeks of shadowing, then one big-bang cutover.
- Why
- Two-way sync between two different databases is where records get lost or duplicated. One direction kept a single source of truth until the switch.
- Trade-off
- Everything rode on one switch, and going back afterwards would mean reconciling data written in the new system.
Azure, Azure SQL and Entra ID, to match the Microsoft environment
- Considered
- Moving Supabase to a self-managed setup; Postgres on another cloud; the client's own Microsoft stack.
- Chose
- A Next.js API in containers on Azure App Service, Prisma over managed Azure SQL, Entra ID single sign-on and Azure DevOps pipelines.
- Why
- People already have Microsoft work accounts, so access follows the client's own accounts and their IT runs familiar tools.
- Trade-off
- Postgres to SQL Server meant translating the schema and queries, and replacing what Supabase gave for free, such as built-in auth.
An MCP server to replace live-data prompting
- Considered
- Dropping it; fixed dashboards; direct database access for Claude; a governed MCP server.
- Chose
- An MCP server on the new system, with a reporting skill, query validation, authorization and role-based access.
- Why
- Dashboards answer only the questions someone predicted, and direct database access would undo the security work.
- Trade-off
- The skill and validation rules need upkeep as the data model changes, and numbers that matter still get checked by a person.
05 · Security
Microsoft Entra ID single sign-on
Replaces in-app passwords. Access follows the client's own work accounts.
Role-based access on the server
Every API endpoint checks the caller's role; the UI is not the enforcement point.
No database access from the browser
The front end talks only to the API.
Guarded MCP server
Read-only: a tool for reading and digesting data, never changing it. Authorized users only, the same roles as the app, and every query validated before it runs.
Azure DevOps CI/CD with automated tests
Every change, including each migration-tool pull request, is tested and reviewed before deploy.
Secrets kept out of the code
Injected per environment, never stored in the repository.
High availability and backups
Azure SQL with high availability and automated, point-in-time backups.
06 · Delivery
1. Eject and design. We took the React code out of Lovable into a normal Git repository. Our engineers designed the target first: API, SQL Server data model, roles, and how the existing UI would call it.
2. A migration tool, not a one-off rewrite. We built a hybrid migration tool for our engineers to operate. They run it, choose what to migrate next and steer it. Inside, a team of AI agents coordinates the work, splitting it up, rewriting the ejected code from PRDs and skills our engineers wrote, and checking each other's output: database calls become API calls, server functions become endpoints, password sign-in becomes Entra ID. Each result lands as a pull request, runs the tests and is reviewed by an engineer before it merges. The agents write code; our engineers own the system.
3. Shadow running. For a couple of weeks the new system shadowed the live Lovable app. A sync script mirrored data one way, from Supabase into Azure SQL, so the new system could be checked against the old one on current production data. The client team kept working in Lovable, and the tool carried each fix and small feature across.
4. One cutover, zero downtime. The final data mirror ran beforehand. The cutover itself was a rollout of the new system and a domain switch: people signed in with their Microsoft accounts and kept working, with no downtime. At no point did both systems take writes. We also had a rollback plan, which we never needed: inside the Lovable app we built backend endpoints that could both export data and ingest it, so any records written in the new system could have been restored to Lovable if we had to switch back.
5. Restoring lost insight. In Lovable, the product manager could prompt against live data for reports, feature adoption and business metrics. Risky but useful, and the migration took it away. We built an MCP server on the new system with a skill that teaches Claude the data model. He now does his reporting in Claude, under proper access controls.
The system is now in maintenance mode.
07 · Results
Changes the floor had to learn
at cutover
None: same screens, same workflows
Sign-in
since cutover
Before: Passwords in the appAfter: Microsoft Entra ID single sign-on
Backend
since cutover
Before: Supabase, on the prototype platformAfter: Next.js API on Azure App Service, Prisma, managed Azure SQL
Release path
since cutover
Before: Publish from the prototype platformAfter: Azure DevOps pipelines with automated tests and review
Downtime at cutover
at cutover
None: rollout and domain switch after a couple of weeks of shadow running
Ad-hoc reporting on live data
since the MCP server shipped
Before: Prompting the prototype directlyAfter: Claude via an MCP server with role checks and query validation
- The whole migration, 3 engineers over 3 months, cost less than the business would lose in a short outage of the MES.
- Bug fixes and small features made in Lovable during the migration were carried into the new system, so the client never had to freeze development.
- The system is now in maintenance mode on infrastructure the client's IT can operate.
- The product manager does his reporting in Claude, inside the same access rules as the app.
08 · Team
3 Blackbird engineers, working with the client's product team, who built the original prototype and own the product.
Who owned what: we owned the architecture, the migration tool, the new backend, the pipelines, the cutover and the MCP server. The client owned the product and every change made in Lovable along the way.
What we'd do differently
Not much. If we ran it again, we'd give the migration tool more agents and more compute from day one, so more of the rewrite runs in parallel while our engineers review each pull request.