Модернизация legacy-системы крупного речного оператора

Крупный оператор речных круизов (анонимно) Десятки тысяч заявок в сезон, флот 10+ судов, 8+ лет legacy на PHP 5.4 Туризм и пассажирские перевозки 2024 — наст. время
211
SQL миграций
17 620
записей мигрировано
9
live PDF-шаблонов

Услуги

  • legacy-modernization
  • complex-systems
  • ai-development

Стек

  • SvelteKit 2
  • Svelte 5
  • Supabase Postgres
  • Hatchet
  • Gotenberg
  • PDFKit
  • Tailwind 4

Крупный оператор речных круизов — туризм и пассажирские перевозки. Модернизация legacy PHP 5.4 + MariaDB монолита: 211 SQL миграций, 17 620 записей перенесено, 9 LIVE PDF-шаблонов. С 2024. Сохранено 8 лет истории заявок без downtime и без потери ни одного бронирования.

Один из крупнейших операторов речных круизов с оборотом десятки тысяч заявок в сезон. Legacy PHP 5.4 + MariaDB монолит за 8+ лет накопил техдолга — невозможно добавлять новые фичи, всё ломается. Задача: миграция на современный стек без потери истории заявок и без downtime.

Контекст

Систему писали разные подрядчики с 2016 года. Накопились классические проблемы:

  • PHP 5.4 EOL — невозможно ставить современные библиотеки.
  • MariaDB без формальных миграций — изменения схемы делались вручную через phpMyAdmin.
  • Бизнес-логика в хранимых процедурах + в шаблонах — отслеживать изменения цен и скидок невозможно.
  • Платёжный модуль inline в шаблонах — копипаст между разделами.
  • 5 разных способов отправки уведомлений (mail(), SMTP, telegram-бот, sms-шлюз) без единой шины.
  • Нет тестов. Релиз = «попробовать в проде, откатить если что».

При этом система обрабатывала тысячи заявок в сезон, и просто переписать всё с нуля означало потерять 8 лет истории заявок, цен, договоров с агентствами.

Какие вызовы решены

  • Как мигрировать с PHP 5.4 на современный стек без downtime? Поэтапная миграция с прокси-уровнем: новый стек подключается к legacy-БД read-only, постепенно перетягивает функционал, затем переключается на Supabase. Без блокировки бронирований.
  • Как сохранить 8 лет истории заявок и платежей? Все исторические данные мигрировали 1:1 в Supabase Postgres с маппингом ID → UUID и валидацией FK-цепочек (Sacred Integrity, contractors_without_name, Reconcile snapshot). 17 620 записей перенесено.
  • Как заменить 5 систем уведомлений (mail(), SMTP, Telegram, SMS, in-app) единой шиной? Создали shared-notifications модуль с adapter-pattern: один интерфейс, 5 драйверов, retry/backoff в Hatchet workflow.
  • Как извлечь бизнес-логику из шаблонов и хранимых процедур? Поэтапно вычленяли prices/discounts/promotions из inline-кода в Edge Functions с TypeScript. Бизнес-правила теперь покрыты тестами и версионируются в git.
  • Как добавить тесты к legacy без полной переписки? Contract tests на новый Supabase API + smoke-тесты на legacy-проксируемые маршруты. Регрессии ловятся до прода.

Подход

Поэтапная миграция с сохранением старой системы в работе и постепенным переключением модулей.

  1. Migration_app — воспроизводимый pipeline. Extract из MariaDB → Transform (нормализация полей, исправление кодировок, выравнивание типов) → Insert в Supabase PG 17 → Verify (сравнение SQL-выборок legacy ↔ новая БД с диффом). Каждый прогон автоматически детектирует drift и предлагает фикс.
  2. Public_id 7-символьный для всех URL-сущностей вместо bigint. Backfill через триггеры BEFORE INSERT, без downtime. Короткие URL /orders/Xy3kR9a вместо /order.php?id=12345.
  3. Insert-only versioning через valid_from. Единая модель для discounts, prices, booking_rules, promotions, document templates. Старые версии неприкосновенны. Резолвер: max(valid_from) ≤ effective_date. Никаких race conditions при изменении цен.
  4. Universal Document Platform v2 (merged 2026-04-26, tag pf-pdf-foundation-v1). Hatchet workflows + Gotenberg HTML→PDF + изолированная schema hatchet в общем Supabase Postgres. Заменили самописный PDFKit-pipeline.
  5. Shared modules (shared-pay, shared-notifications, pay-service) для повторного использования между Круизным флотом и параллельным продуктом «Прогулочный флот».
  6. mTLS + HMAC bridge к остаточной legacy-системе для постепенной миграции — новый фронт ходит к старой PHP за остатками атомарных операций.

