Booker and Booker Embed Atoms
Purpose and Scope
The Booker area is the booking-flow surface where a visitor chooses an available time and attempts to create a booking. For developers extending Cal.diy or embedding scheduling in another product, the important idea is that the user interface is not just a form around a selected slot. It participates in a concurrency-sensitive flow where schedule reads, temporary reservations, and final booking creation must agree closely enough to avoid presenting users with times that cannot be booked. The Booker README documents those user-facing failure-prevention strategies, while the platform atom provides an embeddable package surface for product integrations.
Sources: packages/features/bookings/Booker/README.md, packages/platform/atoms/booker-embed/index.ts
This page focuses on the relationship between the core Booker behavior and the platform booker embed atom. The feature README explains how the booking page handles stale availability and contested slots. The atom entrypoint shows the public package export used by consumers that want to integrate a Booker experience into their own application shell. The base atoms example README then gives a practical local workflow: run the Cal backend, run the API service, run the atoms package, run the web app, create an OAuth client, configure the example app, and test the flow locally.
Sources: packages/features/bookings/Booker/README.md, packages/platform/examples/base/README.md
Relevant Source Files
- packages/features/bookings/Booker/README.md — Documents Booker availability, reservation, refresh, and slot no-longer-available behavior.
- packages/platform/atoms/booker-embed/index.ts — Defines the public booker-embed atom entrypoint by exporting BookerEmbed from its implementation module.
- packages/platform/examples/base/README.md — Describes how to run atoms examples locally against a Cal.diy backend, API v2 service, atoms package, and web app.
Sources: packages/features/bookings/Booker/README.md, packages/platform/atoms/booker-embed/index.ts, packages/platform/examples/base/README.md
Core Primitives
The first primitive is the schedule read. In the Booker README, the schedule call returns only bookable slots and intentionally shares availability checking logic with the booking call. That shared logic matters because it reduces drift between the list a visitor sees and the decision made when the booking is confirmed. A scheduling interface can otherwise fail in an awkward way: the page may advertise a time, accept the user's form input, and then reject the booking because the server-side booking path interpreted availability differently. Booker treats that mismatch as a product problem, not merely a backend validation detail.
Sources: packages/features/bookings/Booker/README.md
The second primitive is reservation. A reservation is a lower-priority claim used to hide a selected slot from other visitors before the final booking exists. The README describes the common race where two people have the same booking page open at the same time. Both may initially see the same available slot because their schedule result was fetched earlier. When the first visitor selects the slot, the reservation system marks it for that person. If the second visitor then selects the same slot, the UI moves to the slot no-longer-available state rather than letting the user continue as if the slot were still safe.
Sources: packages/features/bookings/Booker/README.md
The third primitive is the embed atom. The platform package surface for this page is intentionally narrow: the booker-embed index re-exports BookerEmbed from the local BookerEmbed implementation. That small entrypoint is useful for consumers because it gives the package a stable import boundary while leaving implementation details inside the atom package. When documenting or reviewing integrations, treat the exported BookerEmbed as the public-facing scheduling UI atom and the Booker feature README as the behavioral contract that explains why the UI refreshes, disables confirmation, and asks the user to choose another slot in contested cases.
Sources: packages/platform/atoms/booker-embed/index.ts, packages/features/bookings/Booker/README.md
Booking Flow and Race Handling
A typical booking flow starts with the visitor viewing available slots. Booker does not rely on a single page-load schedule fetch for the entire session. The README says schedule data is fetched on window focus, on a configurable interval, and when a slot is selected. Those refresh points are chosen for realistic browser behavior: a visitor may leave a tab open, return after several minutes, or interact with a slot whose availability has changed since the first render. The refresh strategy improves the visible list before confirmation, while still accepting that stale client state can exist between refreshes.
Sources: packages/features/bookings/Booker/README.md
The slot no-longer-available state is the explicit recovery path for that stale state. When Booker detects that a selected slot is no longer available, the confirm action is disabled and the user is told to select a different slot. That is a better failure mode than allowing a doomed confirm attempt, because the interface gives immediate guidance and keeps the user in the booking context. The README separates two checks: schedule fetching prevents unavailable slots from appearing in the list, while the reservation query prevents a slot from being bookable by the current user after another visitor has reserved it.
Sources: packages/features/bookings/Booker/README.md
One subtle implementation constraint is that reservation is not checked during the final confirm booking call, because the README defines a reservation as lower priority than an actual booking. In other words, a reservation is a coordination hint for the interactive flow, not the ultimate source of truth. The actual booking wins over a reservation. Developers should preserve that hierarchy when changing the Booker flow or wrapping it in an atom. The goal is not to make reservations equivalent to bookings; it is to reduce conflicts and guide users before the final booking decision is made.
Sources: packages/features/bookings/Booker/README.md
Booker Embed Atom Surface
The source-level public surface for the booker embed atom is compact enough to summarize directly: the index module exports BookerEmbed. That tells consumers and maintainers where the import boundary sits, but it does not expose configuration details in the supplied snippet. The important documentation implication is that the atom should be discussed as an embeddable UI primitive rather than as a separate scheduling engine. It surfaces Booker behavior inside platform atom examples, while the underlying booking safety model remains the one described by the Booker feature README.
Sources: packages/platform/atoms/booker-embed/index.ts, packages/features/bookings/Booker/README.md
| Entry point | Export | Role |
|---|---|---|
| packages/platform/atoms/booker-embed/index.ts | BookerEmbed | Public atom entrypoint for embedding the Booker UI surface. |
Sources: packages/platform/atoms/booker-embed/index.ts
Local Example Workflow
The base atoms README provides the most concrete way to exercise the atom in development. It assumes a local Cal.diy backend and explicitly calls out Google credential setup as important. The workflow uses several running pieces: the API v2 app, the atoms package, the Cal web app, and the selected example app. It also requires an organization and an OAuth client in the web app, with the example app redirect URI pointing to the local example server. This makes the example more than a visual component preview; it is an integration test environment for authenticated platform usage.
Sources: packages/platform/examples/base/README.md
A minimal setup sequence, following the example README, is to configure the API environment, start the API with yarn dev, start the atoms package with yarn dev, start the web app with yarn dx, and then log in as the seeded admin user. After creating a sample organization, the developer creates an OAuth client under the platform OAuth clients settings page, grants permissions, and sets the redirect URI to the example app. The example app then receives its client identifier and secret through its environment file before its local database is reset and pushed.
Sources: packages/platform/examples/base/README.md
NODE_ENV="development"
API_PORT=5555
DATABASE_READ_URL="postgresql://postgres:@localhost:5450/calendso"
DATABASE_WRITE_URL="postgresql://postgres:@localhost:5450/calendso"
API_URL="http://localhost"
NEXTAUTH_SECRET="copy from .env of root of repository cloned in step 1"
DATABASE_URL="postgresql://postgres:@localhost:5450/calendso"
JWT_SECRET="asjdijI1JIO12I3O89198jojioSAJDU"
REDIS_URL="redis://localhost:6379"yarn dev
yarn dx
rm -f prisma/dev.db && yarn prisma db pushThe example workflow also includes a Google OAuth redirect adjustment: the Google Cloud Console credentials must authorize the local API route used to save Google Calendar OAuth state. This matters for Booker-oriented examples because scheduling experiences often depend on connected calendars for accurate availability. If the backend and OAuth client are running but Google credentials reject the callback, the user may reach the atom shell without a fully useful scheduling configuration. When debugging an embed example, verify the API port, the example app redirect URI, the OAuth client values, and the Google redirect URI together rather than treating them as separate setup tasks.
Sources: packages/platform/examples/base/README.md
Implementation Notes and Edge Cases
When modifying Booker or consuming BookerEmbed, keep the refresh cadence and state transitions visible in the product design. The README names three schedule refresh triggers and a separate reservation polling query. Those checks are not redundant; they defend against different stale-state windows. Focus refresh handles a user returning to an old tab, interval refresh handles passive waiting, selection refresh handles the moment of intent, and reservation polling catches lower-priority claims that should block the current user from proceeding. Removing one of these paths can make the interface appear faster while increasing the chance of late booking failure.
Sources: packages/features/bookings/Booker/README.md
The main user-facing edge case is two visitors selecting the same initially visible slot. Booker accepts that both visitors can see the same stale slot, but it must not let both proceed as if the slot were still available. The intended behavior is that the later visitor reaches the slot no-longer-available state, sees the confirm action disabled, and is guided back to choose another time. For atom consumers, that means embedding the Booker UI should preserve the stateful interaction rather than wrapping it in a flow that hides or bypasses the disabled-confirm state.
Sources: packages/features/bookings/Booker/README.md, packages/platform/atoms/booker-embed/index.ts
Related Pages and Next Steps
Read the Platform Atoms Overview next if you need the broader atom model and package organization. Read API v2 Overview when setting up the backend used by atoms examples. Read Booking Features and Audit Trail for adjacent booking package documentation. For implementation work, start by running the base atoms example end to end, then reproduce a contested-slot scenario with two browser sessions. That exercise validates the most important Booker contract: visible availability, reservation state, and final booking behavior must remain understandable to the user even when two people compete for the same time.
Sources: packages/features/bookings/Booker/README.md, packages/platform/examples/base/README.md