Skip to content

System Overview

Бекенд побудований на .NET із використанням принципів Clean Architecture. Це забезпечує незалежність бізнес-логіки від зовнішніх сервісів та бази даних.


Структура шарів (Clean Architecture)

Section titled “Структура шарів (Clean Architecture)”

Проєкт розділений на чотири основні проєкти (шари), залежність між якими йде виключно ззовні всередину.

Core / Domain (Cinema.Domain) No Dependencies

Section titled “Core / Domain (Cinema.Domain) ”

Ядро системи. Не має жодних зовнішніх залежностей.

  • Сутності (Entities): Movie, Session, Order, Seat, Ticket.
  • Бізнес-логіка: Доменні сервіси (SeatLayoutService, OrderingDomainService).
  • Моделі: Переліки (Enums), абстракції помилок (Result, Error) та кастомні винятки (DomainException).
  • Інтерфейси: Визначення контрактів (IMovieInfoProvider), реалізація яких лежить на зовнішніх шарах.

Містить бізнес-правила (Use Cases) нашої системи. Знає про Domain, але нічого не знає про базу даних чи веб-сервер.

  • CQRS: Поділ на папки Commands (запис) та Queries (читання) для кожного модуля (Users, Movies, Orders тощо).
  • Валідація: FluentValidation для перевірки вхідних даних перед виконанням логіки (CreateOrderValidator).
  • Поведінка (Behaviors): Пайплайни MediatR (ValidationBehavior, IdempotencyBehavior) для наскрізної обробки запитів.
  • DТО: Об’єкти передачі даних та налаштування мапінгу.

Шар реалізації. Тут міститься код для взаємодії із зовнішнім світом. Залежить від Application.

  • База даних: Реалізація ApplicationDbContext (Entity Framework Core) та конфігурації сутностей.
  • Сервіси: Реалізації інтерфейсів з Application (SmtpEmailService, RedisSeatLockingService).
  • Фонові задачі: CancelExpiredOrdersJob (наприклад, через Quartz).
  • Повідомлення: Консьюмери подій (TicketPurchasedConsumer).

Точка входу в систему. Відповідає виключно за маршрутизацію HTTP-запитів та налаштування залежностей (Dependency Injection).

  • Controllers: Тонкі контролери, які лише приймають HTTP-запит і відправляють його в MediatR (_mediator.Send()).
  • SignalR Hubs: TicketHub для забезпечення зв’язку з фронтендом у реальному часі.
  • Middleware: Глобальна обробка винятків (GlobalExceptionHandler) та логування.

Стандартний життєвий цикл запиту в нашій системі виглядає так:

  • API: Контролер отримує HTTP-запит, формує об’єкт Command або Query і передає його в ISender (MediatR).
  • Application (Pipeline): Запит проходить через ValidationBehavior. Якщо дані невалідні, негайно повертається помилка.
  • Application (Handler): Викликається відповідний обробник (наприклад, CreateOrderCommandHandler).
  • Domain / Infrastructure: Обробник звертається до репозиторіїв або зовнішніх сервісів через абстракції (Інтерфейси). Якщо це Command — викликаються методи сутностей для зміни стану.
  • API: Обробник повертає об’єкт Result<T>, який контролер трансформує у відповідний HTTP-статус (200 OK, 400 Bad Request, 404 Not Found).

Ми використовуємо патерн Command Query Responsibility Segregation (CQRS) за допомогою бібліотеки MediatR. Це дозволяє оптимізувати операції читання та запису незалежно одна від одної.

Відповідають за зміну стану системи (Create, Update, Delete, Lock).

  • Мають жорстку інкапсуляцію логіки в CommandHandler.
  • Використовують Domain Entities для зміни стану (наприклад, бронювання місця Seat).
  • Можуть бути ідемпотентними (реалізують IIdempotentCommand), щоб уникнути дублювання критичних операцій (наприклад, оплати).

Відповідають за отримання даних. Не змінюють стан системи (Read-only).

  • Оптимізовані для швидкості: часто використовують DTO та AsNoTracking() в EF Core, або навіть прямі SQL-запити.
  • Підтримують пагінацію (GetMoviesWithPaginationQuery).

Система інтегрується з низкою зовнішніх провайдерів для забезпечення повного циклу роботи кінотеатру. Всі ці інтеграції інкапсульовані в шарі Infrastructure:

  • TMDB API (TmdbService): Відповідає за синхронізацію кінокаталогу. Дозволяє імпортувати фільми (ImportMovieCommand), завантажувати постери, жанри та метадані (тривалість, опис).
  • Gemini AI (GeminiEmbeddingService): Використовує моделі ШІ для генерації векторних вбудовувань (embeddings). Це дозволяє реалізовувати розумні рекомендації фільмів або семантичний пошук на платформі.
  • SMTP (SmtpEmailService): Класичний протокол надсилання транзакційних email-повідомлень (підтвердження реєстрації, надсилання придбаних квитків користувачам).
  • Redis (RedisSeatLockingService): Забезпечує розподілене блокування місць у реальному часі. Коли користувач обирає місце, Redis гарантує, що ніхто інший не зможе забронювати його одночасно.
  • QuestPDF (QuestPdfTicketGenerator): Відповідає за програмну генерацію персоналізованих квитків у форматі PDF із штрих-кодами після успішної оплати замовлення.