PhoenixKitBookings
Universal booking module for PhoenixKit.
One install runs any mix of booking shapes — the shape is per-service configuration, never a module-level setting:
| Archetype | Config | Example |
|---|---|---|
| Day / night stays | time_unit: night (or day), pooled seats inventory, min/max stay, check-in/out times | A hotel room type with 7 rooms |
| Fixed slots | time_unit: minutes, duration + slot_interval grid | A massage parlor booked on the hour, for an hour |
| Free-form | flexible_duration, min_duration, max_duration (blank = unlimited) | A gym floor booked from any time, for any length |
All three coexist in one install (a hotel that also offers massages), share
one admin, one public surface, and one bookings table.
Features
- Rules engine from
phoenix_live_calendar's booking layer: availability windows (weekly rules + date overrides + block-outs), buffers, minimum notice, booking window, per-slot/per-date pooled capacity, cross-midnight-correct validation. - Race-proof creation — requests re-validate inside a
FOR UPDATEtransaction on the service row; the last seat can only be taken once. - Live everywhere — every mutation broadcasts on per-service and admin PubSub topics; public pickers grey out a just-taken slot in real time and admin lists refresh across sessions.
- Public booking pages (
/bookings,/book/:slug) with guest booking, per-service signup policy (anyone/login_required), optional approval flow (require_approval→ pending, RSVP-style), and tokenized guest self-service (/bookings/manage/:token— view + cancel, no account needed). - Embeddable widget —
PhoenixKitBookings.Web.Public.BookingWidgetLivemounts on any host page vialive_render/3(see its moduledoc for the session contract). - Named units — optionally name the individual rooms/chairs/courts;
capacity becomes the active-unit count and every booking is
auto-assigned a free unit (pooled counting stays the default — the
Booqable
trackabledichotomy, per service). - Slot holds — advancing to the details form reserves the picked
range for 5 minutes (Cal.com
SelectedSlotspattern); rivals see it taken, expiry is lazy, the locked create still decides. - Providers — attach a staff person to a service; their bookings block each other ACROSS services (a therapist can't be double-booked between "Massage" and "Consultation").
- Pricing — per-service price per booking/hour/day/night; totals are computed and stored on each booking and shown everywhere. Payment collection (billing checkout) is deliberately not wired yet.
- Emails — confirmation (with
.icscalendar attachment + manage link), approval, cancellation, and Oban-scheduled reminder emails, all best-effort via core's mailer. - Waitlist — full dates offer a join form; a cancellation emails every open entry for the freed dates (notify-all, first-to-book).
- Cancellation windows — per-service
cancel_noticegates guest self-cancellation; admins are never blocked. - Ownership + permissions — base
bookingspermission scopes the admin area to services the user OWNS;bookings.manage_allis site-wide. Owner-controlled self-service settings: whether users may create their own services and how many (0= unlimited). - Admin — Reservations (filter tabs, approval queue, cancel), Services (mode-aware form, availability rules + named-units editors, soft-delete trash), and a Settings page for the self-service policy.
Installation
# mix.exs of your PhoenixKit host app
{:phoenix_kit_bookings, "~> 0.1.0"}
Run mix deps.get, then mix phoenix_kit.update — the module owns its
versioned migration (PhoenixKitBookings.Migrations.Schema, discovered via
migration_module/0), so no core upgrade is needed. Enable Bookings on
the admin Modules page.
Development
mix test.setup # createdb phoenix_kit_bookings_test + migrations
mix test # 74 tests; :integration auto-excluded without a DB
mix precommit # compile --warnings-as-errors, credo --strict, dialyzer
Cross-repo work against local checkouts: PHOENIX_KIT_PATH=../phoenix_kit
and/or PHOENIX_LIVE_CALENDAR_PATH=../phoenix_live_calendar (unset = the
published Hex pins). See AGENTS.md for architecture notes.