Shawn Mervin

Case study: replacing a legacy rental ERP without closing for a day.

Super Sonic Equipment Rentals had run its whole operation on one PHP system since 2008. It couldn't be switched off, so I replaced it underneath the business while it kept renting. That system is now Rental Pilot.

Every number on this page comes from the production system. No customer data is shown.

The Rental Pilot dashboard: billing alerts, today's tasks, open agreements and a needs-attention list.
The field app on an iPhone: a rental agreement with its progress steps and the equipment on rent.
Rental Pilot today: the office web app and the field app, on the same data. Rental Pilot running a demo company, Northline Equipment Rentals, with made-up customers.

The starting point

One system ran everything

Assets, rental agreements, billing cycles, maintenance, jobs, employees and payroll all lived in one CodeIgniter application on one MySQL database. It had grown for years, around the way this particular yard works: bulk items by the hundred, fencing, partial returns, fuel delivered to machines on site, agreements that stay open for months.

The business rules were in the code and nowhere else. Nobody had written down why a credit is stamped the way it is, or which charges belong on the first invoice only. A rewrite from a blank page would have thrown all of that away.

The constraint

No maintenance window. Drivers are out at 6 a.m., invoices go out on a cycle, and the office can't stop for a weekend while software is swapped. Whatever replaced the old screens had to run beside them, against the same data, and every invoice had to keep adding up at every step.

How it was done

Keep the engine, replace the screens

The old application already held the logic, so it became the API. Its controllers learned to answer in JSON next to the HTML views they already served, on the same models and the same database. A React web app for the office and a React Native app for the field crew were built on that API, one workflow at a time.

For months both worlds were live. Staff could do a job in the old screen or the new one and the record was the same record. That is what made it safe: if a new screen got something wrong, the old one was still there, and the data never forked.

One workflow at a time

Rental agreements, deliveries and pick-ups, billing, work orders, service calls, timesheets, the customer portal. Each one moved when its new screen did everything the old one did, checked side by side on the old UI, the web app and the phone app. Behaviour that worked differently on one of the three was treated as a bug, even when the new behaviour looked better.

Tested on a copy of real life

A sandbox database is refreshed from a production snapshot, read without locking the live system. Every outside email address in it is scrubbed before anything can run against it, so a test can't send a real customer an invoice. Changes are tried there first, then on production through the same deploy path every time.

Every change with a screen is opened in a real browser or on a real device and looked at before it ships. A passing build isn't the test. The invoice on screen is.

Money rules written into the system

Billing runs off a bill-through date and nothing invoices until a person approves it. The system never bills behind anyone's back. Records are never hard-deleted; a void or reversal leaves a trail. Those rules were in the old system by habit. In the new one they are enforced in the API, so every screen, old or new, gets the same answer.

Switching the old one off

Frozen first, retired second

In August 2026, with every daily workflow running on web and mobile, the old UI was frozen: still reachable, no longer changed. In October 2026 it was retired. Every old address now redirects to the new app. Browser visits to old screens bounce to their replacements, and background calls the phone app still relied on kept working, so nobody's field app broke mid-shift.

There was no cut-over weekend. The last day of the old UI was an ordinary working day.

What it runs today

A rental agreement: progress from created to picked up, the job site, contacts, billing cycle and rented equipment tabs.
A work order for a skid steer loader: summary, assigned mechanic, labour hours and the service description.
A rental agreement and a work order in the React web app that replaced the old screens. Rental Pilot running a demo company, Northline Equipment Rentals, with made-up customers.
  • 3,900 rental agreements, 6,200 invoices and 43,000 fuel deliveries logged against equipment in the field
  • 1.4 million rows of audit trail that kept reconciling while the software underneath was replaced
  • A React web app, a React Native field app for iOS and Android that works offline, and a signed desktop app for Mac and Windows, kept at feature parity
  • A customer portal where customers see their rentals, invoices and requests and place new orders
  • Probed every five minutes from outside, with outages sent to my phone (live status)

Then it became a product

Once the yard's own system was modern, multi-company tenancy and role-based access turned it into Rental Pilot: the same engine, white-labelled for rental businesses in 18 industries, each with its own database, branding and domain. Everything it does, module by module.

What I'd tell anyone doing the same

  • Read the old code before you judge it. The ugly function is often the only written copy of a business rule.
  • Keep one database. Two systems writing to two copies of the data is how a migration loses money.
  • Move workflows, not tables. Users feel progress one screen at a time; nobody feels a schema.
  • Make parity the bar. Improve things after the move, not during it.
  • Freeze before you delete. A read-only old system is a cheap insurance policy for a month.

Questions people ask first

How long did the move take?

It ran alongside normal work over many months, one workflow at a time. The business got value from the first new screen, not at the end.

Was there any downtime?

No planned downtime. Old and new ran side by side on the same data, and the old UI was retired on an ordinary working day in October 2026.

Can the same approach work on our system?

If your system is a working web application with a database behind it, usually yes. The language matters less than whether the business rules can be read out of it. How I approach legacy modernization.

Read next

Running on software you can't switch off?

Tell me what it runs, what it's written in, and what keeps breaking. If I'm not the right person for it, I'll say so.