Car Dealership — обзор и архитектура
Бэкенд мультибрендового автосалона на Java 21 / Spring Boot 3, два независимых микросервиса. Вырос из курса «Разработка ПО» в ИТМО: пять итераций, от доменной модели до gRPC, история коммитов сохранена как есть.
Архитектурная схема (archify) →
Два сервиса, две ответственности
order-service (:8080) — заказы (комплектация или со склада), заявки на тест-драйв, пользователи. storage-service (:8081 REST / :9091 gRPC) — каталог машин, комплектующие, сборочные заказы. Разделение по границе предметной области: один сервис знает про деньги и статусы, другой — про то, что вообще есть на складе.
У каждого сервиса своя база Postgres — postgres-orders и postgres-storage. Это не техническая прихоть, а прямое следствие микросервисной границы: сервис, который не владеет данными, не должен иметь к ним прямой доступ через общую схему.
Жизненный цикл заказа целиком
Created(Stock|Custom) → ApprovedByManager → ApprovedByWarehouse → AwaitingPayment → Paid → (ReadyForIssue | AwaitingDelivery) → Completed.
Заказ со склада (Stock) после оплаты сразу переходит в ReadyForIssue — машина физически уже есть. Заказ под комплектацию (Custom) после оплаты уходит в AwaitingDelivery — её ещё нужно собрать и привезти. На каждом шаге допустима отмена через отдельный cancel()-переход, а не общий флаг "отменён" поверх любого состояния.
Зачем два канала связи, а не один
gRPC — для быстрых синхронных запросов каталога: order-service спрашивает у storage-service "эта машина ещё доступна", ждать ответа секунду-другую нормально, задержка напрямую видна пользователю.
RabbitMQ + Outbox — для событий об одобрении или отклонении заказа. Здесь важна не скорость, а гарантия доставки: если storage-service временно недоступен, событие не должно потеряться, оно должно долететь, когда сервис вернётся. Один канал для двух настолько разных требований (低latency синхронный ответ vs надёжная асинхронная доставка) заставил бы жертвовать чем-то одним.
Аутентификация одной строкой
Оба сервиса проверяют JWT независимо друг от друга через JWKS Keycloak (realm cardealership) — order-service не доверяет storage-service слепо, у каждого своя проверка токена как resource server. Роли: MANAGER, WAREHOUSE_ADMIN, USER, ADMIN — подробный разбор ролевой модели и OrderSecurityService в отдельном файле этой же папки.