2026年5月9日11 分鐘POS 系統 · 餐飲 POS · 桌邊點餐 · LINE Pay · 電子發票 · KDS · Electron · SQLite · 小吃店

台灣小吃店 POS 該怎麼架 — 桌邊 QR + LINE Pay + 電子發票 + KDS 平板的整合設計

客戶要的不是「會結帳的收銀機」,是「客人手機點餐、付款、開發票、廚房自動印單、平板看單」一整套流。這篇拆我們最近交付的一套餐飲 POS 整體架構:Electron + SQLite + Express + WebSocket,三介面三印表機、LINE Pay 三條通路。

陳先生 (Henry)

「我有一家麵店,想要客人掃 QR 點餐、付款自動進帳、廚房自動印單、平板顯示出餐進度。預算不能太誇張。」

這是我們最近交付的一個案子(北部某傳統麵店)原始描述。聽起來不複雜,但**「整合」這層就是難點** — 桌邊點餐、LINE Pay、電子發票、廚房印表機、KDS 平板,每一個單獨拿出來都是一個 SaaS,整合在一起 + 離線可用 + 預算 NT$10 萬以下 才有意思。

這篇拆我們交付的整體架構。給想做類似專案的開發者、或想知道「自己要的 POS 該長什麼樣」的餐飲業者參考。

為什麼不直接用市售 POS(iCHEF、PosBank、open!) #

第一個念頭當然是「買現成的」。但都不對:

方案 為什麼不適合
iCHEF / open! 訂閱制 月費 NT$1,800-3,500,3 年下來 6-12 萬,功能還是被限制
傳統 PosBank / VPC 買斷 介面醜(90 年代風格)、桌邊點餐要加錢、客製化等廠商排程
網路收銀機(街口 / 線金科技) 桌邊 QR 通常綁支付通路,LINE Pay 不一定支援所有方案
自己刻 沒人有時間刻 6 個月

關鍵 insight:現代台灣小吃店要的不是「收銀機」,是「客人 + 員工 + 廚房 + 平台」的整合系統。市售 POS 通常只強在一塊(收銀)。自己整合一套,每塊用對的方案,總成本反而最低

整體架構:一台 POS 主機跑全部 #

                  ┌──────────────────────────────┐
                  │   POS 主機(Windows / mac)   │
                  │   Electron App                │
                  │   ├ React UI(收銀、後台)    │
                  │   ├ SQLite(本機資料)        │
                  │   ├ Express :8080(API)     │
                  │   └ WebSocket(即時推播)    │
                  └──────────────────────────────┘
                       │              │              │
            ┌──────────┘     ┌────────┴───────┐      └──────┐
            ↓                ↓                ↓             ↓
      ┌──────────┐    ┌──────────┐    ┌──────────┐  ┌──────────┐
      │ KDS 平板  │    │ 桌邊 QR  │    │ 印表機×3 │  │ Turnkey  │
      │(瀏覽器) │    │(手機)   │    │ ESC/POS  │  │ 電子發票 │
      └──────────┘    └──────────┘    └──────────┘  └──────────┘
                         │
                         ↓
                    ┌──────────┐
                    │ LINE Pay │
                    │(3 通路)│
                    └──────────┘

所有東西跑在一台 POS 主機上:Electron App 同時是 UI、API server、資料庫、印表機驅動、外部整合。離線優先:網路斷了還能繼續開單、結帳、印單,等網路回來再 sync。

