Lead Full Stack Developer

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.

1

Client requests a slot → API checks cached availability from Redis

2

Redis lock acquired on {resource_id}:{slot_start} — concurrent attempts rejected immediately

3

Booking persisted to Postgres inside a DB transaction with tenant scope enforced

4

Event broadcast over WebSocket to the practitioner's live dashboard

5

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

LaravelNext.jsPostgreSQLRedisWebSocketsAWSDockerStripe

Have a similar problem you're trying to architect your way through?