Restaurant management system

Your restaurant, on your own machine.

Point of sale, kitchen display, and back-office management in one application. It runs on hardware you already own, needs no cloud account, and keeps taking orders when the internet goes down.

License: MIT Latest release 175 tests passing Flutter 3.47.5 PocketBase 0.40.1 Status: pre-1.0

The problem with restaurant software

Most of it is rented, and most of it stops working when the internet does. A restaurant that cannot take an order during a five-minute outage has lost money it will never count.

Offline first

The till keeps working

The server runs in the restaurant, not in a data centre. Adding to a bill works with the network unplugged and drains to the server when it comes back. Firing to the kitchen and settling a bill deliberately do not work offline, because a total only the server computes cannot honestly be guessed at on a tablet.

No account

Nothing to sign up for

No licence key, no subscription, no telemetry, no paid tier. One installer gives a restaurant a working system on its own hardware. The data stays where the restaurant can see it.

One binary

Three shells, one download

Not three applications. The signed-in staff member's role decides whether they get the till, the kitchen screen, or the manager shell. One codebase, one thing to explain.

What it does

Everything a small restaurant needs to run a service, and nothing that gets in the way of one.

Point of sale

Till

Floor plan with live bill totals per table. Modifiers, kitchen notes, and quantities. Send to kitchen in one action. Partial payments that accumulate until a bill covers itself, cash with tendered and change, discounts by percentage or amount, each with a reason and each written to the audit log.

Voids are recorded rather than silently deleted.

Kitchen display

Pass

Tickets appear the moment the till fires them, sized to read from across a kitchen. Tapping an item walks it queued, cooking, ready. Timers count from when the ticket was fired and the card ages against a ten-minute target.

A ticket's border and timer carry how long it has waited; its dots and chips carry what state each item is in. Because ageing never touches the status colours, a late ticket full of cooking items still reads correctly at a glance.

Back office

Manager

Menu with categories, photographs, tags, preparation times, modifier groups, and a sold-out toggle. Tables grouped into zones. Staff accounts with five roles, each described in plain language rather than by permission flags.

A manager can reset a forgotten PIN without anyone opening the admin dashboard.

Reporting

Takings

Sales broken down by item, by who served it, and by hour, with CSV export for the bookkeeper. Shifts with an opening float, a counted close, and the variance called out.

Takings are counted by when a bill closed, not when it was opened. A table seated before a shift began and settled during it belongs to that shift.

Table-side ordering

Guest ordering

A guest scans the QR code on their table and orders from their own phone. It is a web page, not an application to install, and it runs on the same server and port, so nothing is exposed to the internet.

Guests reach exactly three public routes; every collection stays staff-only. No price is ever taken from the request.

Hardware

Printing

Network thermal printers over TCP 9100 using ESC/POS, which is what virtually every restaurant printer already speaks. No driver to install: a printer is an address and a paper width.

Thermal printers speak code pages, not Unicode, so any non-ASCII currency symbol falls back to its three-letter code. Every printable byte the builder emits is plain ASCII, and a test holds it to that.

Four rules the code is built to keep

These are not style preferences. Each is enforced in code and covered by a test, because breaking one silently is how a restaurant loses money.

Rule Why it exists Proved by
Money is only ever computed on the server A point-of-sale system must never let a client decide what a bill costs. A client that PATCHes a forged total has it overwritten. smoke, "Client cannot forge a total"
Menu names and prices are snapshotted onto order lines Editing tomorrow's menu must never rewrite yesterday's bill. smoke, line totals against snapshot values
Takings are counted by when a bill closed A table seated before a shift began and settled during it is that shift's takings. Keying on creation credits the money to the wrong session and leaves the drawer looking short. payments, settlement and shift figures
Ageing and status use separate colour channels Merging them makes a late ticket full of cooking items unreadable: the two meanings fight each other. Visual; documented in the developer guide

How it fits together

