Business

Two years of setbacks, a core that did not move

A theme bought and thrown away twice, migrations reset four times, a framework upgrade that never recovered, a library that went paid, a database replaced, a front end entirely rewritten. On BuyStep, almost everything changed in two years, except the core. Here is what held, and why.

Contents (11 sections)
  1. Three weeks to lay the core, two years to benefit from it
  2. Setback 1: the purchased template, thrown away twice
  3. Setback 2: migrations reset four times
  4. Setback 3: dependencies that change their terms under your feet
  5. Setback 4: the version upgrade that would not go through
  6. Setback 5: the work nobody sees, and that still has to be funded
  7. Setback 6: the team that changes
  8. What the core made possible: replacing half the stack in three weeks
  9. What replaced discipline: executable guardrails
  10. The most honest test: can you rebuild your project as it was six months ago?
  11. What we take away

No development project goes to plan. That is not an organisational failing, it is the nature of the work: over three years, the market moves, libraries change their licences, frameworks ship major versions, the team changes, and the product itself discovers who it is talking to. So the real question is not “how do we avoid surprises” but what, in an application, must stay standing when everything else moves.

We have a textbook case to hand. BuyStep, the B2B energy marketplace whose platform we have been building since summer 2024, has changed its framework, its database, its mapping engine, its e-mail provider, its billing system and its presentation technology. It has thrown away two purchased templates and reset its migrations four times. Today it runs on a .NET 10 API and a Next.js 16 portal, and its domain model is still the one from August 2024.

To write this article, we reconstructed nothing from memory: twenty-six real commits were extracted from the Git history, recompiled with the SDK of their time, restarted on a fresh database and photographed. Twenty-five started up again. The figures come from Git, not from an estimate.

Contact sheet of 25 screenshots of the BuyStep platform between August 2024 and August 2026, each annotated with the technology stack in service
Twenty-five successive states of the same application, rebuilt and restarted one by one. The monospace line under each thumbnail gives the stack actually in service that day: it changes four times. The application itself was never rewritten.

Three weeks to lay the core, two years to benefit from it #

The repository starts on 1 August 2024. What was put in place in the first twenty days shaped everything that followed:

  • A layered architecture (Domain, Application, Infrastructure, WebApi, Utils) laid down in the very first commits, before there was anything to display.
  • A generic translation model: one entity, one associated translations table. No nom_fr, nom_en columns, no resource files duplicated per language.
  • Continuous integration from day one. The pipeline file was fixed eight times in the same day before it worked. It was tedious, and it was the best investment in the project: two years later, that pipeline still blocks anything that breaks.
  • Database migrations in code, versioned with the application, rather than a schema administered by hand somewhere.

Setback 1: the purchased template, thrown away twice #

BuyStep screen on 25 August 2024: an off-the-shelf furniture e-commerce template, with a subscription bubble overlaid
25 August 2024. The product still shows the e-commerce template bought three weeks earlier (furniture), with a single in-house adaptation on top. Behind this screen, the layered architecture and authentication are already in place.

Starting from a commercial template is a reasonable decision at launch: it buys time. It costs in October 2024, when more than 240,000 lines of old presentation files have to be removed and replaced with a lighter stylesheet. And it costs again in January 2025, when a second template is imported wholesale, with the old page kept alongside under a name ending in OLD.

The key point: these two clean-ups touched only the presentation layer. No entity, no application service, no migration was affected. A project where the purchased template had seeped down into the data model would have paid for these two episodes with a rewrite.

Setback 2: migrations reset four times #

This is the most visible symptom of a young project: the database migration history is rebuilt from scratch four times. In December 2024, most of the October and November files disappear. In March 2025, thirteen new migrations replace the previous ones. In October 2025, 54 files are deleted in one go. In April 2026, the whole history is squashed into a single initial migration.

Should that be alarming? As long as the schema is derived from the model in code and not the other way round, no: a reset is a housekeeping operation, not a loss. What would be serious is resetting a schema whose truth lives in the production database and nowhere else.

Setback 3: dependencies that change their terms under your feet #

None of these decisions was in the original plan, and each one was forced from outside:

  • The search client moves from an abandoned library to the official one in June 2025: a complete API change, carried out in a dedicated branch.
  • The mapping library goes paid and starts checking a token at startup. In April 2026, it is replaced by a code generator that produces the same conversions at compile time: no more reflection at runtime, no more licence to renew.
  • The API documentation drops the long-standing tool for the framework's native OpenAPI support, after a round trip reverted the same day.
  • E-mail sending changes provider in December 2025; file storage moves to S3-compatible object storage with a CDN in April 2026; in-house billing (invoices, transfers, payment details) is removed in September 2025 in favour of a model fully delegated to the payment provider.

The common thread is always the same: these libraries were confined to the Infrastructure layer. You replace an adapter, not a system. The day a mapper goes paid, the team that let its calls spread into the business services rewrites three hundred files; the team that kept them behind an interface rewrites ten.

Setback 4: the version upgrade that would not go through #

March 2025, the move from .NET 8 to .NET 9. On paper, a routine operation: every project file, every package in the data access layer, the test suite. In practice, it was the busiest window of the first year (forty-eight commits, twenty-three of them between 10 pm and 6 am) and the only one we never managed to get running again.

A year later, the same operation to .NET 10 took one day, in the middle of a much broader switch-over. It was not the framework that had become easier: it was the project that, in the meantime, had tests, a pipeline, configuration in environment variables and a reproducible container image.

Setback 5: the work nobody sees, and that still has to be funded #

