PaynEat POSInstall guide

Four ways to run your restaurant on PaynEat POS

Pick the one that fits and follow it step by step. No sign-up, no fees, and your restaurant’s data stays on your own machine.

  • Free · Apache 2.0
  • No sign-up
  • Runs on the devices you already have
First

What do you want to do?

Not sure yet? Start with the first one — tap around until you’re happy, then install it for real.

  • Try it in the browser

    Time
    Right now
    You need
    Any browser
    Best for
    Seeing it and tapping around before you decide
    Open the demo
  • Recommended

    Windows, one line

    Time
    3–5 minutes
    You need
    Windows + Docker Desktop
    Best for
    Owners who want the real system on their own PC
    How to install
  • Docker for every device

    Time
    10–15 minutes the first time
    You need
    Docker Desktop (Windows / Mac / Linux)
    Best for
    Restaurants where phones, tablets and the kitchen screen share one server
    How to install
  • Run from source

    Time
    About 5 minutes
    You need
    Node.js 22 + Flutter 3.35
    Best for
    Developers who want to change or extend it
    How to run
Way 2 · Recommended for owners

Install on Windows with one line

The real system — server, live updates across windows, a simulated scale and PDF receipts — without downloading code or building anything: the installer fetches ready-built images.

Time
3–5 minutes (about 200 MB the first time)
You need
64-bit Windows + Docker Desktop
You get
PaynEat at http://localhost:8080 on this PC
  1. Install and open Docker Desktop

    Don’t have it? Download it from docker.com, install it and open it. Wait until the bottom-left corner says Engine running.

  2. Open PowerShell

    Press the Windows key, type PowerShell and press Enter.

  3. Paste this line and press Enter

    Press Copy in the corner of the box, then right-click inside PowerShell to paste.

    PowerShell
    [Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object Net.WebClient).DownloadString('https://github.com/SuruchBoss/PaynEat/releases/download/demo/install-demo.ps1'))
  4. Wait, then sign in

    Your browser opens http://localhost:8080 by itself. Sign in with admin / admin123, or tap a demo account button on the sign-in screen.

PowerShell prints PaynEat is ready: http://localhost:8080 in green and the browser shows the sign-in screen.

Day to day

Start / stop / reset
The PaynEat-Demo folder in your user folder has double-click files: Start, Stop and Reset PaynEat data (Reset erases every bill you tried and restores the sample data).
After a restart
Open Docker Desktop and PaynEat comes back by itself.
Update to the latest version
Paste the same line again. Your data stays.

⚠️ Set up for trying it out only (demo accounts, simulated scale, emails never really sent), and it opens on this PC only — to let the restaurant’s phones and tablets connect, use way 3. Want to read what the script does first? install-demo.ps1

Way 3 · Every device in the restaurant

Run it with Docker so every device connects

The server lives on one computer in the restaurant; staff phones, the cashier’s tablet and the kitchen screen open it in a browser. An order placed on one device shows up on the kitchen screen at once.

Time
10–15 minutes the first time (under a minute after that)
You need
Docker Desktop on Windows, Mac or Linux
You get
PaynEat at http://<this computer’s IP>:8080 from every device on the same Wi-Fi
  1. Download the code

    Easiest: download the ZIP and extract it — you get a folder called PaynEat-main. If you have git, this works too:

    Terminal
    git clone https://github.com/SuruchBoss/PaynEat.git
  2. Find this computer’s IP address

    Windows: open PowerShell, type ipconfig and look for IPv4 Address. Mac/Linux: ifconfig | grep inet. It looks like 192.168.1.15.

  3. Set the server secret

    Create a file named .env in the code folder (next to docker-compose.yml) containing a JWT_SECRET= line with your own random value. Without it the system does not start and explains how to set it. On Mac/Linux use the command below; in Windows PowerShell use ("JWT_SECRET=" + [guid]::NewGuid().ToString("N") + [guid]::NewGuid().ToString("N")) | Out-File -Encoding ascii .env.

    Terminal (Mac/Linux)
    echo "JWT_SECRET=$(openssl rand -hex 32)" > .env
  4. Tell the app where the server is

    Add this line to the same .env file, using your own IP. Skip this step if only this computer will use it.

    .env
    API_BASE_URL=http://192.168.1.15:3000
  5. Start it

    Open a terminal (Windows: PowerShell) in the code folder and run this. The first time takes 5–10 minutes while the app is built.

    Terminal
    docker compose up --build
  6. Open it on every device

    On the same Wi-Fi, open http://192.168.1.15:8080 (your IP) on phones, tablets or the kitchen screen. On the server itself, http://localhost:8080 works.

The terminal shows payneat-api and payneat-web, and http://localhost:3000/health answers.

Day to day

