Thesis project · Hospitality SaaS
Bouquet
Multi-tenant hospitality OS for restaurant chains — role dashboards, Spark analytics, and guest QR ordering.
Summary
The Challenge
Restaurant chains operating with fragmented tools and zero visibility across locations. Owners had no unified view of performance, and managers relied on spreadsheets for critical decisions.
The Solution
A multi-tenant Hospitality OS with role-based dashboards, Apache Spark analytics, and a guest-facing QR ordering system — all powered by real-time data pipelines.
The Impact
52 documented KPIs across 3 roles with <30s data refresh latency. A complete platform from strategic chain vision to individual table orders.
“Every data point should answer a question a restaurant manager actually asks.”
The Design Principle
Constraints
What shaped the architecture.
The context that shaped every architectural decision in the platform.
Multi-Tenant Data Isolation
Three distinct roles (Super Admin, Zone Manager, Branch Manager) each need completely different views of the same data. We implemented PostgreSQL Row Level Security (RLS).
Real-Time Kitchen Operations
Kitchen orders flow through PENDIENTE → EN_PREPARACIÓN → LISTA states in real time. Branch managers see live status without page refresh.
52 Operational KPIs
Each KPI has a documented SQL formula. The Spark pipeline processes raw transactions into Gold analytics tables that power every dashboard metric.
Zero-Friction Guest Experience
Guests scan a QR code per table — no app download, no account creation. Browse menu, track orders, split bills, and get a digital receipt.
Product screenshots
Three views, one data source.

Super Admin
Strategic vision of the entire chain — GMV, zone comparison, top products.

Zone Manager
Comparative view across branches — trends, staff performance, payment methods.

Branch Manager
Operational control of a single location — kitchen status, table occupancy, waiter performance.
Key decisions
Trade-offs behind the platform.
Row Level Security
Each role sees only their data. Super Admins see the full chain, Zone Managers see their region, and Branch Managers see their restaurant. We enforced this at the database level with Supabase RLS policies rather than application-level filtering — a single policy bug cannot leak data across tenants.
The Operational Cost
RLS policies must be written for every new table. Migration complexity increases significantly, and debugging permission issues requires deep PostgreSQL knowledge.
Spark + Gold Tables
Raw transactional data flows through an Apache Spark pipeline that aggregates, cleans, and materializes Gold tables. Dashboards query pre-computed aggregations instead of scanning millions of raw rows — keeping refresh latency under 30 seconds.
The Operational Cost
Pipeline orchestration adds infrastructure complexity. Schema changes in raw data must propagate through Bronze → Silver → Gold layers, requiring coordinated deployments.
QR Menu Flow
Each table has a unique QR code that resolves to a session-less guest interface — no login, no app download. The guest browses the menu, places orders, and tracks preparation status in real time. Split-bill functionality was the hardest UX challenge.
The Operational Cost
Anonymous sessions require careful state management. The split-bill feature alone added three new database tables and complex transaction logic to handle partial payments.
Lessons learned
What broke while building a thesis platform.
Building a production-grade platform as a thesis project taught us that academic rigor and real-world engineering have very different failure modes.
RLS Policy Explosion
Every new feature added 3-5 RLS policies. We ended up with over 60 policies across 20+ tables. A single misconfigured policy caused Zone Managers to see other zones' data in staging.
Spark Pipeline Cold Starts
The first Spark job after a schema change took 3x longer due to cache invalidation. We learned to version Gold table schemas and run parallel pipelines during migrations.
Guest Session Orphaning
QR sessions that expired mid-order created orphaned records. The kitchen would receive orders with no valid session to send status updates to. We added a cleanup cron job and session extension logic.