Этап 1. Глубокий технический аудит
Мы начали с полного code review и анализа production-логов.
В ходе аудита выявлено:
- отключён строгий режим TypeScript (noImplicitAny, strictNullChecks)
- отсутствует централизованная обработка ошибок (throw new Error, console.log вместо стандартных исключений NestJS)
- практически отсутствует покрытие unit и e2e тестами (тестируется только базовый endpoint)
- бизнес-логика перегружена и нарушает принцип SRP (крупные сервисы и контроллеры)
- секреты частично использовались в Dockerfile и конфигурации
- ошибки в production-логах указывали на необработанные edge-cases и EntityNotFoundError
Главный вывод аудита:
исправление существующей архитектуры потребовало бы сопоставимых трудозатрат с полной переписью backend.
Ключевая архитектурная проблема
Платформа состояла из множества микросервисов:
- auth
- artists
- mylabel
- files
- profiles
- muslink
- notifications
- payments
- tickets
- survey
- statistics
- booking и др.
Каждый сервис имел собственную БД.
Связи реализовывались только через UUID без реальных внешних ключей.
Для проекта такого масштаба это создавало:
- сложность поддержки
- риск рассинхронизации данных
- проблемы с транзакционной целостностью
- невозможность корректного восстановления после аварий
Принятое решение
Мы предложили заказчику:
Полный отказ от микросервисной архитектуры и перенос всей логики в единый Symfony-монолит с общей PostgreSQL базой данных.
Заказчик поддержал решение.
Фронтенд и UI остались без изменений.
API-контракты были сохранены, чтобы переход прошёл безболезненно.
Этап 2. Проектирование монолитной архитектуры
Была создана единая миграция Doctrine, объединяющая все домены в одной PostgreSQL базе.
В монолит перенесены:
- Auth
- Artists
- Releases / Tracks
- Files
- Profiles
- Muslink
- Payments / Subscriptions
- Survey
- Tickets
- Statistics
Все таблицы приведены к единому стилю (snake_case).
Настроены реальные внешние ключи и индексы.

Этап 3. Перенос бизнес-логики
В Symfony были реализованы:
- Entity + Repository для всех доменов
- Сервисы с разделением ответственности
- DTO для валидации входящих данных
- Контроллеры, повторяющие старые API-контракты
- JWT-аутентификация
- Symfony Messenger вместо хаотичных очередей
Логика, которая раньше агрегировалась в api-gateway, теперь формируется внутри монолита в одном месте.

Этап 4. Объединение всех баз данных
Одна из самых сложных задач - объединить дампы всех микросервисов в единую БД.
Мы разработали:
- скрипт импорта дампов
- конвертер COPY → INSERT
- фильтрацию данных с учётом FK
- механизм ON CONFLICT DO NOTHING
- автоматическую синхронизацию sequence

Это позволило:
- безопасно объединить разрозненные БД
- сохранить UUID-связи
- избежать дублирования
- восстановить целостность данных
Почему монолит оказался правильным решением
Для данного проекта:
- нет необходимости в независимом масштабировании сервисов
- нет высокой нагрузки, требующей микросервисов
- важна консистентность данных
- критична стабильность
Монолит на Symfony дал:
- единую точку ответственности
- прозрачную архитектуру
- реальную транзакционность
- простоту деплоя
- управляемость
Команда
Руководитель проекта - 1
Backend-разработчики - 2
DevOps - 1