One server, one binary. PocketBase contains the database, authentication, realtime subscriptions, file storage, and an admin interface. There is no cloud service and no account.

  +-----------------------------------------------------------------------+
  |                            RESTAURANT LAN                             |
  |                                                                       |
  |   +-----------------+                    +------------------------+   |
  |   |  Flutter app    |                    |  Guest phone           |   |
  |   |                 |                    |                        |   |
  |   |  POS shell      |                    |  QR code -> web page   |   |
  |   |  KDS shell      |                    |  3 public routes only  |   |
  |   |  Manager shell  |                    |  no price from request |   |
  |   +--------+--------+                    +-----------+------------+   |
  |            |                                         |                |
  |            |  HTTP (LAN only)                        |                |
  |            +-----------------+   +-------------------+                |
  |                              |   |                                    |
  |                              v   v                                    |
  |            +---------------------------------------------+            |
  |            |  PocketBase (single binary, on-site)        |            |
  |            |                                             |            |
  |            |  +----------------+  +-------------------+  |            |
  |            |  |  Migrations    |  |  Hooks            |  |            |
  |            |  |  the schema,   |  |  order numbering  |  |            |
  |            |  |  version       |  |  ALL MONEY MATH   |  |            |
  |            |  |  controlled    |  |  role guards      |  |            |
  |            |  +----------------+  |  audit log        |  |            |
  |            |                      +-------------------+  |            |
  |            |  +----------------+  +-------------------+  |            |
  |            |  |  SQLite        |  |  Realtime subs    |  |            |
  |            |  +----------------+  +-------------------+  |            |
  |            +---------------------------------------------+            |
  |                                                                       |
  |   +-----------------+                                                 |
  |   | Thermal printer |<---- ESC/POS over TCP 9100 -------------------+|
  |   +-----------------+                                                 |
  +-----------------------------------------------------------------------+

Full structure, data model, and where future work attaches: architecture.

What happens when the network drops

  Network up          Network down                Network restored
  ----------          ------------                ----------------
  write sent   --->   write queued to disk   ---> queue drains,
  to server           (addLine only)              oldest first,
                                                  stops at the first
                                                  failure so ordering
                                                  survives

Opening a bill and settling one deliberately do not work offline. Opening a bill needs a number the server assigns, and settling one needs a total only the server computes. Settling against a made-up number is how a restaurant loses money.

Running it

Two terminals. PocketBase downloads itself on first run; there is no database to install and no account to create.

# Terminal 1 — the server
./server/scripts/dev.sh

# Terminal 2 — the application
cd app && flutter run -d windows

The first run fetches the pinned PocketBase into server/bin/ and applies the schema migrations. The admin interface is then at http://127.0.0.1:8090/_/.

Building for Windows

installer/windows/build_windows.sh

Developer Mode must be enabled once, as an administrator. Flutter needs symlinks for native plugins, and its own failure message does not name the prerequisite. Run start ms-settings:developers. The build script checks for this before doing anything and explains the fix.

Running the tests

# Everything, with per-agent isolation
.harness/scripts/test.sh --agent local --all

# One backend suite
.harness/scripts/test.sh --agent local --suite smoke

# Dart tests only
.harness/scripts/test.sh --agent local --app

Roadmap

Mise-Kal is pre-1.0 and moving. The current release is infrastructure and correctness rather than features, because stabilising the existing system and making it testable comes before building on top of it.

Phase Focus Status
1Stabilise the implementation, tests, and installerIn progress
2Indonesian localizationIn progress
3Payment and QRIS integration layerPlanned
4WhatsApp and business notificationsPlanned
5Inventory and stock controlPlanned
6Multi-branch supportPlanned
7Owner dashboardPlanned
8Backup and sync architecturePlanned
9Analytics and AI-assisted business insightsPlanned
10Production hardeningPlanned

Built on Mise

Mise-Kal is a derivative of Mise by K M Shahriar Hossain, which established the security posture and design decisions this project inherits, in particular the rule that money is only ever computed server-side.

The MIT license is retained unchanged and the upstream copyright notice is preserved in LICENSE.