The challenges inheriting a legacy system

11th January 2024

When we start working with new clients we often inherit systems built by their “old developers”. Sometimes they’re great, sometimes they aren’t. In 2021 we inherited a Laravel / React application that definitely fit in the latter category.

The application we took over was used to manage a fleet of electric cars and had thousands of daily users. Our client was expanding rapidly and had a backlog of new features as long as your arm. With improvements needed rapidly, we could not afford to assign resources to a complete rebuild, we had to work out how to add the functionality they require and perform the maintenance / upgrades / improvements to ensure the system would last well into the future.

Technical details

The application was built in Laravel with a Gatsby frontend. The backend included a proprietary Laravel package hosted on the previous developer’s own servers and was password protected. Furthermore, as it was Laravel 6, PHP was pegged to 7.4 (EOL was November 28, 2022). The whole solution was hosted on a rudimentary AWS solution.

From a technical perspective, the primary issue was how outdated most of the solution was. Our challenge was to support their ongoing business development needs whilst simultaneously bringing the stack up to modern standards.


The frontend was built in React 12 with Gatsby to facilitate SEO and relied on node 12. It also used Redux+Saga and had ZERO tests! Our plan was as follows:

  1. Add Jest so we can get some tests in place
  2. Update node to v16
  3. Update React to v16

If you’ve ever tried something like this you can probably guess what the next few sentences will say… 

Unfortunately, adding Jest with node v12 and React v12 plus all the other dependencies in the project was not as straightforward as we’d have liked and we ended up having to move to node 14 first before we could add Jest. At that point we wrote a small handful of tests so that we would have something to lean on during the rest of the upgrade process.

The next step was to try and upgrade React and associated libraries to something more modern, ideally v16. With not too much back and forth, we did manage to bring both node and React up to v16 and thanks to a few tests, we had some confidence we hadn’t broken anything along the way.

Now that we had a more modern stack (React 18 had just been released but we didn’t feel it was necessary to make that jump quite yet as Gatsby was not receiving the updates necessary to work well with more modern versions of React), we started adding the features we felt would make the difference between a nice MVP and a proper web application frontend. Specifically, we added Sentry, Cypress, Storybook, and Eslint and prettier rules.

At this point we were able to add nearly 100% test coverage and were able to produce really high quality results.

The backend

The single biggest challenge on this project was bringing the backend up to date (well, Voyager did present some issues but nothing we couldn’t manage). 

This was a Laravel 6 application with a dependency on PHP 7.4. PHP 8 had already been out for several years and 7.4 was approaching EOL. 

Complicating matters was a dependency on a proprietary, password protected Laravel package created by the previous developers.

As a team, we sat down and evaluated all the issues we were facing, which included a very outdated and highly customized version of Voyager. We estimated the time required to follow the standard upgrade path taking into account there were some unknown variables that could have meant a matter of days or a matter of months. We just couldn’t tell at that time. 

Based on our estimates, the decision was made to start a parallel development branch that depended on the updated versions of Laravel, replacing Voyager with Filament for the admin panel, while maintaining the existing database schema. 

As one can imagine, this was not quite the easiest path but it was more predictable and it would allow us to go directly to these more modern solutions rather than having to evaluate update paths and migrations at each step of development.


The key to our success on this upgrade path was our database migration scripts. Naturally, as the existing (old) project was in active development while the new version was being built, changes in database schema were introduced in the old version that would need to be present in the new version. The new version, meanwhile, because it was using Filament, also suffered changes to the database schema. Schema conflicts are not easy to resolve but as a testament to Laravel’s amazing migration infrastructure, we were able to write scripts that migrated everything required, including doing some data transformation as part of the migration.

Update day …

We fully automated the entire migration process, start to finish, and when the day came, after months of testing, the migration went smoothly and the client suddenly found themselves on a totally modern stack, front to back, with a snappy admin panel based on Filament, on a resilient and redundant AWS infrastructure that used CircleCI, SonarCloud, Sentry and other tools to assure the highest quality possible.

We all went out for beer and pizza to celebrate.

If you are looking for a development partner to work on or upgrade an existing platform, we’d love to chat. We’re experts in web and mobile application development.

Please email us at [email protected]  or pop a time directly in our calendar