Skip to content

Booking Module

Purpose

codex_django.booking is the Django adapter layer for the resource-slot 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 Django domain data and resource-slot 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

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