Результат

  • 211 SQL миграций в production без блокировок (используем CREATE INDEX CONCURRENTLY, ADD COLUMN ... DEFAULT NULL + батч-backfill, feature-flags для rollback).
  • 17 620 единиц данных мигрировано (10 578 круизов + 7 042 прогулок) с побитовой верификацией.
  • 312k платёжных записей скорректированы migration drift-fix процедурой за один сеанс (302 940 buh + 9 101 alfabank помечены site_id='pf').
  • 9 LIVE PDF-шаблонов в работе (1 voucher + 1 voucher_pf + 7 версий pf_excursion).
  • >1000 одновременных пользователей поддерживается (требование ТЗ).
  • 20+ ролей в системе (менеджер, бухгалтер, директор круиза, агент, менеджер агента, физлицо и др.) с разделением через RLS-политики.
  • Бизнес-эффект. Время добавления новой фичи: было 1-3 месяца → стало 1-2 недели. Релизы: было редкие и опасные → теперь несколько раз в неделю.

Эффект для бизнеса

  • Скорость релизов — раньше 1 фича = 1-2 недели и страх «всё упадёт»; теперь — 1-2 дня с тестами и rollback-планом.
  • Стоимость поддержки ↓ — миграции декларативны, схема версионируется в git, не в phpMyAdmin.
  • Команда не зависит от единственного PHP-разработчика, который понимает legacy.

Что мы можем сделать у вас

Если у вас legacy PHP 5.x/7.x с MySQL/MariaDB без миграций и 5+ лет истории — мы делаем поэтапную миграцию на современный стек (TypeScript + Postgres + декларативные миграции) без downtime и без потери истории. /contacts

Что использовали

SvelteKit 2 + Svelte 5 runes + Tailwind 4 + shadcn-svelte (frontend), Supabase Postgres 17 + RLS + Edge Functions Deno (backend), Hatchet TS SDK v1 (workflow engine), Gotenberg 8 (HTML→PDF), Альфа-банк SBP C2B + ЮKassa (платежи), mTLS + HMAC + Idempotency (legacy bridge), Caddy auto-TLS, systemd, Docker Compose. AI-усиление: Claude Code SDK + Hermes Stack (9 docker-сервисов) для оперативного контроля проектов.

Часто задаваемые вопросы

Что входит в проект модернизации?
Миграция legacy PHP 5.4 + MariaDB монолита (8+ лет, флот 10+ судов) на SvelteKit 2 + Supabase Postgres. 211 SQL миграций, 17 620 записей с проверкой каждой через сравнение SQL-выборок legacy ↔ новая БД. 9 LIVE PDF-шаблонов через Hatchet + Gotenberg. valid_from-versioning для цен и шаблонов.
Сколько занимает миграция 8-летнего legacy без downtime?
В этом проекте — ~12 месяцев wall-time с 2024 по 2026. Чистое время разработки migration_app + регрессионных тестов — ~4 месяца. Остальное — анализ legacy-схемы, drift-fix паттерны, поэтапные cutover-окна. Финальный cutover каждой подсистемы — 5-30 минут, без потери ни одного бронирования.
Можно ли было дописывать legacy вместо миграции?
Можно было, но дорого. PHP 5.4 deprecated с 2019, MariaDB схема — implicit-зависимости и триггеры за 8 лет, новые фичи (ЕГИС ОТБ, ГИС ЭП, payment-flow) на legacy требовали бы 3-5× больше времени из-за технического долга. ROI миграции — за 1,5 года через скорость разработки новых фич.
Какие риски сохранения legacy?
PHP 5.4 без security-патчей с 2019 — уязвимости в proddependencies. MariaDB 10.1 не поддерживает window-функции, JSON-типы, foreign-tables. Невозможно интегрироваться с новыми гос-системами (требуют TLS 1.3, modern crypto). Найм PHP 5.4 разработчиков всё дороже. Каждая новая фича — экспоненциальный рост стоимости.

Похожая задача?

Расскажите контекст — подскажу, что и как делать.

Обсудить похожий проект →