Island-Mode Server
一台小型的 Node 伺服器在實體站點上運行,維護該站點在 Firestore 中對應資料區塊的即時 RxDB 副本。當網路暢通時,它處於隱形狀態;當網路中斷時,區域網路上的自助點餐機/員工終端機會自動切換至該伺服器,站點仍能繼續接單、調整庫存、控制硬體。重新連線後,離線期間的作業會回補至雲端。貫穿全局的核心洞察是:同步是兩個系統,而非一個 — 文件層級的 RxDB 複製用來同步狀態,加上 HTTP 回補用來傳輸必須由雲端自行應用其邏輯的業務事件(庫存增量、稽核資料寫入)。兩者相輔相成,缺一不可。
使用時機
- 站點必須在網路中斷時仍能進行真實寫入(訂單、庫存、硬體控制),而不只是快取讀取。
- 終端機是瀏覽器基礎(PWA/自助點餐機),且必須能無縫切換至備援。
- Firestore 是雲端權威來源且維持不變。
不建議使用的情況
- 純讀取快取或一個只需 Firestore 內建離線持久化的 PWA — Firebase SDK 已能處理,無需額外伺服器。
- 使用不同的雲端資料庫(Supabase/Postgres):複製層級的概念雖可套用,但此處的所有範本皆專屬於 Firestore。
- 多主同步的跨站點對等複製 — 此設計為嚴格的星狀拓撲,以雲端為權威來源,並採用最後寫入者取勝的衝突解決策略。
架構
Internet
|
+--------+---------+
| 雲端 (SSoT) | Firestore + 公開 API + 定時狀態標記 cron
+--------+---------+
| |
RxDB 複製 HTTP 回補 (重新連線)
| |
+-+-------------+-+
| 本地伺服器 | Node/NestJS + RxDB,LAN 透過 nginx TLS 提供 :443
+--------+--------+
|
LAN — 自助點餐機 PWA、員工 PWA、硬體控制器
關鍵事實
- 每個對複製集合進行的雲端寫入都必須標記檢查點欄位(
serverTimestamp: FieldValue.serverTimestamp())與_deleted: false— RxDB Firestore 外掛程式會根據serverTimestamp > checkpoint拉取資料;未標記的文件永遠不會被複製機制拉取。 - 三種複製層級,可依集合選擇:僅拉取(站點消費的設定)、雙向(站點會變更的營運狀態)、僅推送(站點產生的日誌)。搞錯集合的層級是主要的設計錯誤。
- 使用記憶體儲存的 RxDB 意味著離線時重新啟動會遺失所有離線作業。 副本會從 Firestore 重新填入,但離線建立的文件會消失。請明確評估儲存取捨 — 參見 replication.md。
- 回補作業為至少一次語意,因此雲端接收端必須具有冪等性 — 使用客戶端產生的 ID 作為每個 apply 的索引鍵,並跳過已處理過的內容。
- 推送過濾器可防止迴響:雙向推送僅推送標記為
_offlineCreated/_locallyModified的文件,如此從雲端拉取的文件就不會被推送回去。 - 終端機優先連線雲端 — 故障切換僅在連續 N 次健康檢查失敗後才會啟動,且離線時終端機必須持續掃描本地伺服器,而非僅在切換時掃描一次。
硬性規則
切勿在未經認證的情況下暴露雲端同步接收端點。 這些端點會處理庫存增量與訂單注入。最低限度必須使用共享密鑰標頭。
在連線雲端時,切勿寬鬆地驗證離線員工權杖。 不驗證簽章即解碼的降級方式是區域網路環境下可接受的取捨;必須嚴格限制在伺服器實際處於離線狀態時才能使用,否則將成為繞過簽章驗證的後門。
對於尚未確認同步完成的交易,切勿重設本地庫存增量。 應在收到確認後按 ID 重設,否則離線銷售將重複計算或從可用庫存中消失。
切勿讓本地伺服器自行產出歸屬於雲端的業務規則(如營業時間、定價)。應複製設定並據以計算,否則島嶼模式的行為將與網站不一致。
快速開始
- 將集合歸類至各層級並定義邊界名稱 — architecture.md。
- 建立 RxDB 並搭配自訂權杖認證與安全規則進行複製 — replication.md。
- 新增重新連線回補機制與冪等的雲端接收端 — sync-flush.md。
- 設定心跳/狀態檢查鏈與客戶端故障切換邏輯 — network-failover.md。
- 保護本地 API(員工 / 自助點餐機 / 硬體 HMAC / 靜態權杖) — auth.md。
- 鏡像終端機所需的雲端端點 — local-api.md。
- 在現場部署:systemd、nginx TLS、mDNS、監控 — operations.md。
參考文件索引
| 情境 | 觸發關鍵字 | 參考文件 |
|---|---|---|
| 拓撲、層級、邊界、重新命名表格 | pull-only、bidirectional、push-only、dual-path、locationId、conflict | architecture.md |
| 副本設定、結構定義、檢查點陷阱 | RxDB、replicateFirestore、serverTimestamp、custom token、storage-memory、firestore.rules | replication.md |
| 重新連線回補、庫存增量、接收端 | flushAll、idempotent、FieldValue.increment、localDelta、syncedIds | sync-flush.md |
| 中斷偵測與 API 切換 | heartbeat、lastHeartbeatAt、cron、NetworkManager、apiBaseUrl、failover | network-failover.md |
| 本地 API 認證 | AuthGuard、HMAC、replay window、offline JWT fallback、kiosk key | auth.md |
| 離線端點與寫入 | availability、mutex、offline booking、check-in、pricing stock filter | local-api.md |
| 現場部署與操作手冊 | systemd、nginx、self-signed TLS、mDNS、avahi、journalctl、rollback | operations.md |
| 帳本:稽核變更、保留、新增的內容 | provenance、audit、deviations、kept deliberately | provenance.md |
針對信任關鍵邏輯(HMAC 驗證、離線權杖解碼、在實際 RxDB 上的增量折疊、故障切換重新掃描)通過的 vitest 測試套件: assets/behavior.test.ts — 將其帶入目標專案作為回歸測試覆蓋。