Scheduling architecture and workflows
Schema by domain, booking, payment, team, routing, and workflow lifecycles, named GraphQL commands, and access control.
Architecture
Route files under app/ are thin. Operator screens live in features/platform/<slice>, customer screens in features/storefront, and the shared Keystone admin shell in features/dashboard. The server contract is features/keystone/models/**, features/keystone/access.ts, features/keystone/mutations/**, and the generated schema.graphql. Scheduling logic such as availability, host assignment, routing, workflows, and payment transitions lives in features/keystone/lib. Side effects go through outbox rows that schedulingOutboxWorker.ts processes.
Data model by domain
Identity and team
Usersigns in operators and customers.Rolecarries dashboard flags:canAccessDashboard,canManageScheduling,canManageOnboarding,canSeeOtherPeople,canEditOtherPeople,canManagePeople,canManageRoles. Sessions are stored inAuthSession.Teamis the business and tenant root: name, slug, status (active,paused,archived), time zone,publicBookingEnabled, storefront copy, and logo.Memberis a person's seat in a team with role (owner,admin,host,viewer), status,roundRobinWeight,dailyBookingCapacity, andpublicProfileEnabled.TeamInvitation,TeamInvitationDelivery(email outbox), andTeamAdministrationEvent(append-only audit log).
Event types and availability
EventType: title, slug, status (draft,published,private,archived),schedulingType(individual,collective,round_robin), duration, buffers, location and conference provider,requiresConfirmation, payment policy (freeorrequired, set only throughconfigureEventPaymentPolicy), daily limits, and recurrence. It links to hostMemberrecords, aSchedule, aPaymentProvider, aConferenceConnection, and an optionalManagedEventTemplate.BookingQuestion(intake questions, at most 50 active per event type),BufferRule,EventTypeLifecycleEvent.Schedule(named weekly hours in a time zone) andAvailabilityRule(weekly,dateoverride, orblock). Overrides change throughmanageAvailabilityOverrideand are audited inAvailabilityOverrideEvent.Resource(room, equipment, or capacity pool),EventResourceRequirement(units an event type needs),ResourceAllocation(held,reserved,released,expired),ResourceLifecycleEvent.
Bookings
BookingHoldreserves a slot while the customer fills the form:heldtoconverted,expired, orabandoned.Booking: status (pending,confirmed,cancelled,completed,no_show), start and end, time zone, payment fields. It links to hosts,BookingAttendee,BookingResponse,BookingLifecycleEvent, and optionally aBookingSeriesfor recurring bookings.RescheduleRequestexists in the schema, but no code path writes it. Rescheduling is direct.
Routing, automation, delivery
RoutingForm(draft,published,archived), orderedRoutingRulerows that target an event type and optional host, andRoutingSubmission(evaluated,converted,expired).WorkflowDefinitionwith triggersbooking_created,booking_confirmed,booking_rescheduled,booking_cancelled,booking_completed,booking_no_show,before_start, andafter_end. Steps areWorkflowActionrows of typeemailorwebhook. Runs areWorkflowExecutionandWorkflowActionExecution.WorkflowReminder(email, SMS, or webhook reminder per event type) andReminderDelivery.WebhookSubscription,WebhookDelivery, andNotificationSubscription.
Payments, calendars, conferencing
PaymentProvider(stripeormanualadapter),PaymentBooking,PaymentSession,PaymentOperation(outbox),PaymentLifecycleEvent.CalendarConnection(Google or Microsoft per host),CalendarBusyInterval,CalendarEventLink,CalendarOperation.ConferenceConnection,ConferenceMeeting,ConferenceOperation.
Embeds, developers, data
EmbedConfig(draft,published,archived) and immutableEmbedReleasesnapshots.ApiKey,OAuthClient,OAuthTokenfor machine access.DataJobandDataJobEventfor imports (dry run or apply) and exports of event types, availability, resources, and bookings.AnalyticsFact,AnalyticsProjection, and the hiddenPublicRequestBucketrate-limit counter.
Customer booking workflow
storefrontEventTypesandstorefrontAvailabilityreturn published event types and open slots for the storefront team. Availability combines schedules, rules, buffers, existing bookings, calendar busy intervals, host capacity, and resource requirements.createStorefrontBookingHold(orcreateStorefrontRecurringBookingHold) creates aBookingHoldand resource allocations.createStorefrontBooking(orcreateStorefrontRecurringBooking) converts the hold. Attendee details and answers are stored. Status starts aspendingwhen the event type requires confirmation or payment, otherwiseconfirmed. Round-robin hosts are picked using member weight and daily capacity.- The receipt includes a private manage link signed with
BOOKING_MANAGE_SECRET.manageStorefrontBookinglets the guest reschedule or cancel.manageStorefrontBookingSeriescancels future occurrences of a series. - Signed-in customers use
customerBookingHistory,customerBookingDetail, andmanageCustomerBooking. - Routing path:
storefrontRoutingForm->evaluateStorefrontRoutingrecords aRoutingSubmissionand returns the matched event type and host. The submission ID carries into availability and booking.
Operator booking lifecycle
transitionBooking applies these transitions:
| Action | From | To | Extra checks |
|---|---|---|---|
confirm | pending | confirmed | Payment must be paid if required; booking must not have ended |
decline | pending | cancelled | Actor must manage the team or be an assigned host |
cancel | pending, confirmed | cancelled | |
no_show | confirmed | no_show | Booking must have started |
complete | confirmed | completed | Booking must have ended |
reschedule | pending, confirmed | keeps status | New start required; payment must be paid if required |
Every transition writes a BookingLifecycleEvent. Workflow executions, reminders, webhooks, calendar writes, and conference meeting updates follow through the outbox.
Payment workflow
configureEventPaymentPolicysets price, currency, payment window, and provider on an event type.initiateBookingPaymentcreates aPaymentSession. For storefront payments Stripe creates a hosted Checkout Session with an expiry; other Stripe payments create a PaymentIntent with manual capture. Themanualadapter records an offline payment.- Stripe events reach
/api/payments/webhook/[providerCode]and are verified against the provider's webhook secret. transitionBookingPaymentcaptures or refunds. Failed provider calls land inPaymentOperationand can be retried withretryPaymentOperation.- Session states run
created,pending,authorized,captured,refunded, withfailedandexpiredexits.
Team workflow
inviteTeamMember -> email through TeamInvitationDelivery -> invitee accepts at /account/invitation with acceptTeamInvitation -> manageTeamMember (update_profile, change_role, suspend, reactivate, remove) -> transferTeamOwnership. resendTeamInvitation, revokeTeamInvitation, and retryTeamInvitationDelivery handle invitation problems.
GraphQL commands
Besides generated list queries, the schema registers these named operations:
- Storefront:
storefrontSettings,storefrontEventTypes,storefrontAvailability,storefrontRoutingForms,storefrontRoutingForm,storefrontEmbedConfigs,storefrontManagedBooking,storefrontManagedBookingSeries,storefrontManagedBookingAvailability,createStorefrontBookingHold,createStorefrontRecurringBookingHold,createStorefrontBooking,createStorefrontRecurringBooking,closeStorefrontBookingAttempt,manageStorefrontBooking,manageStorefrontBookingSeries,evaluateStorefrontRouting,recoverStorefrontBookingCommand. - Customer account:
registerSchedulingCustomer,customerProfile,updateSchedulingCustomerProfile,changeSchedulingCustomerPassword,requestSchedulingCustomerEmailChange,confirmSchedulingCustomerEmailChange,requestSchedulingPasswordReset,redeemSchedulingPasswordReset,customerBookingHistory,customerBookingHistoryPage,customerBookingDetail,customerBookingAvailability,manageCustomerBooking. - Bookings and availability:
transitionBooking,operatorBookingAcceptedEvidence,operatorBookingRecoveryOptions,manageAvailabilityOverride. - Catalog and resources:
configureEventPaymentPolicy,applyManagedEventTemplate,detachManagedEventTemplate,upsertSchedulingResource,transitionSchedulingResource,configureEventResourceRequirement. - Team:
inviteTeamMember,resendTeamInvitation,revokeTeamInvitation,acceptTeamInvitation,retryTeamInvitationDelivery,manageTeamMember,transferTeamOwnership. - Integrations and delivery:
beginCalendarOAuth,completeCalendarOAuth,syncCalendarConnection,retryCalendarOperation,configureStripePaymentProvider,initiateBookingPayment,transitionBookingPayment,retryPaymentOperation,configureConferencingConnection,retryConferenceOperation,retryWorkflowAction,transitionWebhookDelivery,transitionNotificationSubscription,publishEmbedConfig. - Developers, data, analytics:
createSchedulingApiKey,revokeSchedulingApiKey,createSchedulingOAuthClient,revokeSchedulingOAuthClient,machineViewer,createSchedulingDataJob,retrySchedulingDataJob,schedulingAnalytics. - Onboarding:
bootstrapSchedulingOnboarding,upsertSchedulingOnboardingSampleBooking,upsertSchedulingOnboardingCalendarConnection,upsertSchedulingOnboardingPaymentProvider,updateSchedulingStorefrontBrandHue.
Operator commands take an idempotencyKey, so a retried request replays its result rather than repeating the change.
Access control
- Team scope:
teamOwnedListAccessfilters reads to teams with an active membership and restricts writes toownerandadminmembers of the owning team. Records cannot be re-parented across teams. - Hosts:
canConfirmAssignedBookinglets ahostconfirm or decline bookings they are assigned to. - Command-only lists:
Booking,Member,TeamInvitation,Resource,EventResourceRequirement,PaymentBooking,ConferenceConnection,ApiKey, and similar lists refuse raw create, update, and delete. - Dashboard: the Keystone UI and
/dashboardrequirecanAccessDashboard. Accepting a team invitation grants dashboard access. - Machine access: API keys and OAuth client-credential tokens carry scopes such as
bookings:read,bookings:write,payments:write, andanalytics:read.requireMachineScopechecks them in commands. - Public endpoints: storefront queries return bounded projections.
PublicRequestBucketrate-limits public requests. GraphQL uses CSRF prevention and query depth and size limits.
A model in the schema does not by itself mean a feature works end to end. The platform pages and named commands above are the supported paths.
Getting started with Scheduling
Clone the source, configure PostgreSQL, sessions, secrets, and storage, apply migrations, create the first admin, run onboarding, and deploy.
External dashboards
Give an LLM the Scheduling dashboard skill to adapt the built-in operator experience or create a separate client.