Point of sale, kitchen display and back office for restaurants with one or many branches: tables, orders, payments, recipes and stock, purchasing, loyalty, delivery orders and tax documents.
Spring Boot 4 · Java 17+ · Microsoft SQL Server
User Guide · Version 1.0.0
Restaurant POS Starter is a complete web application. Every device only needs a browser: a tablet or touch PC at the counter, a tablet in the hands of a waiter, a screen in the kitchen, a small screen facing the guest.
| Part | Who uses it | What it does |
|---|---|---|
| POS | Cashiers, waiters, managers | Floor plan, dine-in / take-away / delivery / drive-thru bills, options and notes, courses, split and merge, all payment types, receipts, shift and cash drawer. |
| Kitchen display | Kitchen and bar | Tickets per station with timers, Start / Bump, recall, sold-out items. |
| Customer display | Guests | The bill as it is built, the total and a payment QR code. |
| Back office | Managers, store, purchasing, accounting | Dashboard, menu and recipes, stock at FIFO cost, purchasing, members and promotions, delivery platforms, reports, tax documents, journal export, users and audit log. |
One installation serves any number of branches. Each branch has its own tax rate, service charge, prices, floor plan, terminals, stock and document numbers.
Open database/01-create-database.sql, change the password in it, and run it as a SQL Server administrator
(SQL Server Management Studio, Azure Data Studio or sqlcmd):
sqlcmd -S localhost\SQLEXPRESS -E -i database\01-create-database.sql
It creates the database RestaurantPosDB with a UTF-8 collation and a login restaurant_pos.
The application creates all tables itself on the first start (Flyway migrations).
SQLEXPRESS) the
SQL Server Browser service must run, or use a fixed port in the URL.Set the connection and start the application (Windows example; on Linux or macOS use export and ./mvnw):
set DB_URL=jdbc:sqlserver://localhost;instanceName=SQLEXPRESS;databaseName=RestaurantPosDB;encrypt=true;trustServerCertificate=true set DB_USERNAME=restaurant_pos set DB_PASSWORD=the-password-you-chose mvnw.cmd spring-boot:run
Or build once and run the jar: mvnw.cmd package then java -jar target\restaurant-pos-starter-1.0.0.jar.
Open http://localhost:8080. On an empty database the demo data is created (about 20 seconds):
two branches, a menu with recipes, stock, staff, members and two weeks of sales.
All settings are environment variables; env.example lists every one of them.
Back-office password for every demo account: Demo@2026. Staff who work on terminals also have a PIN.
| User | Name | Role | PIN | Branches |
|---|---|---|---|---|
| admin | Alex Admin | System admin | 9024 | all |
| avery.collins | Avery Collins | Branch manager | 2580 | Riverside, Old Town |
| jordan.lee | Jordan Lee | Cashier | 1470 | Riverside |
| sam.rivera | Sam Rivera | Waiter | 3690 | Riverside |
| riley.chen | Riley Chen | Waiter | 4826 | Riverside |
| morgan.patel | Morgan Patel | Kitchen | 5173 | Riverside, Old Town |
| drew.santos | Drew Santos | Cashier | 6284 | Old Town |
| casey.brooks | Casey Brooks | Store keeper | - | Riverside, Old Town |
| quinn.hayes | Quinn Hayes | Purchaser | - | Riverside, Old Town |
| taylor.kim | Taylor Kim | Accountant | - | all (read) |
| jamie.ford | Jamie Ford | Executive | - | all (read) |
| robin.vale | Robin Vale | Auditor | - | all (read) |
Two demo branches show both tax styles: Riverside adds 7% tax and a 10% service charge on dine-in; Old Town has prices that include tax and rounds cash to 0.05.
SEED_DEMO_DATA=false) on a new, empty database
and set ADMIN_INITIAL_PASSWORD. See chapter 24.For security, staff sign in with a PIN only on devices that a manager has registered. A registered browser keeps a signed device cookie; another browser cannot use the PIN screen.

The POS locks itself after 60 seconds without use (Settings). Press Lock to hand the device to a colleague; open bills stay as they are.
Payments are always booked into the shift of the terminal. The first cashier of the day opens the shift with the opening float (the change in the drawer). The Shift tab shows the payments taken, cash drops, cash in and the cash that should be in the drawer. Waiters can take orders without a shift; only taking payment needs one.


Tap an item to add it. Items with options (size, doneness, extras) open a choice dialog; required choices must be made. Add a note for the kitchen ("no peanuts"). Tap a line on the bill to change the quantity, add a note, give an item discount or void it.
The More menu of a bill: guests & name, move to another table, merge bills, split by items, send a held course, reopen a bill to add more, delivery status and void the whole bill. Add a member with their phone number or member number to earn and use points.
Send prints a kitchen ticket per station (hot kitchen, cold, bar, pastry) and shows it on the kitchen display. Items can be held for a later course and sent with Send a held course. Unsent items are sent automatically when the bill is paid.

| Method | Notes |
|---|---|
| Cash | Quick buttons, change is calculated. Only cash gives change. Cash rounding follows the branch. |
| Credit / debit card | Card type, the last 4 digits and the approval code from the card terminal. Full card numbers are refused everywhere. |
| QR pay | Shows a dynamic QR code (also on the customer display); the bill closes when the payment notice arrives. The included gateway is a test simulator. |
| E-wallet, voucher | With a reference. |
| Points | Member points at the value set in Settings. |
| Credit sale | Pay later (house account); needs a manager approval. |
Mix methods freely ("$20 cash, the rest by card"). Split equally shows each guest's share; Split by items (in More) moves items to a new bill. After payment the receipt prints and, if set, a QR code on it opens the e-receipt. A full tax invoice with the buyer's name, address and tax ID can be issued from a paid bill.