Stop it
Press Ctrl+C in the terminal, then run docker compose down.
Start over with fresh data
docker compose down -v (erases every bill and all data).
Turn on the simulated scale and test emails
Add SCALE_DRIVER=simulator and MAIL_TRANSPORT=json to the same .env file, then run docker compose up --build again. Never use the simulator in a real shop.

💡 Another device can’t open it? Check it’s on the same Wi-Fi and that the server’s firewall allows ports 8080 and 3000. Before staff use it for real, go through the go-live checklist.

Way 4 · For developers

Run it from source

For changing the code, reading the log request by request, or running on a real phone through Flutter.

Time
About 5 minutes
You need
Node.js 20 or later (22 recommended) + Flutter 3.35 or later
You get
The API at http://localhost:3000 and the app in Chrome
  1. Get the code

    Terminal
    git clone https://github.com/SuruchBoss/PaynEat.git
    cd PaynEat
  2. Window 1 — the server

    .env holds a JWT_SECRET for local use; without it the server refuses to start (on Windows use copy instead of cp). The database and sample data are created for you.

    Terminal 1
    cd backend
    npm install
    cp .env.example .env
    npm run dev
  3. Window 2 — the app

    Open a new window and keep the first one running.

    Terminal 2
    cd app
    flutter pub get
    flutter run -d chrome

Window 1 prints a line with PaynEat POS API listening on http://localhost:3000 and Chrome opens the sign-in screen.

Handy shortcuts

Just the app, no server
flutter run -d chrome --dart-define=DEMO_MODE=true (sample data in the browser, reset on refresh)
A real phone on the same Wi-Fi
flutter run --dart-define=API_BASE_URL=http://<your computer’s IP>:3000
Android emulator
Points at 10.0.2.2:3000 by itself, nothing to set.
Run the tests
cd backend && npm test · cd app && flutter test

Architecture, the API and every test are described in the README.

After installing · every way

Back up and restore

All of the shop's data is in one file on the server. PaynEat backs it up by itself after each shift close, every 6 hours when data changed, and before an update. The status is in Settings for the admin; if no backup has succeeded for more than 26 hours, the owner and managers see a warning on the home screen.

Where
data/backups next to the database, plus a second location you set
How long
Every file for 48 hours, then one a day for 30 days
Restoring
A command on the server; the app has no restore button
The Backups section in Settings: last backup time, both locations and the Back up now button
Admin → Settings → Backups
  1. Set a second location on another disk

    The first copy is on the same disk as the database, so a failed disk loses both. Plug in a USB drive or use a folder on a NAS in the shop, add this line to backend/.env (with your folder) and restart the server

    backend/.env (running from code)
    BACKUP_COPY_DIR=E:\PaynEat-backup
  2. Docker: keep the second copy outside the container

    Uncomment - /mnt/usb-backup/payneat:/backup-copy under volumes: of api in docker-compose.yml (change the part before : to your folder; on Linux let uid 1000 write to it: sudo chown 1000:1000 /mnt/usb-backup/payneat), add this line to .env, then run docker compose up -d

    .env (Docker)
    BACKUP_COPY_DIR=/backup-copy
  3. Make one backup to check

    Sign in as the admin, open Settings → Backups and press Back up now. Both locations should show a green tick

  4. Restoring: stop the server first

    The restore command refuses to run while the server is up · From code: press Ctrl+C in the server window · Docker: run this in the code folder

    Terminal (Docker)
    docker compose stop api
  5. Pick the file to restore

    The name says when and why, e.g. payneat-2026-09-29T221530+0700-shift-close.sqlite is the one after the 22:15 shift close on the 29th · From code: look in backend/data/backups · Docker: list them with this command

    Terminal (Docker)
    docker compose run --rm api ls data/backups
  6. Restore it

    From code: cd backend, then npm run db:restore -- data/backups/<file name> · Docker: the command below · PaynEat checks the file first and always keeps the current data as a pre-restore file, so a wrong pick can be undone

    Terminal (Docker)
    docker compose run --rm api npm run db:restore -- data/backups/payneat-2026-09-29T221530+0700-shift-close.sqlite
  7. Start the server again

    From code: npm start (or npm run dev) · Docker: the command below

    Terminal (Docker)
    docker compose start api

The restore command prints Restored … from … with the name of the pre-restore file, and the Audit Log shows Restore from a backup

If the command refuses

The PaynEat server is still running
Stop the server first. If the machine just went down by itself (a power cut), wait 30 seconds and try again
The backup file is damaged
Pick an earlier file, or the file of the same name from the second location
made by a newer PaynEat
The file comes from a newer PaynEat. Update PaynEat first, then restore again

🔒 A backup holds customer phone numbers and staff password hashes. Keep the USB drive somewhere locked and never share or upload it to a cloud · One-line Windows installer (demo): use the same Docker commands in PowerShell, adding -f "$env:USERPROFILE\PaynEat-Demo\docker-compose.yml" after docker compose

