Files
ticket-system/ARCHITECTURE.md
2026-03-05 14:27:30 +00:00

2.5 KiB
Raw Permalink Blame History

Архитектура и бизнес-правила (Ticket System)

1. Базовые принципы

  • Стек: FastAPI, SQLAlchemy 2.0 (asyncpg), PostgreSQL, Redis, RabbitMQ.
  • Модели данных: Описаны в backend/database/models.py.
  • Ключевые сущности: User, Tournament, Seat, Ticket.

2. Жизненный цикл билета (State Machine)

Статус билета (TicketStatus в таблице tickets) строго ограничен:

  1. AVAILABLE — место свободно для бронирования.
  2. LOCKED — место временно захвачено пользователем (15 минут на оплату).
  3. PAID — оплата прошла успешно.
  4. SCANNED — билет погашен на входе.
  5. REFUNDED — возврат.

3. Сценарий А: Конкурентное бронирование (Критический путь)

Захват места должен исключать "состояние гонки" (race condition).

  1. При POST-запросе на захват места (/api/seats/{seat_id}/lock), FastAPI обращается к Redis.
  2. Пытается установить ключ lock:seat:{seat_id} с помощью SETNX и TTL 15 минут.
  3. Успех: Если Redis вернул 1, обновляем статус билета в БД на LOCKED и привязываем user_id. Возвращаем HTTP 200.
  4. Отказ: Если ключ уже существует, немедленно возвращаем HTTP 409 Conflict. БД не трогаем.

4. Сценарий Б: Асинхронная выдача билета (Idempotency)

Защита от двойных списаний и зависаний интерфейса при долгой генерации PDF.

  1. Платежный шлюз присылает Webhook об успешной оплате.
  2. FastAPI проверяет поле idempotency_key в таблице tickets. Если ключ уже обработан — игнорируем запрос.
  3. Обновляем статус билета на PAID.
  4. Отправляем событие ticket_paid (содержит ticket_id и данные пользователя) в очередь RabbitMQ. Отвечаем шлюзу HTTP 200.
  5. Фоновый воркер забирает задачу, генерирует PDF (reportlab), грузит в MinIO (boto3) и сохраняет ссылку в БД.