Two screenshots of the platform, 26 February and 24 March 2026, visually identical even though 626 files changed between them
26 February and 24 March 2026: the same screen, pixel for pixel. In between, two merges to production total 626 modified files and 234,950 added lines: the structured supplier audit system and token-based authentication. The commit on the right carries the only tag in the repository's entire history.

This episode is not isolated. September 2024: a whole month of domain modelling (REST API, DTOs, first tests) without a single pixel of change. 3 December 2025: twelve commits in the day (pipeline, telemetry, commission management) and screenshots strictly identical to those of the day before.

This is the most frequent source of misunderstanding between a technical team and those who fund its work. What is visible and what costs money are not correlated, and project management that only looks at screens always ends up deciding against the core, in other words against the product's ability to absorb the next setback.

Setback 6: the team that changes #

The history shows up to four active contributors in a month, and whole months with just one. February 2026 contains only one commit and a text fix. Conversely, October 2025 was written by a single person, in eleven consecutive merges to production.

What absorbs this variation is not heroics: it is written conventions. In October 2025, configuration moves entirely to environment variables, the application is dockerised, a seed data set is written and the build commands are documented in the repository. From then on, a newcomer can run the project without asking anyone. It is the only lasting answer to staff turnover, and incidentally the condition for AI assistance to be useful rather than noisy.

What the core made possible: replacing half the stack in three weeks #

State of the BuyStep platform on 24 August 2026: Next.js 16 portal served by a .NET 10 API on PostgreSQL
24 August 2026. Next.js 16 portal, a single .NET 10 API, PostgreSQL, dedicated search, delegated subscriptions. The domain model behind this screen is the one laid down in August 2024.

Between 24 March and 12 April 2026, the repository is restructured into a monorepo, the database moves from MySQL to PostgreSQL (with the two separate databases merged back into one), the framework moves up to .NET 10, the portal is rewritten in Next.js and the Blazor administration is removed from the repository. Three weeks.

None of these operations required rewriting the business domain. That is exactly what a layered architecture is supposed to buy, and it is rarely tested in real conditions: here, it was tested four times in a row. One detail says it all: the day before the Blazor administration was deleted, commits were still fixing its navigation. You keep repairing what you are about to remove right to the end, because the removal is planned, dated, and leaves no double maintenance behind it.

What replaced discipline: executable guardrails #

A core does not hold on its own; it holds because something checks that it holds, on every release. In the same window in which the volume of code exploded, four things appeared:

  1. Integration tests leave the in-memory database for a real, ephemeral PostgreSQL in a container, reset between tests. An in-memory database replays neither the migrations nor engine-specific SQL: it hides precisely the bugs that a large migration produces.
  2. Architecture tests automatically check that the layers are not crossed. It is the only way to guarantee that a core stays a core when fifteen people (or fifteen assistant sessions) are writing in it.
  3. A clear separation between unit tests (a few seconds) and integration tests (a few tens of seconds), so that nobody has a reason to skip the former.
  4. A five-stage pipeline that blocks anything that breaks, and end-to-end tests on the payment journey added in August 2026, where a mistake costs real money.

The most honest test: can you rebuild your project as it was six months ago? #

That is the question this retrospective ended up asking, and we now use it in our own audits. Rebuild an old commit, apply its migrations, get it to start: if the operation fails, it is almost never the code that is at fault. It is a secret that became mandatory without being documented, a dependency that stops the process when its service is missing, a port already in use, a migration that does not replay.

In other words, it is a test of how well you control your environment, and it is merciless. The tooling that runs it is described in a separate article; what AI assistance changed in the way these migrations were carried out is covered in this one.

What we take away #

  • Decide early what will not move. The layered structure and the data model are paid for at the start or ten times over later. Everything else is replaceable, and will be replaced.
  • Confine external dependencies. A library that changes its licence or its API should never cost more than an adapter.
  • A schema derived from code can be repaired; a schema administered by hand is something you endure. Four migration resets broke nothing for that reason.
  • Fund what nobody sees. The months without a single pixel of change are often the most structural.
  • Make the project startable without you. Configuration in environment variables, containers, a seed data set, documented commands: that is the answer to a developer leaving as much as to a new one arriving.
  • Automate the checks on the core. Tests on a real database, architecture tests, a blocking pipeline: without them, a core degrades in silence.

This is how we design the business applications we build, and how we take over those that already exist. If your platform is a few years old, nobody knows how to rebuild it any more and every change costs more than the last, that is precisely the diagnosis we know how to make. First conversation free, quote within 48 h, and hosting in France if you wish.

About
01/Read nextThree articles

Related articles

Business

BuyStep: choosing an energy supplier on evidence, not on a catalogue

Panels, batteries, inverters: professional buyers are buried in supplier brochures and short of comparable data. BuyStep answers with an audit structured in 9 dimensions and 200+ criteria, a reliability score and AI-assisted analysis. An overview of the platform, and of what lies underneath.

marketplaceb2b
Business

AI and productivity: why “100% AI” is a social illusion

Transcribed meetings, auto-written e-mails, generated designs: behind the pressure to go all-AI lies a facade of productivity. The view of a freelancer tired of the prevailing FOMO.

aiproductivity
Method

93% of our code was never reviewed. We closed the door.

Over ninety days, 855 commits reached the main branch without going through a merge request, against 63 that did. And that branch triggers the release to production. Measurement, decision, and the four pitfalls we hit while closing the door.

continuous integrationcode review

What next

Use AI where it is genuinely useful?

Use cases, data, hosting: honest scoping before any development.

Discuss your project

Reply within 24 working hours, from one of the two founders. Or by phone: +33 7 59 96 14 99.