Demo accounts

Sign in as any role

The sign-in screen has a button for every demo account — one tap and you’re in, nothing to type.

RoleUsernamePasswordWhat it sees
Administratoradminadmin123Everything — dashboard, menu, staff, reports, settings
Managermanagermanager123Same as the administrator, but can’t delete user accounts
Waiterwaiter1waiter123Floor plan, orders, kitchen screen
Kitchenkitchenkitchen123The kitchen screen only
Cashiercashiercashier123Floor plan, orders, reports
Waiter, two brancheswaiter2waiter123Like waiter1 but can pick a branch — typed by hand, and only with a real server (ways 2–4)
Trying several devices at once

The browser demo keeps its data on each device separately — an order from a phone won’t reach a kitchen screen on another tablet. To watch orders move between devices, use way 3, or open several windows on the one PC of way 2. The globe button top right switches ไทย / English / 한국어 even before you sign in.

Before going live

Checklist before staff use it for real

The demo accounts and passwords above are published on the internet, so the system guards against them: in production mode it refuses to start while they’re still in place.

Every item in detail, and how to report a vulnerability: SECURITY.md

  • Set JWT_SECRET to your own random value, for example from openssl rand -hex 32. With NODE_ENV=production, the server refuses to start with a sample value or one shorter than 32 characters.
  • Set your own passwords for all six starting accounts (SEED_ADMIN_PASSWORD … SEED_CASHIER_PASSWORD), or turn off AUTO_SEED and create real staff accounts yourself.
  • Set CORS_ORIGIN to the restaurant’s real address instead of *.
  • Keep the database file and .env on the restaurant’s machine — never upload or share them. Set BACKUP_COPY_DIR to another disk and try one restore before opening, as in Back up and restore.
  • Don’t use the one-line Windows installer for a real shop: it is set up for trying things out.
  • If you connect PaynEat ERP, use its https:// address. The POS never sends its credential over http:// except to the same machine, and ERP_ALLOW_INSECURE_HTTP is only for a closed network. If the ERP’s certificate comes from the chain’s own CA, see “PaynEat ERP’s HTTPS certificate isn’t trusted” under troubleshooting.
Troubleshooting

Stuck? Tap the problem

It says "port is already allocated"

Something else is using port 3000 or 8080. Close it (or a PaynEat you left running) and try again.

It says "Docker Desktop is not running" or "is not installed"

Install Docker Desktop from docker.com if needed, open it, wait for Engine running in the bottom-left corner, then paste the line again.

It says "PaynEat started but is not answering yet"

It is up but slow to answer. Wait a moment and open http://localhost:8080; if it still doesn’t open, check Docker Desktop → Containers → payneat.

Docker sits on the Flutter step for ages

The first time downloads the Flutter SDK, about 2 GB. Let it finish (5–10 minutes); next time it’s cached.

The page opens but sign-in fails

Open http://localhost:3000/health; if nothing answers, the server isn’t running. If you set API_BASE_URL, check the IP and run docker compose up --build again after changing it.

A phone or tablet can’t connect

It has to be on the server’s Wi-Fi, use the IP rather than localhost, and the firewall must allow ports 8080 and 3000.

Docker says "required variable JWT_SECRET is missing a value"

The server secret is not set yet. Create the .env file next to docker-compose.yml as in the "Set the server secret" step of way 3, then run it again.

It says JWT_SECRET must be set

There is no .env yet: run cp .env.example .env in backend (Windows: copy), then npm run dev again.

Settings say “PaynEat ERP’s address must start with https://”

The POS sends its credential only over https://. Ask the ERP administrator for the ERP’s https:// address. A http:// address works only for an ERP on the same machine (localhost). If you connected over http:// before this update, the POS has stopped sending the credential: save the https:// address with the credential in Settings.

Settings say “PaynEat ERP’s HTTPS certificate isn’t trusted”

The POS server doesn’t trust the certificate authority that issued the chain’s ERP certificate. Ask the ERP administrator for the CA file (PEM), and check it first: curl --cacert chain-ca.pem https://your-erp-address/health must answer "status":"ok". Then restart the POS server with NODE_EXTRA_CA_CERTS=/path/to/chain-ca.pem in its environment (putting it in backend/.env has no effect: Node reads it at startup, before that file). Docker: mount the CA file into the api container and set it in docker-compose.override.yml. Never turn certificate checks off.

npm install fails on better-sqlite3

Build tools are missing. macOS: xcode-select --install · Linux: sudo apt install build-essential python3 · Windows: install Visual Studio Build Tools.

I want to start over with fresh data

Way 2: double-click Reset PaynEat data · way 3: docker compose down -v · way 4: cd backend && npm run db:reset

Still stuck?Ask on GitHub Issues or LinkedIn — say which way you used, your operating system and the message on screen.