DineLedger: floor, kitchen and counter for Al Ajmaan
Restaurant & Hospitality
- Client
- Al Ajmaan
- Year
- 2026
The intro and the screens
A 24-second intro and 5 screens — scroll sideways





Every screen shown is the real application, rendered from the real frontend. The menu, the staff names and all figures are demonstration data chosen to look like a normal evening's service — they are not Al Ajmaan's trading numbers, and no customer data appears anywhere.
The Challenge
Al Ajmaan seats guests across two rooms and twenty-six tables, cooks out of six separate kitchen sections, and takes takeaway from the counter, the phone, its own website, Swiggy and Zomato — every evening until two in the morning. The order had to be walked to the pass by a person, one ticket listing a whole table was the wrong piece of paper for all six sections, nobody could see the floor, and a party across three tables had to be re-added by hand at the end.
The Goal
Get the order from the table to the right section of the kitchen without anyone carrying it, and give the floor, the counter and the owner the same picture of service as it happens.
Our Strategy
We drew the floor plan from the owner's own sketch rather than asking the restaurant to describe itself in rows and columns, and designed the printing around the assumption that the line will drop — tickets are queued on the server and collected by the PC, never sent to a printer and hoped for.
The Solution
LeafOne built DineLedger: four separately installable apps over one database — waiter, kitchen, counter and admin — plus a small Windows tray program that does nothing but print. The waiter orders at the table seat by seat on a live plan of the real rooms; each kitchen section is sent only its own dishes, printed on its own printer; the counter settles the bill and records the payment.
Key Features
Decisions worth talking about
Joined tables are still separate tables.
When a large party takes tables 22, 23 and 24, the easy thing is to merge them into one big table. DineLedger refuses to. Each stays its own table with its own seats, and one of them carries a pointer that says bill all of us together. That is more work to build, and it is the only version that matches the restaurant: the kitchen still gets one ticket per table because the food still goes to three physical places, and the seats still number from one at each table because that is what the waiter says out loud. Only the bill is joined, and only because the customer asked for one.
The print queue lives on the server, and the screens admit when it is down.
Tickets are not sent to a printer. They are written to a queue on the server, and the Windows agent collects them — so if the restaurant's PC is off, asleep, on battery or offline, nothing is lost. The two details we would defend hardest are the ones that say no. A ticket older than the waiting time the admin has set is not printed at all; it is marked not printed and can be reprinted deliberately, because a shawarma ticket that surfaces forty minutes late is worse than no ticket. And the kitchen and counter screens show a banner when the agent is offline, instead of quietly looking normal while nothing prints.
The kitchen counts stock blind.
The kitchen opens a session with a count, adds stock during service, and closes with a count. What it never sees is the figure the system expects. Showing the expected number would make the count faster and worthless — people confirm the number in front of them. The live figures and the variance live in the admin's stock report instead. It is a slower process that produces a number the owner can act on.
The business day ends at 2 AM, because that is when the shop closes.
Al Ajmaan serves from noon until two in the morning. A calendar day would split every night's trade across two dates, so the day's closing report, paid today, parcels today and every date-range report would all disagree with what the staff actually worked. The admin sets the hour the business day ends, anywhere from midnight to 6 AM, and the whole system follows it. It is a small setting that stops every number in the product from being subtly wrong at 1 AM.
Technology Stack
Design & Infrastructure
Each app is shaped around who is holding the device: the waiter's is one-handed and thumb-reachable at a table, the kitchen's is a wall screen readable across a hot room at a glance, and the counter and admin are dense and keyboard-friendly. Colour carries state everywhere — available, occupied, food ready — so the floor can be read without stopping to interpret it.
A Node.js service against MySQL with Socket.IO for the live floor and kitchen, the four apps installable from the browser, and the Printer Hub holding the connection from the restaurant's own PC. DineLedger is not billing software: it issues a bill number that matches the numbering of the billing software the restaurant already uses, and the counter records the payment against it.
Engineering notes
- Node.js 20, Express 5, MySQL/MariaDB and Socket.IO, with nine production dependencies in total.
- 26 tables, all InnoDB with foreign keys throughout, defined in one readable schema.sql — no ORM and no migration framework between the schema and the person reading it.
- Zero frontend dependencies: 5,834 lines of JavaScript across 23 files with no framework, no bundler and no build step. The only external link in any screen is the credit back to leafone.in.
- One open session per table is enforced by the database, not by application code: a generated column is 1 while the session is open and NULL when closed, under a unique key. Two waiters tapping the same table at the same moment cannot produce two sessions.
- Every order and parcel carries a client-generated UUID under a unique index, so a double-tapped send on a slow connection cannot create two orders.
- Item names and prices are copied onto the order at the moment it is taken. Changing a price tonight never rewrites what was billed last week.
- One continuous bill number across dine-in and takeaway, allocated inside the bill's own transaction so a failed bill returns its number — no gaps and no repeats.
- All timestamps are stored in India time and set on every database connection, so a phone with the wrong timezone still shows the right service timer.
- Nothing is hard-deleted. Staff, dishes and categories that have been used are hidden and kept, because old orders and reports name them.
- JWT auth with bcrypt-hashed passwords, helmet, rate limiting per username, and a token version that signs a user out of every device when their password, role or status changes.
- The Windows Printer Hub is a single C# file built to a standalone 94 KB executable: a tray app that starts with Windows, maps departments to USB, LAN or port-9100 thermal printers at 80 mm or 58 mm, and remembers which tickets it has printed so nothing prints twice.
- Tests cover the two places where a silent bug would be expensive — the business-day boundary and the tax calculation — and run with node --test, no database required.
Results
DineLedger runs the floor, the kitchen and the counter on one database. The order reaches the right section of the kitchen without anyone carrying it, every order is timed against a service target with the delays recorded per waiter, and a party spread across three tables still leaves with one bill.