Portfolio

back to portfolio

Microservice platform migration

Initial situation

We were approached with the pro.mylabel.cc project, which had been in operation for over a year.

Main issues:

  • Regular errors in production
  • Unstable business logic
  • lack of centralised error handling;
  • poor test coverage;
  • database loss twice a year;
  • complex and overly fragmented microservice architecture;
  • high support costs and inability to predict scalability.

The project was built as a set of microservices on Node.js/NestJS and partly PHP, each with its own separate database and UUID connections without common foreign keys.

For this scale of product, such an architecture proved to be excessive and complicated maintenance.

Stage 1. In-depth technical audit

We started with a complete code review and analysis of production logs.

The audit revealed the following:

  • Strict TypeScript mode (noImplicitAny, strictNullChecks) is disabled.
  • There was no centralised error handling (throw new Error, console.log instead of standard NestJS exceptions).
  • There was virtually no unit and e2e test coverage (only the basic endpoint was tested).
  • The business logic was overloaded and violated the SRP principle (large services and controllers).
  • Secrets were partially used in Dockerfile and configuration.
  • Errors in production logs indicated unhandled edge cases and EntityNotFoundError.

Main audit conclusion:

Fixing the existing architecture would require a labour effort comparable to a complete backend rewrite.

Key architectural problem

The platform consisted of a multitude of microservices:

  • auth
  • artists
  • mylabel
  • files
  • profiles
  • muslink
  • notifications
  • payments
  • tickets
  • survey
  • statistics
  • booking и др.

Each service had its own database. Connections were implemented only through UUIDs without real foreign keys.

For a project of this scale, this created:

  1. complexity of support
  2. risk of data desynchronisation
  3. problems with transactional integrity
  4. inability to recover correctly after failures

The solution

We proposed the following to the customer: Complete abandonment of microservice architecture and transfer of all logic to a single Symfony monolith with a shared PostgreSQL database.

The customer supported the decision.

The front end and UI remained unchanged. API contracts were preserved to ensure a smooth transition.

Этап 2. Проектирование монолитной архитектуры

Была создана единая миграция Doctrine, объединяющая все домены в одной PostgreSQL базе.

В монолит перенесены:

  • Auth
  • Artists
  • Releases / Tracks
  • Files
  • Profiles
  • Muslink
  • Payments / Subscriptions
  • Survey
  • Tickets
  • Statistics

All tables are formatted in a consistent style (snake_case). Real foreign keys and indexes are configured.

unnamed (1).png

Stage 3. Transferring business logic

The following were implemented in Symfony:

  • Entity + Repository for all domains
  • Services with separation of responsibilities
  • DTO for validating incoming data
  • Controllers that replicate old API contracts
  • JWT authentication
  • Symfony Messenger instead of chaotic queues

The logic that was previously aggregated in the API gateway is now formed within the monolith in one place.

Снимок экрана 2026-03-03 141007.jpg

Этап 4. ОMerging all databases

One of the most difficult tasks is to combine the dumps of all microservices into a single database.

We have developed:

  • a dump import script
  • a COPY → INSERT converter
  • data filtering with FK consideration
  • an ON CONFLICT DO NOTHING mechanism
  • automatic sequence synchronisation Без имени.png

This made it possible to:

  • safely merge separate databases
  • preserve UUID links
  • avoid duplication
  • restore data integrity

Why monolith was the right choice

For this project:

  • there is no need for independent scaling of services
  • there is no high load requiring microservices
  • data consistency is important
  • stability is critical

The monolith on Symfony provided:

  • a single point of responsibility
  • transparent architecture
  • real transactionality
  • ease of deployment
  • manageability

Result

After migration:

  1. Production errors eliminated
  2. Stabilised operation of releases and tracks
  3. Eliminated desynchronisation between services
  4. Increased fault tolerance
  5. Ensured correct backup capability
  6. Simplified support

The project has become technically stable and scalable.

Team

Project manager - 1 Backend developers - 2 DevOps - 1

Conclusion

This case study is an example of how excessive microservice architecture can be detrimental to a medium-sized project. A competent audit, honest risk assessment, and architectural review made it possible to create a stable foundation for further product development rather than merely patching up the system.