Adapter between the Bookings domain and phoenix_live_calendar's booking
rules engine (Layer 3: BookingConfig / Availability / Constraints /
TimeSlots), plus the day/night path (DayEngine) the lib doesn't cover.
Time frame
All minute-unit math runs in the site frame — wall-clock time in the
site's configured offset (core's offset-hours model, "time_zone"
setting). v1 services are physical (hotel / massage parlor / gym), so
slots are shown and validated in venue-local time regardless of the
viewer (the Cal.com lockTimeZoneToggleOnBookingPage behavior). Storage
is always true UTC: frame_to_utc/1 on the way in, utc_to_frame/1 on
the way out. Frame datetimes are UTC-tagged shifted values (the same
trick as core's DateUtils.shift_to_offset/2 display path).
Day/night services never touch clock time — dates are frame-free by the workspace's all-day convention.
Unbounded duration
BookingConfig.effective_max_duration/1 treats nil as "same as
duration", so a free-form service with no ceiling (max_duration: nil) maps to a large sentinel instead; real fit is still enforced by
the availability-window check. (Candidate upstream tweak: an explicit
unbounded semantic in the lib.)
Summary
Functions
Maps timed bookings onto ABSOLUTELY blocking events (overlap: false,
no buffer expansion) — provider cross-service conflicts: a person can't
be in two places regardless of the current service's seat pool.
Bookable slots of a minute service on a frame-local date:
[{start_time, end_time, :available | :booked | :unavailable}].
Maps a Service row onto the lib's %BookingConfig{} (minute units).
Maps active bookings onto lib %Event{}s in the site frame.
Per-date remaining capacity of a day/night service over a date range:
%{date => remaining_seats}. Closed dates map to 0.
Shifts a site-frame wall clock back to true UTC.
Builds a true-UTC datetime from a frame-local date + time.
Maps availability rules onto lib %Availability{} structs. A service
with no rules is always open — a synthetic full-day window keeps slot
generation and validation consistent.
Site offset in seconds (core offset-hours "time_zone" setting).
Today's date in the site frame.
Shifts a true-UTC datetime into the site frame (UTC-tagged wall clock).
Validates a booking request against the service's rules and the current
active bookings. Advisory — PhoenixKitBookings.Bookings.create_booking/5
re-runs it inside a locked transaction.
Functions
Maps timed bookings onto ABSOLUTELY blocking events (overlap: false,
no buffer expansion) — provider cross-service conflicts: a person can't
be in two places regardless of the current service's seat pool.
Bookable slots of a minute service on a frame-local date:
[{start_time, end_time, :available | :booked | :unavailable}].
Maps a Service row onto the lib's %BookingConfig{} (minute units).
Maps active bookings onto lib %Event{}s in the site frame.
overlap: seats > 1 is deliberate: with one seat the event must BLOCK
(Constraints.validate_no_overlap rejects only overlap: false
events); with pooled seats events must pass the overlap check and be
COUNTED by validate_capacity/slot_status instead.
Each event is pre-expanded by the service buffers
([start - buffer_before, end + buffer_after)) because the lib buffers
only the REQUEST side: with both sides expanded, two consecutive
bookings need a gap of buffer_after + buffer_before — the existing
booking's cleanup plus the new booking's prep — which is the intended
semantics for a shared per-service buffer config.
Per-date remaining capacity of a day/night service over a date range:
%{date => remaining_seats}. Closed dates map to 0.
Shifts a site-frame wall clock back to true UTC.
Builds a true-UTC datetime from a frame-local date + time.
Maps availability rules onto lib %Availability{} structs. A service
with no rules is always open — a synthetic full-day window keeps slot
generation and validation consistent.
Site offset in seconds (core offset-hours "time_zone" setting).
Today's date in the site frame.
Shifts a true-UTC datetime into the site frame (UTC-tagged wall clock).
Validates a booking request against the service's rules and the current
active bookings. Advisory — PhoenixKitBookings.Bookings.create_booking/5
re-runs it inside a locked transaction.
range is {starts_at_utc, ends_at_utc} (DateTime, minute services) or
{:dates, starts_on, ends_on} (day/night services).
Returns :ok | {:error, reason_atom, message}.