<!-- DOC_TYPE: CONCEPT -->

# Booking Module

## Purpose

`codex_django.booking` is the Django adapter layer for the booking engine that lives in `codex-services`.
Its job is not to reimplement scheduling logic.
Its job is to bridge Django project models and transaction semantics to the engine's provider-oriented interface.

This module gives a Django project three things at once:

- reusable abstract models for booking-related entities
- ORM-based adapters that convert project data into engine input
- selector functions that expose booking operations in a view-friendly form

So `booking` is best understood as an integration layer between domain data in Django and scheduling intelligence in `codex-services`.

## Architectural Boundary

The core booking algorithm is delegated to `ChainFinder` and related DTOs from `codex-services`.
`codex_django.booking` focuses on the Django-specific concerns around that engine:

- how masters, services, schedules, and appointments are modeled
- how ORM data is converted into `BookingEngineRequest` and `MasterAvailability`
- how row locking and transaction boundaries are handled during booking creation
- how busy-slot caching is invalidated safely

This separation is important because it keeps scheduling rules reusable across frameworks while still giving Django projects a practical integration path.

## Main Building Blocks

### Composable Booking Models

The `mixins` package defines abstract model mixins for the core booking entities:

- `AbstractBookableMaster`
- `AbstractBookableService`
- `AbstractBookableAppointment`
- `AbstractWorkingDay`
- `MasterDayOffMixin`
- `AbstractBookingSettings`

These are not final project models.
They are scaffolding primitives that let each project keep its own foreign keys, categories, statuses, and business details while still matching the expectations of the adapter layer.

The design choice here is composability over hardcoded schema.

### Availability Adapter

`DjangoAvailabilityAdapter` is the center of the module.
It translates Django ORM state into the provider data structures expected by the booking engine.

It is responsible for:

- building engine requests from service ids and master selections
- resolving which masters can perform which services
- collecting working hours, breaks, days off, and busy intervals
- constructing `MasterAvailability` objects
- locking master rows during booking creation

In effect, this adapter is the contract translator between Django models and `ChainFinder`.

### High-Level Selectors

`booking.selectors` contains pure-function entry points used by views and generated feature code:

- `get_available_slots()`
- `get_nearest_slots()`
- `get_calendar_data()`
- `create_booking()`

These functions keep orchestration outside of model methods.
That makes them easier to reuse from views, APIs, commands, and future generated code.

### Cache Adapter

`BookingCacheAdapter` is a thin bridge over the Redis booking cache manager from `core`.
The module's caching strategy is intentionally narrow:

- cache busy intervals per master per date
- compute free windows dynamically from those intervals
- invalidate only the affected master/date entries after a successful booking change

This keeps cache invalidation surgical and avoids storing derived slot maps as the primary source of truth.

### Booking Settings Sync

`AbstractBookingSettings` provides configurable booking defaults such as:

- slot step size
- default buffer between appointments
- advance booking limits
- fallback working hours

Its save hook synchronizes settings to Redis, following the same general pattern used elsewhere in the repository for runtime-accessed administrative state.

## Concurrency Model

The most important architectural concern in this module is not slot computation itself, but safe booking creation under concurrency.

`create_booking()` follows a defensive flow:

1. enter a transaction
2. lock the relevant master rows
3. recompute availability under lock
4. verify the requested start time still exists
5. persist the appointment or the multi-service chain
6. invalidate cache only after transaction commit

This design avoids the classic problem where a slot appears free during initial display but is taken before final confirmation.

For multi-service booking, the module introduces a `BookingPersistenceHook` protocol.
That keeps the persistence of complex booking chains project-specific while preserving the shared locking and revalidation logic.

## Runtime Flow

```mermaid
flowchart TD
    A["Django view or API"] --> B["booking selectors"]
    B --> C["DjangoAvailabilityAdapter"]
    C --> D["Project ORM models"]
    C --> E["BookingCacheAdapter"]
    C --> F["codex-services ChainFinder"]
    B --> F
    G["create_booking transaction"] --> H["lock masters"]
    H --> I["recompute availability"]
    I --> J["persist appointment or chain"]
    J --> K["invalidate cache on commit"]
```

## Role In The Repository

`booking` is the domain adapter layer for appointment scheduling.
It is where the repository turns generic booking engine capabilities into Django-usable building blocks.

That makes it different from:

- `core`, which provides shared infrastructure primitives
- `system`, which provides project-state models and admin workflows
- `notifications`, which handles message dispatch around domain events

`booking` sits closer to business behavior than those modules, but it still remains an adapter library rather than a full concrete booking application.

## See Also

- `notifications` for confirmation and reminder workflows built on top of booking events
- `system` for settings models that can store booking defaults at the project level
- `codex-services` for the actual slot-finding and chain-solving engine this module integrates with
