Hidang

A restaurant till, from the first tap to the last receipt.

Hidang is a point of sale I designed, built and ran for restaurants in Malaysia: a web till, an Android tablet app, the owner’s dashboard, and the receipts and kitchen dockets that come out of the printers.

It took real orders at a restaurant in Selangor. The demo runs on a made-up one.

HIDANG

Restaurant point of sale

Made for Malaysian restaurants


Receipt#001

Served byOne developer


ItemQty

  • Web till1+ tables, takeaway, split bills
  • Android tablet app1+ Flutter, customer display
  • Owner dashboard1+ live takings, on a phone
  • Kitchen & receipt printing1+ ESC/POS, added rounds, voids
  • Shifts, payouts, refunds1
  • Multi-restaurant platform1+ PostgreSQL row-level security
  • Automated tests1,400+

Grand total1 product

Paid inDjango, Flutter


Terima kasih! Come again.

Seventy seconds of service

A waiter seats table B2 and rings up nasi lemak with a fried egg, satay and two iced teh tarik, then sends them to the kitchen. The cashier takes RM 50; the till rounds to the nearest 5 sen, works out the change and prints the receipt. Then the owner signs in with her PIN and watches the day’s takings.

Try it yourself

The demo is Warung Seri Rasa, a made-up restaurant with six weeks of sales behind it. Anything you ring up shows on the dashboard straight away. It resets every morning.

  1. Open the till

    demo.hidang.world

  2. Connect this browser

    Restaurant serirasa, connect password serirasa-demo. A till in a restaurant does this once.

  3. Tap a name, enter the PIN

    Ravi Kumarwaiter3333
    Mei Ling Tancashier1111
    Hafiz Ismailmanager2580
    Aisyah Rahmanowner1234

Each role sees what it should: a waiter takes orders, a manager reaches reports and the menu, and the owner watches without ringing anything up. Settings that would lock other visitors out, such as the connect password and staff PINs, are switched off in the demo.

What it looks like

The owner's dashboard: today's takings against last week, open bills, latest sales and sales by day
The owner’s dashboard. Every figure is compared with the same moment last week, so a quiet Tuesday afternoon is measured against last Tuesday afternoon, not against a whole day.
The till: a menu with dish photos and a table's ticket
The till, with a table’s ticket. Send to kitchen, print the bill, take payment.
Choosing a spice level and a fried egg for nasi lemak
Options and add-ons. The price moves as they are picked, and the server prices every line.
Taking RM 50 in cash with the change worked out
Cash rounded to 5 sen, split tenders, e-wallets and cards.
The dining room: tables free and seated, with what each owes
The dining room: who is seated, what each table owes, takeaways alongside.

On the owner’s phone

Owners run the restaurant from their pocket, so every screen works at phone size: the day’s numbers, the dining room, the menu and the staff.

The dashboard on a phone The dining room on a phone The menu on a phone

On paper

Receipts and kitchen dockets are written by the server as ESC/POS and sent to the printers by the tablet on the shop’s wifi. The kitchen gets only the new dishes of a second round, marked ADDED, and is told when a dish is voided.

The platform console listing three restaurants with today's orders and takings
One server, many restaurants. Onboarding and support live in a console, and each restaurant’s data is walled off by the database itself.

How it is built

The server owns every number

Prices, tax, service charge, cash rounding and change are worked out on the server and travel as strings, never floats. A till that adds up money on the device is a till a few sen out with nobody able to say why.

Many restaurants, walled off

Every restaurant shares one Django and PostgreSQL deployment. Row-level security in the database keeps their rows apart, and the role the app connects as cannot bypass it.

A tap does not wait

The tablet queues ticket changes and sends them in order with idempotency keys, so a wifi blip during a rush neither loses a dish nor sends it to the kitchen twice.

Two clients, one product

The web till and the Flutter app are kept level by a test that fails the build when one gains a feature the other lacks.

The day ends when the restaurant closes

A sale at half past midnight belongs to the night it was rung up in, not to tomorrow, so order numbers and the day’s takings follow the restaurant’s hours.

Run like production

Docker, nightly encrypted backups with a rehearsed restore, and error alerts to the owner’s phone. Django, PostgreSQL, HTMX and Alpine on the server; Flutter on the tablet.

Have something like this to build?

I take products from the database to the device in someone’s hand, and keep them running afterwards.

Hire me on Upwork