Разработка и DevOps / кейс 06

Radario: Билетная платформа и офлайн-сканер для мероприятий

Платформа объединяет продажи через сайт и партнерские каналы с проверкой QR-кодов на площадке. PWA-сканер поддерживает заранее согласованный офлайн-сценарий и синхронизацию проходов после восстановления сети.

  • Ticketing
  • PWA
  • Платежи
Официальная страница Radario с заголовком о сканировании билетов на входе

Организатор связал продажу, выпуск билета и проход одним управляемым контуром. Повторный платежный callback не выпускал второй билет, а сотрудники площадки могли проверять подписанные QR-коды с обычного телефона при потере сети. После восстановления связи проходы синхронизировались, а спорные офлайн-конфликты оставались в общем журнале.

Паспорт билетного контура

  • Направление: ticketing, backend, PWA, платежи.
  • Задача: Продавать билеты через сайт и партнерские каналы, а на входе быстро проверять QR-коды даже при нестабильном интернете.
  • Продолжительность: 7 месяцев.
  • Команда: PM, tech lead, 3 Go-разработчика, 2 PWA-разработчика, UX, 2 QA, DevOps и специалист по платежам. Всего 12 человек.
  • Роль AIFlowPoint: Разработка витрины событий, backend продажи и выпуска билетов, кабинета организатора, партнерского API и PWA-сканера.

Четыре момента, которые происходят не одновременно

Покупка, подтверждение платежа, доставка билета и проверка на входе происходили в разных системах и в разное время. Платеж мог подтвердиться с задержкой, письмо временно не отправиться, а телефон сотрудника площадки остаться без сети во время прохода гостей.

Основной риск был в смешении этих событий. Успешная попытка оплаты еще не равна выпуску уникального билета, доставка письма не определяет состояние покупки, а офлайн-проверка не может мгновенно знать обо всех проходах на изолированном входе. Параллельная покупка не должна превышать квоту или продавать одно место дважды. Возврат должен менять возможность прохода с учетом того, когда сканер получил обновление.

В объем работ вошли витрина, продажа и выпуск, кабинет организатора, партнерский API и PWA-сканер. Проект не обещал математически исключить конфликт между полностью изолированными офлайн-входами. Для такого риска требовался локальный координирующий узел или обязательная сеть между сканерами.

Декомпозиция состояний и ключевые решения

Продажу, выпуск билета и проход разделили на самостоятельные процессы. Для каждого процесса определили отдельное состояние и правило повторной обработки. Контролируемый офлайн-режим спроектировали с последующей фиксацией конфликтов. Для мероприятий с высоким риском предусмотрели локальный координирующий узел или обязательную сеть между сканерами.

Разделение позволяло обрабатывать задержку платежного callback независимо от доставки уведомления. Повтор callback не создавал новый билет. Сканер проверял подписанный QR-код без хранения полного заказа на устройстве. Офлайн-пакет задавал согласованный набор разрешенных билетов, а журнал сохранял результат каждого прохода для последующей синхронизации.

Реализация от продажи до входа

Команда собрала восемь частей одного пути:

  1. Разработали страницы событий, тарифы, схемы залов, квоты, промокоды и партнерские виджеты.
  2. Добавили временный резерв места и выпуск билета после подтвержденной оплаты.
  3. Создали кабинет организатора с продажами, возвратами, гостевыми списками и ролями.
  4. Реализовали подписанный QR-код и PWA-сканер для обычного телефона.
  5. Добавили офлайн-пакет разрешенных билетов и синхронизацию проходов после возвращения сети.
  6. Предусмотрели несколько входов, устройств и смен с общим журналом контроля.
  7. Разработали версионируемый партнерский API.
  8. Подготовили нагрузочный сценарий резкого старта продаж.

Покупатель выбирал событие, тариф или место, получал временный резерв и завершал оплату. Билет выпускался только после подтвержденного платежа. Организатор управлял продажами, возвратами, списками и ролями в кабинете. На входе сотрудник открывал PWA на обычном телефоне и проверял QR-код online либо в заранее согласованном offline-сценарии.

Технический контур и честная граница offline

Next.js отвечает за витрину и кабинет организатора. Go обслуживает короткие операции продажи и проверки. PostgreSQL гарантирует уникальность места и билета, Redis удерживает квоту во время оплаты, RabbitMQ отделяет выпуск билета от отправки уведомления. Service Worker и IndexedDB дают сканеру контролируемый офлайн-режим, Web Crypto API проверяет подпись без хранения полного заказа на устройстве.

Технологический контур проекта: Next.js, React, TypeScript, Go, PostgreSQL, Redis, RabbitMQ, PWA, Service Worker, IndexedDB, Web Crypto API, REST API, OpenAPI, API платежного провайдера, Docker, GitHub Actions, k6, Playwright и Go test. Он поддерживает продажу, выпуск, проверку, синхронизацию и нагрузочное тестирование в границах кейса.

Офлайн-режим имеет явное ограничение. Если два изолированных входа одновременно примут один билет, конфликт будет виден при синхронизации. Для мероприятий с высоким риском предусмотрен локальный координирующий узел или обязательная сеть между сканерами.

Возвращенный билет перестает проходить после синхронизации сканера или обновления офлайн-пакета. Если блокировка должна действовать немедленно, используется сетевой режим. Это ограничение не прятали за формулировкой о полной автономности: приемлемый режим выбирался исходя из риска конкретного мероприятия.

Результат и профиль нагрузки

В нагрузочном сценарии проверяли, что параллельные покупки не превышают квоту, а на входе на площадку контролировали скорость и предсказуемое поведение сканера без сети.

Измеримый результат: От 500 до 2 000 попыток покупки в минуту без превышения квоты; p95 проверки билета до 300 мс online и до 150 мс offline; каждый конфликт offline-синхронизации фиксируется в журнале.

Эффект: Платформа выдержала старт продаж, а сотрудники продолжили пропускать гостей даже при нестабильной связи.

Приемка и проверка результата

  • Параллельная покупка не превышает квоту и не продает одно место дважды.
  • Повторный callback не выпускает новый билет.
  • Возвращенный билет перестает проходить после синхронизации сканера или обновления офлайн-пакета; для немедленной блокировки используется сетевой режим.
  • Сканер работает в заранее согласованном офлайн-сценарии.
  • Партнерский API сохраняет обратную совместимость в рамках версии.
  • Нагрузочный тест подтверждает согласованный профиль старта продаж.

Проверку результата фиксируют k6-отчет, видео работы сканера без интернета, dashboard продаж, журнал проходов и отчет с мероприятия. Материалы отдельно показывают профиль нагрузки, online и offline latency, отсутствие превышения квоты и регистрацию конфликтов.

Что передали организатору

  • Витрина событий и backend.
  • Кабинет организатора.
  • PWA-сканер.
  • Партнерский API и схема синхронизации.
  • Платежная документация.
  • Нагрузочные тесты.
  • Инструкция площадке и runbook спорных проходов.

Передача включала инструкции для реальной площадки. Runbook задавал порядок разбора спорного прохода, а схема синхронизации и платежная документация позволяли отличить проблему выпуска, доставки, проверки или внешнего callback.

Для кого релевантен кейс

Опыт подходит ticketing и другим системам с ограниченной квотой, резким пиком спроса и операцией на границе нестабильной сети. Он особенно полезен, если бизнесу нужны управляемый offline, точная семантика возврата, идемпотентный выпуск и честно описанный конфликтный сценарий.

Если продажи должны выдержать пик, а проверка продолжаться при слабой сети, начнем с модели состояний, профиля нагрузки и допустимых границ offline.