PhoenixKit plugin module for universal bookings.
One install can mix bookable services with entirely different shapes — the booking mode is per-service configuration, never a module setting:
Day / night (
time_unit: "day" | "night") — hotel-style date-range stays with pooled room inventory (seats), min/max stay, blackout dates, check-in/check-out display times.- Fixed slots (
time_unit: "minutes",flexible_duration: false) — massage-parlor-style slot grids (duration+slot_interval). - Free-form (
flexible_duration: true) — gym-style "pick any start, any length" withmin_duration/max_duration(nil= unbounded).
The slot/validation engine is phoenix_live_calendar's booking layer
(BookingConfig / Availability / Constraints / TimeSlots), adapted
in PhoenixKitBookings.Engine; the date-granular path lives in
PhoenixKitBookings.Engine.DayEngine. Creation is race-proof — see
PhoenixKitBookings.Bookings.
How it works
use PhoenixKit.Modulemarks this module as a plugin.- PhoenixKit discovers it by
.beamscanning — no config line needed. migration_module/0points atPhoenixKitBookings.Migrations.Schema;mix phoenix_kit.updatecreates the three tables — no core PR needed.- Admin pages ride on
admin_tabs/0; the public booking pages (/bookings,/book/:slug,/bookings/manage/:token) come fromPhoenixKitBookings.Web.Routes.generate/1.
Installation
Add to your parent app's mix.exs:
{:phoenix_kit_bookings, "~> 0.1.0"}Run mix deps.get, then mix phoenix_kit.update to create the tables.
The module appears in the admin sidebar and Modules page automatically.
Embedding
PhoenixKitBookings.Web.Public.BookingWidgetLive is embeddable via
live_render/3 on any host page — see its moduledoc for the session
contract.
Summary
Functions
Admin sidebar tabs: a parent tab plus visible Reservations + Services
lists and hidden leaf tabs for the service form. Static /new is
ordered before the :uuid wildcard tab so route generation (list
order) doesn't let the wildcard shadow it.
OTP apps whose templates Tailwind should scan for CSS classes.
Disables the module. Same pattern as enable_system/0.
Enables the module by persisting a boolean setting.
Whether the module is currently enabled.
Versioned migration coordinator for the bookings tables. Picked up
automatically by mix phoenix_kit.update — the tables are not part of
core phoenix_kit's own migration chain.
Unique key for this module. Used in settings, permissions, and PubSub events.
Display name shown in the admin UI.
Permission metadata. Calendar-module orientation (a sub implies its
base, so the base must be the NARROW capability): the base key grants
the bookings admin area scoped to services the user OWNS — the key an
owner hands out for self-service; bookings.manage_all is site-wide
management + module settings.
Public booking routes (the admin pages ride on admin_tabs/0).
Settings page (self-service policy) under Admin → Settings.
Version string (from mix.exs via the app spec, so it can't drift).
Functions
Admin sidebar tabs: a parent tab plus visible Reservations + Services
lists and hidden leaf tabs for the service form. Static /new is
ordered before the :uuid wildcard tab so route generation (list
order) doesn't let the wildcard shadow it.
OTP apps whose templates Tailwind should scan for CSS classes.
Disables the module. Same pattern as enable_system/0.
Enables the module by persisting a boolean setting.
Whether the module is currently enabled.
Reads from the DB-backed settings table. Defensive against DB not being
available yet (startup ordering, missing table, sandbox artifacts in
tests) — always falls back to false.
Versioned migration coordinator for the bookings tables. Picked up
automatically by mix phoenix_kit.update — the tables are not part of
core phoenix_kit's own migration chain.
Unique key for this module. Used in settings, permissions, and PubSub events.
Display name shown in the admin UI.
Permission metadata. Calendar-module orientation (a sub implies its
base, so the base must be the NARROW capability): the base key grants
the bookings admin area scoped to services the user OWNS — the key an
owner hands out for self-service; bookings.manage_all is site-wide
management + module settings.
Public booking routes (the admin pages ride on admin_tabs/0).
Settings page (self-service policy) under Admin → Settings.
Version string (from mix.exs via the app spec, so it can't drift).