Some actions need a manager: voiding an item already sent to the kitchen, a discount above the cashier's limit, a credit sale, opening the drawer without a sale, a refund, and closing a shift with a large cash difference. The POS asks for the manager to tap their name and type their PIN on the same screen; the manager is recorded in the audit log.

Register a kitchen screen as a KDS terminal and sign in with a kitchen PIN. Filter by station, press Start when cooking begins and Bump when the food is ready (the waiter sees "ready" on the floor plan). Recall brings back a ticket bumped by mistake. The kitchen can mark items sold out; every POS greys them out immediately.
Each POS has a customer display link (System > Terminals > Customer display). Open it on a second screen facing the guest: it shows the items as they are added, the total and the payment QR code.
In the Shift tab, count the cash by notes and coins. The system compares it with the expected cash and shows the difference. A difference above the limit needs a manager. Closing prints the Z report (sales by method, refunds, discounts, voids, cash movements), which is final and numbered. An X report can be printed at any time without closing. When all shifts of a branch are closed, a manager closes the business day (Back office > Shifts & end of day).


The branch selector at the top switches between branches (for users allowed in several). The search box finds a bill by receipt or bill number. The theme button switches between light and dark.



Every paid bill takes its ingredients from stock automatically (recipe × quantity, plus options). Cost is calculated first in, first out: the oldest received goods are used first, so food cost is exact even when prices change.



Orders from delivery platforms arrive by webhook (see docs/API.md). Each platform has its own signing
secret, commission rate and menu map (their item codes to your items). An order with unknown items goes to the
exceptions list instead of being lost. The demo has two fictional platforms; Simulate sends a test order.



Also: food cost, voids & discounts by staff (the control report) and delivery by platform. Reports can show one branch or all.
ETaxProvider with your provider).| Role | May do |
|---|---|
| Cashier | Orders, payments, own shift |
| Waiter | Orders |
| Kitchen | Kitchen display, sold-out items |
| Branch manager | Everything in the branches given: POS approvals, stock, purchasing, members, reports, end of day, finance |
| Store keeper | Stock |
| Purchaser | Purchasing and stock |
| Accountant | Reports and finance, all branches (read) |
| Executive | Reports, all branches (read) |
| Auditor | Audit log and reports, all branches (read) |
| System admin | Everything, including users, branches and settings |
Each user can be limited to some branches and given their own discount limit. Back-office users can switch on two-step sign-in with an authenticator app (Profile). Passwords need at least 8 characters with upper and lower case, a digit and a symbol; PINs cannot be simple runs like 1234 or 1111.

System > Settings (system admin):
| Setting | Default |
|---|---|
| POS idle lock (seconds) | 60 |
| Wrong PINs before lock / minutes locked | 5 / 15 |
| Cashier discount without approval | 5% |
| Void after sending needs approval; no sale needs approval | yes / yes |
| Quick cash buttons | 5, 10, 20, 50, 100 |
| Kitchen ticket yellow / red / recall (minutes) | 8 / 12 / 30 |
| Cash over/short needing approval | 5.00 |
| Receiving price variance needing approval | 5% |
| Point value; birthday multiplier; points expiry (months) | 0.01; 2; 12 |
| QR on receipts; send tax invoices to e-invoice service | yes; yes |
| Audit log retention (years) | 5 |
| Offline receipt number block size | 500 |
Per branch (System > Branches): legal name, tax ID, address, tax rate, prices with or without tax, service charge, cash rounding, the time a business day starts and the receipt header and footer.
These rules are enforced by the database itself, so not even a bug or a direct SQL change can break them:
The test suite checks these on a real SQL Server, including 2,000 receipt numbers taken in parallel with failed sales in between (no gaps, no duplicates).
SEED_DEMO_DATA=false and ADMIN_INITIAL_PASSWORD.APP_DATA_KEY (openssl rand -base64 32), APP_DEVICE_SECRET,
PAYMENT_WEBHOOK_SECRET. Keep APP_DATA_KEY safe: without it encrypted member data cannot be read.SESSION_COOKIE_SECURE=true and APP_BASE_URL.CURRENCY_SYMBOL, CURRENCY_CODE and APP_TIME_ZONE; enter your branches, tax rates and menu.QrPaymentGateway / ETaxProvider) and a mail server for e-receipts.Step-by-step server notes are in docs/DEPLOY.md.
| Problem | Fix |
|---|---|
| "This browser is not registered as a POS terminal" | Register it (chapter 4). Clearing browser cookies removes the registration. |
| A user is locked on the PIN screen | Wait 15 minutes, or a manager unlocks them in Users. |
| "Take payments on a POS terminal" | Payments are taken on registered POS terminals with an open shift, not in the back office. |
| The application does not start: "The database collation is ..." | Create the database with database/01-create-database.sql (UTF-8 collation). |
| Cannot connect to SQL Server | Enable TCP/IP in SQL Server Configuration Manager, start SQL Server Browser for a named instance, check the firewall. |
| Something went wrong | Every error page and log line has a request id; search the log for it. |