技術棧:

  • Electron 34 + React 19(櫃檯 UI)
  • SQLite(本機資料庫,路徑 %APPDATA%\<app>\data\*.db
  • Express :8080(本機 HTTP server,給 KDS / 桌邊 QR 連)
  • WebSocket(KDS 即時推單)
  • HMAC-SHA256(桌邊 QR 簽章 + LINE Pay 簽章)

三個操作介面 #

POS 主機開出三個獨立介面,跑在同一個 Express server 不同 path 下:

1. POS 收銀(Electron 主視窗) #

員工面對的櫃檯介面。觸控螢幕優化、大按鈕、F-key shortcut。

主要功能:

  • 點餐(內用 / 外帶切換)
  • 桌號管理(佔位、結束、合併、轉桌)
  • 結帳(現金 / LINE Pay / 信用卡刷卡)
  • 開立電子發票(4 種:載具 / 統編 / 捐贈 / 紙本)
  • 折扣(百分比折 / 固定金額補價差,多種預設按鈕)
  • 對帳報表(日結 / 月結 / 通路拆分)

2. KDS 廚房顯示(瀏覽器 + WebSocket) #

設備:一台 Android 平板(10-11 吋,約 NT$3,000-5,000)+ 牆掛支架。

不用買「KDS 專用機」(一台動輒上萬),瀏覽器開 http://<POS主機IP>:8080/kds 就好。

畫面分三欄:

內容 顏色提示
待製作 新單,廚房沒看過
製作中 廚師點「開始」後
待出餐 點「完成」後等取餐

WebSocket 推單,新單進來叮一聲 + 紅色閃爍,廚師不會漏單。

3. 桌邊 QR 點餐(手機 + HTML) #

桌上貼一張 QR Code(80mm 感熱紙列印,含桌號 token)。客人掃 QR:

https://<業主固定IP網域>/t/A05?s=<HMAC-SHA256 簽章>

s 參數是該桌號用 HMAC-SHA256 簽出來的 token,防止有人手改桌號跨桌下單

點完餐有兩個結帳選項:

  • 線上付款:跳到 LINE Pay redirect → 付完 webhook 通知 POS → 廚房自動印單
  • 到櫃檯結帳:訂單進「未結帳」佇列,員工結帳時 callback 出來

未付款 / 未結帳 15 分鐘自動取消,釋放桌位(避免佔位)。

桌邊 QR Token 設計:

const token = crypto
  .createHmac('sha256', QR_SECRET)
  .update(`${tableNo}|${yyyymm}`)
  .digest('hex')
  .slice(0, 12);

// /t/A05?s=a3f8d2e4b7c1

yyyymm 月份是讓 token 每月自動失效(避免被人截圖永久重用)。月初 POS 自動產 1 張 PDF 給業主重印桌邊 QR。

三台廚房印表機分工 #

中餐廳廚房有冷區 / 熱區 / 麵台 / 飯台分區 — 一張單印一台是錯的(廚師要跑來跑去看單)。正確做法:按品項分區自動派單

商品 schema 加一個 mprint 欄位:

意義
1 飯台(熱食)
2 麵台(熱食)
3 小菜冷盤台
9 全部三台都印(綜合餐)
0 不印(飲料、贈品等)

下單時程式按 mprint 把訂單明細拆成 3 張單,分別送到 3 台 IP 印表機(TCP :9100 ESC/POS):

// 廚房印表機分流
async function printKitchen(order: Order) {
  const groups = {
    rice: [],   // mprint = 1 or 9
    noodle: [], // mprint = 2 or 9
    side: [],   // mprint = 3 or 9
  };
  for (const item of order.items) {
    if (item.mprint === 1 || item.mprint === 9) groups.rice.push(item);
    if (item.mprint === 2 || item.mprint === 9) groups.noodle.push(item);
    if (item.mprint === 3 || item.mprint === 9) groups.side.push(item);
  }

  await Promise.all([
    groups.rice.length && printESCPOS(PRINTER_RICE_IP, renderTicket(order, groups.rice)),
    groups.noodle.length && printESCPOS(PRINTER_NOODLE_IP, renderTicket(order, groups.noodle)),
    groups.side.length && printESCPOS(PRINTER_SIDE_IP, renderTicket(order, groups.side)),
  ]);
}

印表機失敗自動 retry 3 次,仍失敗寫到 print_jobs 表 + 紅燈警示,員工手動補印

櫃檯第 4 台印表機印紙本發票 + 對帳報表

LINE Pay 三條通路備援 #

LINE Pay 在台灣使用率高,但有時會抽風(platform 端 503、簽章驗證 timeout)。我們設計 3 條通路備援:

通路 API 用途 出問題時
Online v3 Request/Confirm 桌邊 QR 客人手機付款 跳到「到櫃檯結帳」
Offline v2 oneTimeKey 櫃檯掃客人手機 LINE Pay 條碼 換 Online QR 給客人自己付
LINE Pay Mini (無 API) 純人工標記,月底對帳 系統永遠可用

3 條都串好之後,LINE Pay 服務出狀況時員工有 backup,不會「店裡就因為 LINE Pay 掛了不能收錢」。

申請流程詳見 LINE Pay 商家 API 申請的 5 個眉角

電子發票:本機 Turnkey 即時上傳 #

每張結帳都要開電子發票(B2C 用 C0401,B2B 用 F0401)。整合財政部 Turnkey 4.1:

  • B2C 載具 / 捐贈:寫 XML 到 C:\EINVTurnkey\XML\UpCast\B2BEXCHANGE\C0401\SRC\
  • B2C 紙本:同上 + 觸發櫃檯印表機印紙本
  • B2B 統編:B2SSTORAGE 路徑

直連 MSSQL 看完整狀態(待上傳 / 已上傳 / 已確認 / 異常 4 桶)+ spawn run_start.cmd 暫改排程強制即時上傳。

完整 Turnkey 整合的坑詳見 台灣電子發票 Turnkey 4.1 串接的 4 個坑

對外網域:Caddy + Let's Encrypt 自動憑證 #

桌邊 QR 需要 HTTPS(手機瀏覽器才不會擋)。但小店哪有時間管 SSL 憑證?

Caddy 自動化全包

order.example.com {
    reverse_proxy localhost:8080
}

Caddy 自動拿 Let's Encrypt 憑證、自動 90 天輪替、自動 redirect HTTP → HTTPS。

業主端只需要:

  1. 跟電信業者要固定 IP(中華電信加購月 NT$300)
  2. 路由器 80/443 port 轉發到 POS 主機
  3. 我們幫設好的 domain(用客戶自己的,或我們的子網域 <店名>.gomylife.tw

整個外網設定 30 分鐘搞定,業主不用懂任何網路概念。

服務費與稅務細節(台灣餐廳專屬) #

很多人沒注意到的眉角:

規則 說明
內用 +10% 服務費 服務費也計稅基,發票顯示為「服務費」一筆
外帶不加服務費 order.kind = '外帶' 判斷
內用外帶稅率都 5% 不是有些人以為的「外帶免稅」
服務費結帳才送 沿用傳統 POS 邏輯:服務費不影響廚房單
發票金額 = 商品 + 折扣 + 服務費(依稅後加總,不是稅前) 跟一些海外稅制邏輯不同

POS 內把服務費當「負商品明細項目」也加進訂單,跟正常商品一樣計稅、開發票,邏輯統一不會錯

折扣:8 種預設按鈕,不要做「自由輸入折扣」 #

折扣按鈕設計不能讓員工自由輸入金額(防內偷)。我們做 7-8 個預設按鈕,從舊系統 disc.dbf 全盤遷移:

名稱 類型 計算
8 折 百分比 小計 × -20%
9 折 百分比 小計 × -10%
95 折 百分比 小計 × -5%
補價差 固定 -1 元
補價差 10 固定 -10 元
雙寶補差價 固定 -30 元
排骨補差價 固定 -40 元

每個折扣以「負值明細項目」加入訂單 — 跟正常商品一樣記錄、可追蹤、開到發票上。不要做「結帳前打折」這種隱形邏輯,會稽核不出來。

資料庫設計重點 #

SQLite 路徑:%APPDATA%\<app-name>\data\<app-name>.db

關鍵 schema:

-- 訂單主表
CREATE TABLE orders (
  id TEXT PRIMARY KEY,
  table_no TEXT,
  kind TEXT,           -- '內用' / '外帶'
  status TEXT,         -- 'pending' / 'paid' / 'cancelled'
  total INTEGER,
  payment_method TEXT, -- 'cash' / 'linepay' / 'credit'
  created_at INTEGER,
  paid_at INTEGER
);

-- 訂單明細(含折扣 / 服務費都當一筆)
CREATE TABLE order_items (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  order_id TEXT,
  product_id INTEGER,
  product_name TEXT,   -- 冗餘存:商品改名後舊單還是看得到原品名
  qty INTEGER,
  unit_price INTEGER,  -- 負數 = 折扣 / 服務費
  mprint INTEGER       -- 廚房印表機分流
);

-- LINE Pay 交易追蹤
CREATE TABLE linepay_transactions (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  order_id TEXT,
  transaction_id TEXT, -- LINE Pay 自己給的
  channel TEXT,        -- 'online' / 'offline' / 'mini'
  amount INTEGER,
  status TEXT,
  raw_response TEXT    -- 整個 JSON 留底,debug 用
);

冗餘存 product_name 是關鍵:商品改名後,舊單列印 / 退款 / 重印發票還能看到當時的品名。不要 join 商品表抓即時品名

預算抓多少 #

這套整合下來客戶要準備的:

項目 預算
POS 主機(Mini PC + 觸控螢幕) NT$ 20,000-30,000
廚房印表機 × 3(網路 ESC/POS) NT$ 12,000(每台 4,000)
櫃檯發票印表機 × 1 NT$ 4,000
KDS 平板 + 牆掛架 NT$ 5,000
軟體開發 / 整合 / 訓練 NT$ 60,000-120,000
總計 NT$ 100,000-170,000

3-5 年後沒月費沒授權,比 iCHEF 月 NT$2,000 訂閱 5 年下來 NT$120,000 更便宜,而且功能完整 own 在手裡

重點整理 #

設計 為什麼
單台 POS 主機跑 Electron + SQLite + Express 離線可用,所有東西一台搞定,故障好排查
三介面(POS / KDS / 桌邊 QR)共用 Express 一套 backend,三個前端,狀態同步
三台廚房印表機按 mprint 分流 廚師不用跑來跑去看單
LINE Pay 三通路備援 一條掛了還有兩條
HMAC-SHA256 + 月度失效 token 桌邊 QR 防偽
Caddy + Let's Encrypt 自動憑證 業主完全不用懂 SSL
折扣全預設按鈕、服務費當訂單明細 防內偷、易稽核
冗餘存 product_name 商品改名不影響歷史單

客戶想評估 #

小吃店 / 餐廳 / 飲料店要做 POS 升級,可以聊聊:

  • 評估你現在的需求(桌數、客流量、付款通路)→ 規劃書 + 報價(諮詢免費)
  • 完整交付(硬體 + 軟體 + 整合 + 訓練 + 上線陪跑)
  • 接手現有 POS 加上桌邊 QR / LINE Pay / 電子發票模組

聯絡:0912852835 / henryccy@icloud.com / LINE @3q3tw / 線上表單

延伸閱讀:

想聊類似的東西?

諮詢免費,依工時報價。

聯絡我們