Greenfield-разработка платежей и ваучеров для круизного оператора

Крупный оператор речных круизов (анонимно) Десятки тысяч заявок в сезон, флот 10+ судов, 8+ лет legacy на PHP 5.4 Туризм и пассажирские перевозки 2025 — 2026
6 839
туров «Прогулочного флота» в сезон
~3 сек
генерация PDF
15 мин
TTL на бронь

Услуги

  • complex-systems
  • legacy-modernization

Стек

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

Крупный оператор речных круизов — туризм и пассажирские перевозки. Greenfield-разработка «Прогулочного флота»: 6 839 туров в сезон, чекаут 2-3 экрана vs legacy 5+, генерация PDF ~3 сек, TTL 15 мин на бронь. 2025 — 2026. Переиспользовано 80% кода основного продукта через $shared alias.

Тот же оператор речных круизов, второй продукт — «Прогулочный флот» (короткие прогулки на теплоходах 1-3 часа vs многодневные круизы основного «Круизного флота»). Задача: отдельный быстрый чекаут (бронирование+оплата за 2-3 экрана), общая backend-инфраструктура, без блокировки админ-фич основного продукта. Production-релиз 0.6.86 на pf.sputnik-germes.ru.

Контекст

У оператора уже работала legacy PHP-система бронирования прогулок — устаревший UX, проблемы с мобильной версией, тяжёлый чекаут на 5+ экранов. Параллельно велась миграция основного продукта (Круизного флота) на новый стек SvelteKit + Supabase.

Решение: отдельный фронтенд-проект frontend_mf (micro-frontend) на том же стеке, что и Круизный флот, со 100% переиспользованием backend (та же БД, те же RPC, те же shared-модули). Уникален только UI-слой Прогулочного флота, всё общее подключается через $shared alias.

Дополнительная сложность: legacy PHP-система продолжает работать (управление флотом, отчётность, выгрузки в 1С). Новый фронт должен делать атомарное создание заявок в legacy с TTL 15 минут до подтверждения оплаты.

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

  • Как сделать чекаут «Прогулочного флота» за 2-3 экрана vs legacy 5+? Отдельный фронтенд-проект frontend_mf (micro-frontend) с минимальным funnel: тур → каюта → ПД пассажиров → оплата. Всё на одном экране где возможно.
  • Как переиспользовать 80% кода с основным продуктом? Через $shared alias из Круизного флота: UI-компоненты, утилиты, типы, shared-pay/shared-notifications — общие. Уникален только UI-слой.
  • Как создавать заявки в legacy PHP-системе без отказа от неё? mTLS+HMAC мост к legacy endpoint: client cert + HMAC-SHA256(secret, ts.nonce.body) + Idempotency-Key UUIDv4. Атомарное создание aa_schet+aa_order[]+aa_place[] со статусом=2 и TTL 15 минут.
  • Как делать UPSERT контрагентов без дублей? Уникальный ключ — fio + birthday. Без birthday legacy создаёт дубли. Поле обязательно в payload.
  • Как делать rollback заявки если оплата не прошла? TTL 15 мин на статус=2. После — автоматический rollback в legacy через cron-task.

Подход

  1. frontend_mf как micro-frontend. Уникальный код только специфики Прогулочного флота (короткий чекаут, прогулочные туры). Всё общее (UI-компоненты, утилиты, типы) — через $shared alias из Круизного флота. Принцип: «Круизный флот = primary, Прогулочный флот = derived через $shared/$frontendRoutes».
  2. Legacy bridge через mTLS + HMAC. Endpoint на 192.168.11.11:443/api/pf/create_booking: client cert pf-test/pf-prod от собственного CA + HMAC-SHA256(secret, ts.nonce.body), Idempotency-Key UUIDv4. Новый фронт «Прогулочного флота» делает атомарное создание заявки в legacy (aa_schet + aa_order[] + aa_place[]) со status=2 и TTL 15 минут до подтверждения оплаты.
  3. birthday обязателен в payload — нужен legacy для UPSERT aa_kontragent по fio + birthday. Без него legacy создаёт дубли контрагентов.
  4. Excursion PDF через Hatchet workflow. На сохранение версии экскурсии в админке → background рендер расписания PDF через excursion-schedule-generate workflow + Gotenberg → URL в /pdf/e/{slug}. Время генерации ≈ 3 секунды end-to-end.
  5. Universal Document Platform обслуживает оба продукта через единый pdf-tasks-worker (контейнер из hermes-stack) + общие таблицы voucher_jobs/voucher_templates. 9 LIVE PDF-шаблонов: 1 voucher Круизного флота + 1 voucher Прогулочного флота + 7 версий pf_excursion.
  6. Платежи через shared-pay. Альфа-банк СБП C2B + ЮKassa — переиспользованы из Круизного флота. Callback-обработка через выделенный pay-service для атомарности.

