1 TL;DR
One API serves every restaurant from one deployment. Orders reach the kitchen live, the bill matches what was served, and each staff role sees only what its station needs.
2 Context The problem
A restaurant floor needs one system for the counter, the tables and the kitchen. Orders have to reach the kitchen as they are placed, the bill has to match what was served, and each staff role needs access that fits its station. DineFlow serves more than one restaurant from the same API, so every request has to stay inside its own restaurant's data.
3 What I built
- Designed the data model: restaurants, staff, tables, menu, orders with kitchen batches, inventory with a stock ledger, attendance, customers and an audit log.
- Built the Express API, with JWT sessions for owners and staff and a permission check on every domain route.
- Built the React interface, packaged with Electron for the counter, and shipped the same build as the browser demo.
- Wrote API test suites that run the full order flow, from opening a check to payment, against the live server.
- Deployed the API and web build with Docker behind Caddy, redeployed on every push to main.
4 How a request moves
- Open a checkOpening the check creates the order and marks the table occupied, so two people cannot seat the same table.
- Send to the kitchenEach send creates a kitchen ticket for the items not yet sent. A second round goes out as its own ticket.
- Cook and serveThe kitchen screen receives tickets live over Socket.io; the floor sees served items without a refresh.
- Bill and closePayment closes the order and frees the table. A second payment on a paid order is rejected.
5 Hard problems And how they were solved
Two writes to one order
Sending a ticket and the register's autosave could write the same order at once, and MongoDB rejected the second write as a version conflict. The fix reloads and retries the save, never lets the sent-to-kitchen count go backwards, and pauses autosave while a ticket is in flight.
Permissions on the server, not only the menu
A test showed a cashier's token could still read the staff, inventory and reports APIs. Every domain route now checks the role's permissions on the server and returns 403.
The restaurant comes from the token
An early build trusted a restaurant ID sent in a header. Protected routes now read the restaurant from the signed session only, so a changed header cannot reach another restaurant's records.
6 Results Real outcomes only
- A 117-check API audit run against the production server, passing in full in August 2026.
- Server-side permission checks on every domain route, covered by the test suites.
- A public demo with owner and staff logins, and a step-by-step demo guide.
7 Next revision
Moving the API to FastAPI and the data from MongoDB to PostgreSQL with row-level security per restaurant.
JSON for this page: curl rajshubham.com/api/v1/projects/dineflow-pos