Double-booked at 6am
Two teams booked the same rehearsal room. Both show up. The engineer moves mics. The crew moves mics back. The speaker arrives to chaos.
Reservations
One reservation engine across every resource type, with a GIST exclusion constraint at the database that makes overlap impossible under concurrent writes. Approval workflows where you want them, a clean API where you don't.
If your calendar can allow two reservations to overlap, it will — no amount of discipline from your team will prevent it. Spaces makes overlap impossible at the database, where discipline doesn't matter.
Two teams booked the same rehearsal room. Both show up. The engineer moves mics. The crew moves mics back. The speaker arrives to chaos.
Rehearsal rooms live in one tool. Stages live in a spreadsheet. Trucks live in somebody's head. A cross-resource view doesn't exist because the data doesn't.
High-value resources need approval. The workflow is "screenshot the calendar, Slack the manager, wait for a reply." No record, no audit, no retry.
Maintenance, VIP holds, union breaks — blackouts exist in someone's head. When a booking slips through, nobody knows until the day of.
Overlap protection that holds under concurrent writes, polymorphic resources so one module can book another's, and an approval workflow that doesn't live in Slack.
A GIST exclusion constraint on the time range makes double-bookings impossible at the database level. Not app-layer guesswork — a true concurrency-safe guarantee.
Rehearsal rooms, produce floor plans, standalone resources — all resolve through one resources table. One calendar, every resource type.
Per-resource requires_approval flag routes reservations through a pending → confirmed | rejected state machine. High-value resources get gated; day-to-day bookings flow through.
The check_reservation_conflict() RPC returns a friendly 409 before a conflict hits the database, so the UX is informative. The GIST constraint is the ultimate guarantor.
Maintenance windows, holds, breaks — blackouts are real rows with actors, reasons, and lifecycles. Bookings against blackouts fail cleanly, with the reason visible.
Creating a rehearse session reserves the room automatically. Cancelling releases it. Cross-module coupling without the drift — both systems read the same record.
Every create, approve, reject, and cancel emits a platform event. Command Center, notifications, downstream modules all subscribe — the calendar is reactive, not batch-refreshed.
Rig-build windows, daily rehearsal slots, weekly production meetings — recurring reservations are expanded into discrete rows with the same conflict protection as one-offs.
Connected by Design
Spaces doesn't own calendars — it owns the authoritative reservation record. Rehearse, Produce, and any future module all book through Spaces, so there is exactly one truth for what resource is committed when.
Inbound — data flowing into Spaces
Creating a rehearse session reserves the room automatically via the session → reservation link. Cancelling the session releases the room in the same transaction.
rehearse.session.createdOutbound — events Spaces publishes
When a reservation is cancelled on the Spaces side (maintenance, blackout), the linked session is flagged for the rehearse team — no stale bookings.
spaces.reservation.cancelledThe reservation engine doesn't need AI. But capacity planning, approval tracking, and risk surfacing do — so specialists live at the edges, never in the booking path.
Proposed reservations near capacity or near blackouts get flagged before submission — not with a hard reject, with context, so the booker can decide.
Per-resource utilization % surfaces over-booked rooms and under-used ones. Capacity planning becomes a view, not a spreadsheet.
Reservations sitting in pending approval past a threshold surface with the approver and the resource. Nothing rots waiting for a reply.
The platform is live. Request a demo to see Spaces in action.
Part of a 13-module platform that adapts to your operation. No commitment required.