Sessionora - Multi-Tenant Booking at Scale
Designing a multi-tenant booking platform that guarantees zero double-bookings under concurrent write pressure, while keeping every tenant's data provably isolated on a shared database cluster.
0%
Booking conflict rate
< 50ms
P95 availability lookup
Real-time
Dashboard update latency
500+
Tenants supported per cluster
Problem
Coaches and consultants needed a single workspace to manage bookings, payments, and client history — but no existing tool handled team accounts, timezone-spanning clients, and concurrent booking attempts on the same slot without creating conflicts.
Challenges
- Preventing race conditions when two clients attempt to book the same slot within milliseconds of each other
- Modeling recurring availability rules across timezones without corrupting daylight-saving-time edge cases
- Keeping tenant data strictly isolated while sharing a single database cluster for operational simplicity
- Delivering real-time booking updates to the practitioner's dashboard without polling
Architecture
Sessionora runs on a Laravel API with a Next.js frontend. Each organization is a tenant scoped by a tenant_id enforced at the query-builder layer via global model scopes, so no query can accidentally leak across tenants. Booking writes go through a dedicated availability service that acquires a short-lived Redis lock keyed by slot and resource before the write is committed to Postgres, eliminating the double-booking race entirely. A WebSocket layer pushes booking, cancellation, and reschedule events to connected dashboards in real time.
Client requests a slot → API checks cached availability from Redis
Redis lock acquired on {resource_id}:{slot_start} — concurrent attempts rejected immediately
Booking persisted to Postgres inside a DB transaction with tenant scope enforced
Event broadcast over WebSocket to the practitioner's live dashboard
Async job queued for confirmation email, calendar sync, and reminder scheduling
Database Design
Postgres schema uses a shared-database, shared-schema multi-tenancy model with a tenant_id foreign key on every tenant-scoped table, enforced by row-level Laravel global scopes and mirrored with Postgres row-level security as a defense-in-depth layer. Availability is stored as normalized recurrence rules, not expanded instances, and materialized into concrete slots on read — keeping storage compact while supporting arbitrarily far date-range queries.
Scalability
Read-heavy availability queries are cached in Redis with short TTLs and invalidated on write, keeping the hot path off Postgres entirely for typical traffic. The booking-lock pattern means write throughput scales horizontally across API nodes without a single point of contention beyond Redis itself. Background jobs for reminders, emails, and calendar sync run on a separate worker pool so a spike in notification volume never slows down the booking API.
Outcome
Zero double-booking incidents recorded since the locking layer shipped, with slot-lookup latency under 50ms at the 95th percentile and real-time dashboard updates replacing what was previously a polling interval.
Tech Stack
Have a similar problem you're trying to architect your way through?