Результат

  • 6 839 прогулочных туров в promenade_tours за сезон 2026.
  • 7 версий pf_excursion (живущие документы, обновляются на старте сезона).
  • 15 минут TTL на бронь до оплаты — после автоматический rollback в legacy.
  • End-to-end за ~3 секунды: запрос → PDF в Supabase Storage → public URL → email клиенту.
  • Live E2E с реальной оплатой: заявка создана, ваучер отправлен через 3 секунды, бронь подтверждена.
  • Нулевой дублирующий код: 80% всего frontend Прогулочного флота — это $shared из Круизного флота. Любая правка в основном продукте сразу попадает во второй (если не помечено как специфика).

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

  • Конверсия чекаута выросла — короткий путь 2-3 экрана vs legacy 5+.
  • Производственные расходы не выросли — 80% общего кода с основным продуктом, любая правка идёт в оба продукта.
  • Legacy не стал блокером для нового продукта — атомарное создание заявок и rollback по TTL делают переходный период безопасным.

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

Если у вас на legacy-стеке есть основной продукт, и нужен второй продукт быстрее без переписывания backend’а — мы делаем micro-frontend на современном стеке поверх старого backend’а через mTLS+HMAC мост. /contacts

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

SvelteKit 2 + Svelte 5 runes + Tailwind 4 + shadcn-svelte (frontend_mf), Supabase Postgres 17 + RLS + Edge Functions Deno (backend), Hatchet TS SDK v1 (workflow engine), Gotenberg 8 (HTML→PDF), PDFKit (legacy backup для voucher), shared-pay + shared-notifications (общие модули из Круизного флота), mTLS + HMAC + Idempotency (legacy bridge), Альфа-банк СБП C2B + ЮKassa (платежи), Caddy auto-TLS, systemd, Docker Compose. AI-усиление: Claude Code SDK + Hermes Stack (9 docker-сервисов). Frontend через $shared alias переиспользует ~80% Круизного флота.

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

Что входит в Greenfield-разработку «Прогулочного флота»?
Новый продукт оператора речных круизов под короткие прогулки (1-3 часа). Чекаут за 2-3 экрана (vs 5+ у legacy), TTL 15 мин на бронь, генерация PDF-ваучера за ~3 сек через Hatchet + Gotenberg. Переиспользовано ~80% кода основного продукта через pnpm workspace `$shared` alias и общий Supabase Postgres.
Сколько занял запуск нового продукта?
Около 4-5 месяцев wall-time на MVP: SvelteKit 2 + Svelte 5 runes + Tailwind 4 + shadcn-svelte фронт, общий Supabase backend, переиспользование payment-service и shared-pay. Сезон 2026 — 6 839 туров в системе. Релиз 0.6.86 на pf.sputnik-germes.ru, без блокировки развития основного продукта.
Можно ли было обойтись доработкой основного продукта?
Можно, но дороже и медленнее. Чекаут короткой прогулки требует радикально упрощённого UX (без кают, питания, услуг) — это противоречит UX основного продукта. Greenfield с переиспользованием 80% кода через monorepo дал и скорость запуска, и сохранение единой кодовой базы для совместного развития.
Когда Greenfield не оправдан?
Если новый продукт = тот же UX с другим брендом — достаточно white-label темы. Если backend-логика принципиально другая (B2B вместо B2C) — лучше отдельный сервис, не monorepo. Greenfield с shared-кодом оптимален при ~30-50% общей логики и radically different UX-flow.

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

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

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