「我有一家麵店,想要客人掃 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。
業主端只需要:
- 跟電信業者要固定 IP(中華電信加購月 NT$300)
- 路由器 80/443 port 轉發到 POS 主機
- 我們幫設好的 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 / 線上表單
延伸閱讀: