# Копируем конфигурацию
cp .env.example .env
# Запускаем инфраструктуру и приложение
make dev
# Загружаем данные (после запуска приложения)
docker exec -i ticket_system_db psql -U ticket_user -d ticket_system < data/users.sql
docker exec -i ticket_system_db psql -U ticket_user -d ticket_system < data/events.sql
docker exec -i ticket_system_db psql -U ticket_user -d ticket_system < data/events_archive.sql
docker exec -i ticket_system_db psql -U ticket_user -d ticket_system < data/seats.sqlmake dev # Development режим с hot-reload
make dev-build # Development режим со сборкой
make prod # Production режим
make clean # Очистка volumes и контейнеровТаблицы:
users- 1М пользователей для Basic Authevents_archive- События (6B+ записей)events_current- View актуальных событий (последние 3 месяца)bookings- Бронированияseats- 100k мест для концерта (event_id=1)payment_transactions- Платежи
Basic Auth с email:password из таблицы users
# Пример запроса с авторизацией
curl -H "Authorization: Basic base64(email:password)" http://localhost:8000/api/bookings
# Пример без авторизации (публичные эндпоинты)
curl http://localhost:8000/api/events- Backend: Rust (Axum)
- Database: PostgreSQL с полнотекстовым поиском
- Cache: Redis + атомарные резервы (5 минут TTL)
- Payments: Интеграция с платежным шлюзом + Circuit Breaker
GET /api/events- Список актуальных событий- Query params:
page,pageSize,type,provider,date_from,date_to
- Query params:
GET /api/events/search- Полнотекстовый поиск по событиям- Query params:
q(поисковый запрос),page,pageSize
- Query params:
POST /api/bookings- Создать пустое бронирование- Body:
{ "event_id": 1 }
- Body:
GET /api/bookings- Список бронирований пользователяPATCH /api/bookings/initiatePayment- Инициировать оплату- Body:
{ "booking_id": 1 }
- Body:
GET /api/bookings/{booking_id}/payment-status- Статус платежа по бронированиюPATCH /api/bookings/cancel- Отменить бронирование- Body:
{ "booking_id": 1 }
- Body:
GET /api/seats- Список мест с пагинацией и фильтрацией- Query params:
event_id(обязательный)page(default: 1)pageSize(default: 20, max: 20)row(фильтр по ряду)status(FREE | RESERVED | SOLD)
- Query params:
PATCH /api/seats/select- Добавить место в бронирование (атомарный резерв на 5 минут)- Body:
{ "booking_id": 1, "seat_id": 1 }
- Body:
PATCH /api/seats/release- Освободить место из бронирования- Body:
{ "seat_id": 1 }
- Body:
POST /api/webhook/payment- Webhook для уведомлений от платежного шлюза- Body:
{ "paymentId": "string", "status": "CONFIRMED|FAILED|..." }
- Body:
GET /api/payments/success- Callback успешной оплаты- Query params:
paymentId,orderId
- Query params:
GET /api/payments/fail- Callback неуспешной оплаты- Query params:
paymentId,orderId
- Query params:
GET /api/payments/circuit-breaker-status- Статус circuit breaker для мониторинга
POST /api/reset- Сброс всех тестовых данных- Очищает: бронирования, платежи, резервы
- Сохраняет: пользователей, события, структуру мест
Система защищена Circuit Breaker'ом для обеспечения стабильности при проблемах с платежным провайдером.
- Closed - Нормальная работа, все запросы проходят
- Open - Блокировка запросов при достижении лимита ошибок
- HalfOpen - Тестирование восстановления после timeout'а
CIRCUIT_BREAKER_FAILURE_THRESHOLD=5 # Количество ошибок для открытия
CIRCUIT_BREAKER_TIMEOUT_SECONDS=60 # Время до попытки восстановления# Проверить статус Circuit Breaker
curl http://localhost:8000/api/payments/circuit-breaker-status
# Пример ответа:
{
"success": true,
"circuit_breaker": {
"state": "Closed",
"failure_count": 0,
"threshold": 5,
"timeout_seconds": 60
}
}- При открытом Circuit Breaker новые платежи возвращают HTTP 503
- Webhook'и продолжают обрабатываться локально
- Фоновая очистка пропускает API проверки
- Автоматическое восстановление через указанный timeout
created- Новое бронированиеpending_payment- Ожидает оплатыpaid- Оплаченоcancelled- Отменено
pending- Ожидает обработкиcompleted- Успешно завершенfailed- Ошибка платежаexpired- Истек срок платежа
FREE- СвободноSELECTED- Временно зарезервировано (5 минут)RESERVED- ЗабронированоSOLD- Продано
200- Успешно201- Создано400- Некорректный запрос401- Не авторизован / ошибка аутентификации403- Доступ запрещен404- Не найдено409- Конфликт (дублирующийся платеж)419- Конфликт (место уже занято / бронирование не найдено)429- Превышение лимитов500- Внутренняя ошибка502- Ошибка платежного шлюза503- Сервис временно недоступен (Circuit Breaker открыт)
# 1. Создать бронирование
curl -X POST http://localhost:8000/api/bookings \
-H "Authorization: Basic base64(email:password)" \
-H "Content-Type: application/json" \
-d '{"event_id": 1}'
# 2. Выбрать места
curl -X PATCH http://localhost:8000/api/seats/select \
-H "Authorization: Basic base64(email:password)" \
-H "Content-Type: application/json" \
-d '{"booking_id": 1, "seat_id": 100}'
# 3. Инициировать платеж
curl -X PATCH http://localhost:8000/api/bookings/initiatePayment \
-H "Authorization: Basic base64(email:password)" \
-H "Content-Type: application/json" \
-d '{"booking_id": 1}'
# 4. Проверить статус платежа
curl -H "Authorization: Basic base64(email:password)" \
http://localhost:8000/api/bookings/1/payment-status
# 5. Сброс для нового теста
curl -X POST http://localhost:8000/api/reset# Проверить статус Circuit Breaker
curl http://localhost:8000/api/payments/circuit-breaker-status
# Симуляция успешного callback'а
curl "http://localhost:8000/api/payments/success?paymentId=test-payment-123&orderId=booking-1-1640995200"
# Симуляция неуспешного callback'а
curl "http://localhost:8000/api/payments/fail?paymentId=test-payment-123&orderId=booking-1-1640995200"
# Webhook от платежного шлюза (симуляция)
curl -X POST http://localhost:8000/api/webhook/payment \
-H "Content-Type: application/json" \
-d '{
"paymentId": "test-payment-123",
"status": "CONFIRMED",
"teamSlug": "rorobotics",
"timestamp": "2024-01-01T12:00:00Z"
}'# Проверить резервы в Redis
docker exec -it ticket_system_cache redis-cli KEYS "seat:*"
docker exec -it ticket_system_cache redis-cli TTL "seat:100"
# Проверить кеш событий
docker exec -it ticket_system_cache redis-cli GET "events"
docker exec -it ticket_system_cache redis-cli GET "seats:1"
# Проверить данные в БД
docker exec -i ticket_system_db psql -U ticket_user -d ticket_system -c "SELECT COUNT(*) FROM seats WHERE status='FREE';"
docker exec -i ticket_system_db psql -U ticket_user -d ticket_system -c "SELECT * FROM bookings ORDER BY created_at DESC LIMIT 5;"
docker exec -i ticket_system_db psql -U ticket_user -d ticket_system -c "SELECT * FROM payment_transactions ORDER BY created_at DESC LIMIT 5;"
# Проверить статусы платежей
docker exec -i ticket_system_db psql -U ticket_user -d ticket_system -c "SELECT pt.transaction_id, pt.status, pt.amount, b.id as booking_id FROM payment_transactions pt JOIN bookings b ON b.id = pt.booking_id ORDER BY pt.created_at DESC LIMIT 10;"
# Логи приложения
docker logs ticket_system_app --tail 50 -f- Кеширование: Места кешируются на 24 часа, события на 1 час
- Атомарность: Резервирование мест через Redis SET NX EX (без race conditions)
- Пагинация: Максимум 20 записей за запрос
- Индексы: FTS для поиска, B-tree для дат и foreign keys
- Транзакции: Критические операции (отмена брони, сброс) в транзакциях
- Circuit Breaker: Защита от каскадных сбоев платежного провайдера
- Автоочистка: Фоновое освобождение истекших резерваций (15 минут TTL)
