Repository navigation
Doc Booking
src/Services/Booking/. Заявки на туры, предложения менеджера и избранное. База travel_booking.
Клиент на странице тура нажимает «Оставить заявку»:
POST /api/v1/bookings
{ "tourId": "3f2a…", "comment": "Двое взрослых, июль" }
→ 201 { "id": "b7c1…", "status": 0, … }Booking сначала спрашивает у Catalog по gRPC, опубликован ли тур. Если нет, ответ 422 tour-unavailable, заявка не создаётся. Дальше заявку ведёт менеджер: берёт в работу, отправляет предложение, клиент его подтверждает. Весь сценарий: Заявки и чат.
| Сущность | Поля |
|---|---|
Booking |
Id, ClientId, TourId, Comment, Status, CreatedAt, UpdatedAt
|
BookingStatusHistory |
BookingId, Status, ChangedByUserId, ChangedAt
|
Proposal |
BookingId, ManagerId, TourSnapshot, Notes, IsConfirmed, CreatedAt
|
TourSnapshot |
TourId, Title, Description, Price, Currency, DurationDays, SnapshotTakenAt: копия тура на момент предложения |
Favorite |
UserId, TourId, AddedAt; пара уникальна |
OutboxMessage |
EventType, Payload, Status (Pending, Processed, Failed), CreatedAt, ProcessedAt
|
Статус заявки в JSON передаётся числом:
| Число | Статус | Смысл |
|---|---|---|
| 0 | New |
создана клиентом |
| 1 | InProgress |
менеджер взял в работу |
| 2 | ProposalSent |
клиенту отправлено предложение |
| 3 | Confirmed |
клиент подтвердил предложение |
| 4 | Closed |
заявка завершена |
| 5 | Cancelled |
отменена |
Перевод чисел в названия на фронтенде: src/api/bookings.ts.
| Из | Можно в |
|---|---|
New |
InProgress, Cancelled
|
InProgress |
ProposalSent (только если есть хотя бы одно предложение), Cancelled
|
ProposalSent |
Confirmed, InProgress, Cancelled
|
Confirmed |
Closed, Cancelled
|
Closed, Cancelled
|
никуда |
Недопустимый переход: BookingDomainException, ответ 422.
| Действие | Клиент | Manager, Admin |
|---|---|---|
| создать заявку | да | да |
свои заявки GET /bookings/my
|
да | да |
все заявки GET /bookings
|
нет (403 на Gateway) | да |
| заявка по id | только своя, иначе 403 | любая; плюс имя и email клиента из Identity |
смена статуса PATCH …/status
|
только своя и только в Cancelled
|
любой допустимый переход |
предложение POST …/proposal
|
нет | да, кроме Closed и Cancelled
|
подтверждение POST …/confirm
|
своя заявка | да |
PATCH с Confirmed отвечает 400: подтверждение идёт только через confirm с proposalId. Неверный proposalId: 422. Поле clientPhone в ответе всегда null: телефон хранится в Identity, но gRPC GetUserSummary его не передаёт.
| Вызов | Когда |
|---|---|
Catalog GetTourSnapshot
|
создание заявки и добавление в избранное; тур должен быть опубликован |
Catalog GetTourSnapshotForExistingBooking
|
создание предложения; подходит и снятый с публикации тур |
Identity GetUserSummary
|
GET /bookings/{id} для менеджера и админа (имя и email клиента); роль пользователя в ValidateBookingAccess
|
сервер ValidateBookingAccess
|
Chat проверяет, есть ли у пользователя доступ к заявке |
Цена в снимке: самое дешёвое предложение тура, действующее сегодня; если такого нет, самое дешёвое из всех; если предложений нет, 0 USD. Подробно: Межсервисные контракты.
GET /favorites, POST /favorites/{tourId} (409, если уже есть), DELETE /favorites/{tourId}. Карточки избранного фронтенд берёт из Catalog: GET /catalog/tours/cards?ids=.
При создании заявки, смене статуса и отправке предложения в той же транзакции пишутся сообщения BookingCreated, BookingStatusChanged, ProposalSent. Обработчика, который бы их отправлял, в коде нет: сообщения остаются в статусе Pending. Задача на этапе 1: MVP-1.
ConnectionStrings__BookingDb, JwtSettings__*, GrpcSettings__InternalServiceToken, GrpcClients__CatalogServiceUrl, GrpcClients__IdentityServiceUrl.
Система
API
Сервисы
Как реализовано
Справочное
- Видение продукта
- Дорожная карта
- Этап 1: что осталось
- Этап 2: расширение
- Этап 3: масштабирование
- Концепция сайта и интерфейса
- Шаблон ТЗ