Bookings
Purpose
A booking is a customer’s reservation for a single session. Small context (2 entities) but central: every booking crosses 5 other contexts — Catalog (session), Companies (customer), Passes (entitlement coverage), Wallet (balance debit, refund) and Payments (gateway when paid by card).
The Booking extra child rows snapshot each extra purchased alongside the booking.
Boundaries
- In: the reservation record and its extras snapshot.
- Out:
- What is being booked (session, time slot) — Catalog.
- Who — Company customer.
- Pass coverage — Customer entitlement; when a booking is paid by a pass,
booking.customer_entitlement_idis set. - Money flow —
wallet_debited/bonus_debitedflags here record that a debit happened; the actual ledger lives in Wallet and Payments. - Refunds — Refund request — 0..1 per booking.
Entities
| ID | Entity | Role |
|---|---|---|
| ENT-003 | Booking | The reservation — status, payment state, links to wallet/pass/refund |
| ENT-004 | Booking extra | Snapshot of an extra purchased with the booking |
Backend implementation
- No dedicated feature library. Booking logic lives inside
libs/features/activities/— seebookings-client.service.tsand related controllers. The domain context (bookings/) and the file layout intentionally differ. - Surface routing:
- Client: rich —
/my-bookings, pay, cancel, list-by-session, list-by-company. Guest sub-surface (X2):POST /api/client/guest/companies/:companyId/sessions/:sessionId/bookingsmounted on a sibling controllerBookingsGuestController(no class-level guard, method-level@Public()+ThrottlerGuard). The guest controller and service (bookings-guest.service.ts) live in the samelibs/features/activities/lib and the sameActivitiesClientModule— the guest path is a thin adapter that reusesBookingsClientService.createBookingForCustomerandBookingsService.resolveCustomerId(widened topublicfor X2). - Business: embedded-only — bookings surface via
SessionBookingDtoinside session expansion (SessionResponseDto.bookings,activeBookingsCount). No top-level admin CRUD by design.
- Client: rich —
- Module wiring:
ActivitiesClientModulenow exportsBookingsClientService(X2 — so future cross-module consumers can inject the same orchestrator; intra-module DI already worked). - Drizzle schema:
libs/shared/data-access-db/src/lib/schema/bookings.schema.ts(pgSchema('bookings')). No X2 migration — the guest flow stores rows withcompanyCustomers.userId = NULL, which the existing schema already supports.
Cross-context relationships
- This context owns
bookings.bookingsandbookings.booking_extra. - This context references (all cross-schema FKs, allowed because relationships are central):
- This context is referenced by:
Open questions
- OPEN: the
PENDING_PAYMENTbooking status is documented in the schema comment as the post-fact billing recovery state (when aSLOT_ATTENDEEbooking finishes its session without wallet funds). Confirm the exact code path that transitions a booking into and out of it. - Bookings’ physical co-location in the activities feature lib is intentional today — extracting a dedicated
libs/features/bookings/is open work, not blocking.