Termine
Bundled React module for appointment types, weekly booking windows, internal bookings, a public booking embed, and appointments agent tools.
What it does
book-appointment ("Termine") is a bundled React module for appointment scheduling: it manages appointment types (duration, buffer, optional price), weekly availability windows, and the resulting free slots, and lets staff book appointments internally. It also powers a public, embeddable booking page so website visitors can request appointments; public requests arrive as pending and are confirmed from the module.
All data lives in the app's own appointments backend (/api/appointments/*), not in a module-local store, so the same types, windows, and bookings are shared with the agent tools and the public embed.
How to open it
- Web:
/modules/book-appointment(bundled module, slugbook-appointment). - Manifest:
bundled-modules/book-appointment/module.json(renderer: "react"); React UI:src/components/modules/book-appointment-module.tsx. - Public booking page:
/embed/book-appointment(for iframe embedding on external websites), backed by/api/public/book-appointment/*. - The module is bundled; it starts uninstalled on new minimal-policy instances and remains installed on grandfathered legacy-policy instances. Admins can install or uninstall it from the module store. It does not require developer mode.
Key workflows
Define appointment types
- In the "types" panel, create a type with name, duration (minutes), buffer after (minutes), and an optional price. Types carry a color and active flag.
- Select a type to preview its free slots in the chosen date range.
Set weekly availability
- Add availability windows per weekday with a start and end time (for example Mon 09:00-17:00).
- A window can apply to all types or be restricted to one appointment type.
- Free slots are computed from the windows, the slot step, existing bookings, buffers, minimum notice, and the booking horizon.
Book internally
- Pick a free slot in the "internal booking" panel, enter the customer's name (email/phone/notes optional), and save. Internal bookings are created with status
booked. - The "upcoming" list shows non-cancelled appointments; per row you can confirm a
pendingrequest (sends the customer a confirmation email when email is configured), mark abookedappointmentcompleted, or cancel.
Publish the public booking page
- In the embed panel, toggle the public page on/off and edit its public title and intro text.
- Copy the generated iframe snippet (
<iframe src=".../embed/book-appointment" ...>) into any external website. - Visitor bookings arrive with source
public_embedand statuspending, and the visitor receives a request-received email; staff confirm them from the module.
How the agent can drive it
The native runtime exposes first-class appointment tools (tool-catalog family "Termine"). All four are public-safe: they never reveal existing bookings or customer data, so they are also available to public embed specialists.
appointments_list_types— list active appointment types and durations.appointments_list_free_days— per-day free-slot counts for oneappointment_type_idover afrom/todate range; use for "which days are free?" overviews.appointments_list_free_slots— concrete free start/end times for one type; optionalfrom,to(YYYY-MM-DD),limit(1-100).appointments_book— book one chosen slot; required:appointment_type_id,start_at(fromappointments_list_free_slots),customer_name,customer_email; optionalcustomer_phone,notes. From an internal chat the booking is created directly asbooked(sourceagent); from the public embed it becomes apendingrequest and triggers the request-received email.
On the module page and the public embed surface, the chat agent is instructed to use these tools instead of describing manual steps.
API reference
Internal (authenticated), base /api/appointments:
| Route | Purpose |
|---|---|
GET /overview | settings, types, availability windows, and appointments for a date range |
GET /settings, PATCH /settings | read/update scheduling settings |
GET /types, POST /types, DELETE /types/:id | manage appointment types |
GET /availability, POST /availability, DELETE /availability/:id | manage weekly windows |
GET /slots, GET /days | free slots / per-day availability for one type |
GET /appointments, POST /appointments | list/create bookings |
PATCH /appointments/:id/status, DELETE /appointments/:id | change status / cancel |
Public (unauthenticated, CORS-enabled), base /api/public/book-appointment: GET /config, GET /days, GET /slots, POST /appointments. The module's own module API (/api/modules/book-appointment/api) only serves GET /health and points everything else to /api/appointments.
Configuration & limits
Settings (stored via /api/appointments/settings):
- timezone (default
Europe/Berlin) - booking horizon in days (default 45, 1-365)
- minimum notice in minutes (default 120)
- slot step in minutes (default 15, 5-240)
- public page enabled flag, public title, and public intro text
Appointment statuses are pending, booked, completed, cancelled; sources are internal, agent, public_embed, public_api. Schema migrations: db/migrations/156_book_appointment_module.sql, 159_appointment_type_prices.sql, 165_appointment_pending_confirmation_emails.sql.
Troubleshooting
- No free slots shown: check that the selected type is active, at least one availability window covers the date range, and the range is within the booking horizon and minimum notice.
- Public page shows nothing: the public toggle (
public_enabled) is off; enable it in the embed panel. - Visitor never got a confirmation: pending requests must be confirmed in the module (status
booked); the confirmation email is sent on that transition when email is configured.
