Multi-Venue Restaurant Reservation Platform
Multi-tenant reservation engine for independent venues, with per-venue database isolation, a custom availability engine and async guest communications on a Laravel 12 core.
- Client
- Confidential · Hospitality SaaS
- Role
- {{TODO: e.g. Solution Architect / Lead Backend Engineer}}
- Period
- {{TODO: e.g. 2024–2025}}
Summary
Overview
The system is a multi-tenant reservation platform for independent restaurants and venues. It manages the full booking lifecycle, area and table seating, per-venue availability rules, guest communications and promotional features (gift vouchers, promo codes) behind a stateless Laravel 12 API.
The core challenge was delivering strict per-tenant isolation without rebuilding the application per venue, while re-implementing a monolithic predecessor's business rules and matching its API response format exactly so existing clients keep working.
Context
The Problem
Independent venues each need their own booking rules, opening hours, seating layout, payment gateways and messaging templates, plus data isolation for compliance and simplicity. The legacy monolith coupled tenants tightly, making tenant switching slow and customization awkward.
Constraints
- Isolate every venue's data while keeping one codebase and one deployment.
- Re-implement availability rules that vary per venue — custom durations, sitting times, area capacity overrides and overbooking toggles — without regressions.
- Preserve legacy API response format exactly so existing clients require no changes.
- Keep booking responses fast while confirmations and reminders fan out to thousands of guests.
Scope
Requirements
Functional
- ▹Booking lifecycle: creation, confirmation, cancellation and status tracking (unconfirmed, confirmed, seated, finished)
- ▹Availability checking per-area and cross-area with custom durations and sitting times
- ▹Table management: area-based seating, capacity, assignment and fully-booked detection
- ▹Guest communications: confirmation and cancellation emails plus SMS reminders and venue notifications
- ▹Promotions: gift vouchers with redemption and balance tracking, plus promo codes
- ▹Reporting: booking statistics, guest export and daily handover notes
- ▹Per-venue settings: hours, booking rules, payment gateways and email templates
Non-functional
- ▹Multi-tenancy — an isolated MySQL database per venue with API-key based tenant switching
- ▹Async notifications — queued email and SMS so the request path never blocks on delivery
- ▹Legacy compatibility — logic and response-format parity with the monolithic predecessor
- ▹Stateless API design for horizontal scaling behind a load balancer and shared queue backend
- ▹Observability — Sentry error tracking with tenant-tagged structured logging
System Design
Architecture
Tenant-Switch Middleware
ApiPostAuth resolves the venue from the API key and rebinds the database connection per request, giving per-venue isolation from one codebase without route model binding.
Availability and Sitting-Time Engine
Centralizes the highest-risk logic — custom durations, sitting times, area capacity overrides and overbooking toggles — in one testable, auditable service.
Layered Business Core
Controller to service to repository layering keeps HTTP concerns, business rules and data access separate and supports the legacy migration path.
Notification Dispatcher
Queues confirmation and cancellation emails plus SMS reminders so guest communications run off the request path with retries.
Legacy Parity Mapping
Field mapping across service, repository and resource layers reproduces the predecessor's exact response shape, field names and error codes.
Stack
Technology Stack
Backend
Data
Frontend
Notifications
Quality / Ops
Persistence
Data Model
- Booking: b_code (unique), area_id (0 = waitlist), date, time, party size, status (unconfirmed, confirmed, waitlist, cancelled)
- Area: section or zone with capacity, opening hours and cutoff times
- Table: table_id, area_id, capacity and availability state
- Settings: per-venue config for email, SMS, payment and booking rules
- User: minimal guest record (email); API-key driven with no login
- OpeningHours / BookingRule: per-area hours and capacity or overbooking constraints
- DailyNote: staff handover notes
- GiftVoucher: promotion with redemption and balance tracking
- BookingLabel: internal tags and categories
Reasoning
Key Decisions & Trade-offs
Separate MySQL database per venue
trade-off
More databases to operate and no cross-tenant joins, but strong isolation, simpler compliance and a bounded blast radius per venue.
API-key tenant switching in middleware (no route model binding)
trade-off
Manual model resolution in the service layer because SubstituteBindings runs before tenant selection, but stateless auth and clean per-request isolation.
Service layer owns business rules
trade-off
More files and a deeper call stack, but testable rules and a safer path for migrating logic off the monolith.
Queued email and SMS notifications
trade-off
Eventual consistency and reliance on a healthy worker, but non-blocking booking responses with retry handling.
Legacy logic and response-format parity
trade-off
Constrains design freedom and embeds some legacy shape, but existing clients need zero changes at cutover.
Operations
Scaling & Reliability
Horizontal: stateless controllers behind a load balancer; per-request tenant selection keeps instances interchangeable.
Isolation: one database per venue limits blast radius and makes backup and recovery per-venue, at the cost of cross-tenant query complexity.
Async: separate queue workers absorb email and SMS fan-out off the request path, with retries and Sentry capturing failed jobs.
Observability: Sentry plus tenant-tagged structured logging keeps failures attributable to the venue that produced them.
What made this hard
Architect's Challenges
- →Delivering per-tenant isolation from a single codebase without rebuilding the app per venue
- →Taming the availability engine — custom durations, sitting times, capacity overrides and overbooking — as the highest-risk component
- →Reproducing the monolith's exact API response format so existing clients keep working
- →Fanning out thousands of confirmations and reminders without blocking booking responses
Results
Outcome
- ▹Self-service venue onboarding via API keys with no manual database wiring
- ▹Notification failures isolated to workers and surfaced through Sentry rather than failing requests
- ▹{{TODO: add real metrics — venues onboarded, bookings/day, notification volume, latency}}