Babke Kebab & Plates
An Express and MongoDB build for a Levantine kebab house in Hammam Sousse: a trilingual storefront with WhatsApp ordering, a loyalty card and a 3D flip-book menu, run from a 17-panel staff dashboard.
Visit live site
17
Admin panels
87
API routes
03
Languages
Babke Kebab & Plates is a Levantine grill house on Avenue des Orangers in Hammam Sousse, serving charcoal-grilled kebab platters, chawarma and chich taouk from a printed menu of twenty platters and a kids' menu. The engagement covered both sides of the counter: a public site where a customer browses that menu, composes a dish and sends the order, and a staff dashboard where the owner, the accountant, the media manager and the cashier each run their own part of the restaurant, from stock and purchase sheets to the loyalty programme.
The system is a single Express 4 process on Node.js 22 with MongoDB behind Mongoose 8, serving the landing page, the dashboard and an 87-route API. There is no front-end framework, no bundler and no build step: the page loads plain JavaScript and CSS files directly. Menu, prices, site copy, catering cards and feature settings live in MongoDB, seeded on first boot without overwriting anything staff have changed, and photos uploaded for dishes, the gallery and events are scaled to fit 800 by 800 and re-encoded as JPEG in the browser before being stored as data URIs inside the documents.
The storefront is served in English by default, with French and Tunisian Arabic, and the dialect switches the document to right-to-left. Hero, story, address, opening hours and footer copy saved in the dashboard override the built-in dictionary per language, while the dashboard itself is in French. Two Server-Sent Events streams keep staff screens and open storefronts current without polling, and the whole application runs on the agency's own VPS as a Docker container built from a two-stage node:22-alpine image behind nginx.
The Challenge
The brief was wider than a menu page. On the public side, the order had to end as a WhatsApp message on the restaurant's own number rather than in a card checkout, yet still carry everything the counter needs: the dish, the spice level, the paid add-ons from the printed menu and the customer's address or table. Behind the counter, four staff roles needed their own views of one system, the accountant's paper purchase sheets had to become forms that total themselves, and a loyalty card and a prize game had to hand out real food without trusting anything the browser sends. All of it had to read in English, French and Tunisian Arabic and run in a Docker container on the agency's own VPS.
What We Built
One Express 4 process on Node.js 22 serves the storefront, the dashboard and the API, with MongoDB through Mongoose 8 and plain JavaScript in the browser. Each dish opens a customiser with a spice level, optional per-dish choice groups and the twelve paid supplements priced by id from the database; a three-step drawer then saves the order to MongoDB and opens WhatsApp with a formatted ticket, and public order and reservation posts are rate-limited per client IP. Staff sign in through httpOnly JWT cookie sessions under four roles to a 17-panel dashboard with CSV exports and Chart.js views. The loyalty card and the wheel decide everything on the server: stamps are capped per day and keyed by idempotent request ids, and the wheel draws with crypto.randomInt behind phone, network, daily-win and stock gates. The image is a two-stage node:22-alpine build that asserts full ICU and the Africa/Tunis zone at build time, runs as an unprivileged user and answers a /healthz probe tied to the MongoDB connection.
The Outcome
The live site at babke.tn carries the trilingual storefront, the customiser and WhatsApp checkout, table reservations that land in the dashboard for staff to confirm, a catering section whose quote button opens WhatsApp, the loyalty card and its /carte web pass, the 3D flip-book and a scripted recommendation assistant, all fed from the dashboard. A cashier can mark a dish sold out and every open storefront updates over the public event stream without a reload. The prize wheel is built but still switched off, so its section shows a paused state until the owner sets the odds.
Per-dish customiser and WhatsApp checkout
Each dish opens a modal with a spice level, per-dish choice groups with required and maximum rules (built, none configured yet) and the twelve paid supplements priced by id from the database. A three-step drawer takes name, phone and address or table, saves the order to MongoDB and opens WhatsApp on the restaurant's number with a formatted ticket. No account and no online payment. scripts/cart.js, components/cartDrawer.js
3D flip-book menu
A page-turning menu generated from the live menu data: CSS 3D leaves turned with the Web Animations API, a two-page spread from 900px wide and one swipeable page below, with cover, house page and categories edited from the dashboard. Tapping a dish opens the same customiser as the main menu, and turns are instant under reduced motion. scripts/menubook.js, styles/menubook.css
Carte Babke loyalty card
Customers create a card with a first name and an 8-digit Tunisian number; the browser holds a random token, kept server-side only as a SHA-256 hash, and shows a QR of the public card id, also as a web pass at /carte. Staff activate it at the counter after an identity check and stamp it from a camera scan or a phone lookup, under a daily cap with idempotent request ids. Live with a ten-stamp goal and rewards at five and ten. scripts/loyalty.js, server.js
Server-drawn prize wheel
An SVG wheel that only animates to a result drawn on the server with crypto.randomInt over integer weights, behind a per-phone cooldown, a rolling per-network cap, a daily win cap and a stock count that cannot go below zero, with compensating rollbacks in place of transactions. Prize codes are single-use and expire. Seeded disabled and still served disabled: the public section shows a paused state until the owner sets the odds. scripts/wheel.js, server.js
Seventeen-panel back office for four roles
A French-language single-page dashboard: the owner sees all seventeen panels, the accountant eight, the media manager and the cashier seven each. Stock with per-product low-stock thresholds, end-of-day leftovers, waste by cause, cash expenses, four digitised purchase sheets and a P&L fed by website orders, plus menu, site copy, catering, reviews, orders and reservations. Exports are semicolon CSV with a UTF-8 BOM for Excel. admin/index.html, admin/admin.js
Event streams and audit trail
A staff Server-Sent Events stream announces new orders and reservations with a two-tone Web Audio chime; a public stream forwards only allow-listed events, with order events cut to the id, so open storefronts re-render when a dish is edited or sold out. An audit timeline records logins and changes to stock, waste, purchase sheets, dishes, site copy, loyalty and the wheel. server.js, admin/admin.js
Live in production
Babke Kebab & Plates is running in production today. Open it, then tell us what you want built — BreakNRoot engineers systems like this one from first prototype to production.
BNR-CF-01Beef & Buns
A cinematic site for a Sousse smash burger house, built around a scroll-scrubbed burger that assembles layer by layer, with an ordering menu, a WhatsApp order flow and a loyalty programme run from its own API and back office.
Open file
BNR-CF-03Kinben Sushi
A Next.js 16 site for a Sousse sushi bar, built on two scroll-scrubbed 120-frame sequences, a 37-dish menu that orders over WhatsApp, and a QR loyalty passport stamped at the counter through its own Express and MongoDB API.
Open file