Case study
MenuMate
A web app where restaurants build their menu, put a QR code on each table and receive guests’ orders on a live dashboard. Guests order from their phones without an app and pay the restaurant directly.
- Role
- Sole designer and developer
- Type
- Independent product
- Timeline
- 2025 – today
- Status
- Live, free to use
- Next.js
- TypeScript
- Supabase
- PostgreSQL
- Tailwind CSS

Problem
Restaurant owners need a menu that guests can read on their phones and that staff can update themselves, plus a way to take orders from every table. Guests shouldn’t have to install an app.
Ownership
I designed, built and launched MenuMate on my own: the database schema and access rules, the API routes, the guest menu and its themes, the owner dashboard, the emails and the printable QR sheets.
Constraints
- I work on it alone and part-time, alongside contract work.
- Its first market is Tunisia, where Stripe isn’t available and local gateways don’t offer automatic recurring billing. In September 2026 I removed the billing screens and made MenuMate free. It doesn’t handle payments: guests pay the restaurant the way they already do.
- The Tunisian dinar has three decimal places, so prices and totals are stored and shown with three decimals.
Architecture
MenuMate is a Next.js app (App Router, TypeScript) on Vercel, backed by Supabase for Postgres, authentication, realtime updates and file storage.
Each restaurant’s menu is rendered on the server at its own URL, in one of three themes. A small client-side loader downloads only the theme the restaurant picked, so a menu doesn’t carry every theme’s CSS.
When a guest sends an order, an API route checks the restaurant, the table, the items and their prices, then calls a Postgres function that saves the order with its items. The owner’s dashboard subscribes to a realtime channel for that restaurant and falls back to polling every 60 seconds if the connection drops.
It’s multi-tenant: one account can run several restaurants, each with its own menus, orders and staff access. Row-level security policies keep each restaurant’s data separate, and each owner’s images sit in their own storage folder. QR codes are generated in the browser, printable menus and QR sheets are rendered as PDFs, and the interface is in English and French.
Tradeoff
Orders used to be saved in two requests: first the order, then its items. The dashboard listens for new orders in real time, so the insert event could arrive before the items existed and show the kitchen an empty ticket. A failure between the two requests also left orders without items.
I moved order creation into one Postgres function that inserts the order and its items in a single transaction. The guest’s browser picks the order id, so if a response is lost and the request is retried, the function returns the existing order instead of sending the kitchen a duplicate. The tradeoff is that this logic now lives in SQL, in a database migration, rather than in the TypeScript API route.
Testing & reliability
- A SQL script runs 11 checks that one restaurant can’t read or change another restaurant’s data, against a local database, and rolls everything back afterwards.
- Money formatting and arithmetic have assertion tests, including three-decimal dinar amounts.
- Most API routes validate input with zod. The order route checks ids, the table, prices and a 25-item cap, and limits each client to 10 orders a minute per restaurant.
- Not done yet: there is no CI pipeline and no end-to-end browser tests. The test scripts run by hand.
Outcome
MenuMate is live at menumate.net and free to use. Owners can sign up, build a menu, pick a theme, print table QR codes and take orders on the live dashboard. A demo restaurant’s menu is public, so you can try the guest side.
Evidence
The screenshots below show the public demo menu on a phone and the live orders board with a test order. The code is in a private repository.
(full-size image, opens in a new tab)
(full-size image, opens in a new tab)More case studies
- KartaTunisie
Independent product
- Internly
Final-year project, Bachelor’s in Computer Science
- PromptStream
Independent product