[已讀亂回] GAS + N8N + Notion + Sheet 的架構選型
前陣子在某個 Facebook 技術社團看到一篇貼文,作者分享他幫某非營利宗教組織設計系統的選型過程。元件組合是 GAS(Google Apps Script)+ N8N + Notion + Google Sheet,每個工具都被指派了一個角色。
那篇文章蠻短的,看完之後我順手把這套 stack 在腦袋裡跑了一遍 — 想看看自己會怎麼還原它的架構、推導出哪些設計細節、最後跟我自己的習慣解法差在哪。
這篇是把那段腦袋裡的過程攤平寫下來的紀錄。會經過幾個階段:還原原文的架構、選一個假設版本、做幾輪結構觀察、補上量化驗證、最後對照業界常見的選擇。
原文摘錄
每次選技術架構都是一場取捨,這次分享我幫非營利宗教組織設計系統時的思考過程。
使用者是非技術背景的全職人員,所以第一個限制是「不能要求安裝任何東西」。Google Apps Script 直接在瀏覽器跑,部署即網頁,完美符合。
N8N 自架在 Zeabur,解決了兩個問題:一是視覺化流程讓每個 Webhook 獨立管理,維護容易;二是長期運行不依賴個人電腦,不怕有人關機。
Notion 最聰明的地方在於它同時是資料庫和後台管理介面。主管想調整員工權限?進 Notion 打個 checkbox 就好,完全不需要動程式碼。
Google Sheet 當備援,Notion 掛掉時資料繼續寫得進去,系統不中斷。
選工具的邏輯:
- GAS — 免費、免安裝、直接是網頁
- N8N — 視覺化流程、自架、長期穩定運行
- Notion — 資料庫兼後台,打 checkbox 調權限
- Google Sheet — 備援,Notion 掛了繼續跑
每個工具都有它的位置,沒有多餘的。 每個工具都有它存在的理由,沒有多餘的,也沒有缺少的。
這種「剛好夠用」的架構設計,你覺得有什麼優缺點?
還原原文的架構
要先說一件事:原文沒有附架構圖,下面所有架構圖都是我從文字推出來的猜想。我會列出幾個可能的讀法、用原文線索挑一個比較接近原作者意圖的版本,作為後續分析的對象。並不保證這個拆解跟作者腦袋裡的版本完全一致 — 但即使猜錯,後面挖出來的那幾個結構問題大致都還會存在,只是會落在不同的位置。
原文的關鍵句:「使用者是非技術背景的全職人員,所以第一個限制是『不能要求安裝任何東西』」。從這句出發,整個 stack 被組裝成這樣:
- GAS — 部署即網頁,使用者打開瀏覽器就能用
- N8N(自架在 Zeabur)— 視覺化流程、每個 Webhook 獨立管理、長期穩定運行
- Notion — 同時是資料庫和後台管理介面,主管打 checkbox 調權限
- Google Sheet — 備援,Notion 掛掉時資料繼續寫得進去、系統不中斷
問題來了:原文沒有直接畫架構圖,這四個工具實際上怎麼串起來其實有歧義。我試著畫了兩種可能的讀法。
架構 A:N8N 中央編排 hub
GAS 是薄殼、所有寫入都過 N8N。
[ Staff ] [ Manager ]
| |
| open web | tick checkbox
v v
+-------+ webhook +-----------------+ +-----------+
| GAS | ---------------> | N8N | | Notion |
| (thin)| | validate/route | | (DB+UI) |
+-------+ +--------+--------+ +-----+-----+
| ^
| read perm/write |
+-----------------+
|
| Notion down
v
+-----------------+
| Google Sheet |
| (backup) |
+-----------------+
架構 B:N8N 旁側自動化
GAS 直接 CRUD Notion,N8N 只處理排程通知、跨系統整合。
[ Staff ] [ Manager ]
| |
| CRUD on web | tick checkbox
v v
+-------+ Notion API +-----------------+
| GAS | <-------------> | Notion | <-- Manager edits
+-------+ | (DB + admin) |
+--------+--------+
^
| schedule / notify
|
+--------+--------+
| N8N (Zeabur) |
| sidecar |
+-----------------+
三條線索消弭歧義
回到原文逐句檢查,三處線索把指針推向 A:
第一,「視覺化流程讓每個 Webhook 獨立管理、維護容易」這組詞只有在 business logic 真的住在 flow 裡時才有意義。旁側自動化的維護頻率很低,不會被當成主要賣點。
第二,「Notion 掛掉時資料繼續寫得進去」要做到透明 fallback,必須有一個編排層在中間 route。架構 B 的 GAS 直接 CRUD 沒法做這件事,得拉一個編排層出來。
第三,四個工具的描述呈現「一條 pipeline」的節奏,不是「並排各自獨立」。
OK,A 比 B 更貼近原文意圖。但 A 還不夠精細,要繼續往下挑一個能完整撐起原文承諾的版本。
從多組讀法中挑選假設架構
A 還不夠細,主要是把「讀」這條路徑當沒看到。把使用者打開網頁的常見動作攤開來看:報名表單、列表查詢、編輯紀錄。讀的次數遠多於寫,而且讀通常需要即時回應。
如果讀也走 N8N,每個查詢都要拉一條 flow,N8N 的「視覺化好維護」反而變成負擔 — flow 數量會跟著情境膨脹。比較合理的拆法是讀寫分離。
架構 C:讀寫分離
讀直接打 Notion、寫過 N8N。
[ Staff ] [ Manager ]
| |
| open web | tick checkbox
v v
+--------+ read: direct Notion API +-------------+
| | <-------------------------> | Notion | <-- Manager edits
| GAS | | (DB + UI) |
| | write: webhook +------+------+
+----+---+ ^
| |
v | read perm / write
+----+--------+ |
| N8N | -------------------------------+
| (Zeabur) |
+------+------+
|
| Notion down
v
+------+--------+
| Google Sheet |
| (backup) |
+---------------+
但 C 有個問題 — Notion 掛了的時候,寫得進去、讀不出來。
寫入這條:Notion 掛了 → N8N 改寫 Sheet → 那筆資料安全進去 Sheet。但讀取這條:GAS 還是直直打 Notion → Notion 掛了 → 看不到剛剛寫進去的那筆。N8N 知道 Notion 掛了、自動改了寫入目標;GAS 不知道,照樣去找 Notion。兩邊看到的世界不一樣,使用者可能剛送出表單、馬上回頭刷新就找不到。
要補這個洞有兩條路。
第一條路是寫入改成 dual-write — 永遠雙寫。不切換,N8N 收到 webhook 就 parallel 寫 Notion 跟 Sheet。Notion 永遠是即時的,GAS 直讀 Notion 永遠對。
第二條路是讀也走 N8N — 統一判斷誰活著。GAS 退化成純前端,所有資料流都過 N8N。但 N8N 本來是視覺化 workflow 工具、不是高效能 API gateway,讓它扛所有讀請求是 stress 它的設計目的。
我選第一條,再補上一個讀取 fallback(Notion 掛了 GAS 改讀 Sheet)。後續用這個假設架構當分析對象。
假設架構 C''
[ Manager ]
|
| tick checkbox (bypass)
v
+-----------+
[ Staff ] read 1: primary | Notion |
| +-------------------> | (DB + UI) |
v | +-----+-----+
+--------+ | ^
| |-----+ |
| | | (a) parallel write
| GAS | |
| |--webhook--> +-----+--------------+
| | | N8N |
| | +-----+--------------+
+--------+ | (b) parallel write
| v
| read 2: fallback +----+---------+
+--------------------------------->| Google Sheet |
| (live mirror) |
+---------------+
讀寫分離、dual-write、讀取 fallback — 這版寫進去的東西讀得到、讀寫看到同一個世界,能撐起原文「系統不中斷」這個承諾。接下來對它做幾輪壓力測試。
結構壓力測試(質性)
假設架構大致定了。接下來看看這個結構在不同情境下會冒出什麼問題。
dual-write 的 partial failure
parallel 寫兩邊,意味著要面對四種狀態:
- 都成功 → OK
- Notion 成功、Sheet 失敗 → 鏡像不完整、但資料還在
- Notion 失敗、Sheet 成功 → 主庫缺資料、後台看不到
- 都失敗 → 整個寫入失敗
N8N flow 必須回答這四個狀態各自要怎麼處理:回 200 還是 4xx?要不要 retry?要不要告警?這個邏輯拉得出來,但拉得出來不代表簡單。
Notion 復原後的回填難題
更深的問題在恢復階段 — Notion 掛了 Sheet 接下所有寫入(或者 dual-write 寫不進 Notion)、可是 Notion 復原之後,那段時間 Sheet 收進來的資料怎麼回到 Notion?
三條設計選項,每條都有隱藏成本:
| 選項 | 機制 | 隱藏成本 |
|---|---|---|
| 自動回填 | 偵測 Notion 復原 → 跑 job 把 Sheet 缺漏寫回 | 健康偵測(不能只看一次成功)、找出缺漏(時間戳?status flag?)、Notion rate limit 下回填速度、Manager 同時編輯的 race、idempotent 需求 |
| 唯讀模式 + 手動 | 偵測異常 → 切到 reject write、return「系統暫時唯讀」→ 人工確認補完 | 使用者體驗坦白降級、N8N 需要 circuit breaker、需要 oncall 與 SOP、「人工」對非營利的可持續性是問題 |
| 接受 diverge | 不回填、Sheet 永遠完整、Notion 永遠缺一段 | 後台失真、權限決策基於不完整資料、Notion 慢慢變成「只是個 UI 殼」 |
備援的故事在「寫入不會斷」這段聽起來很美,可是一接到「復原之後呢?」這個問題就會發現是個沒被處理的角落。三條路每一條都不便宜。
Notion 三重身份的可用性集中
Notion 在這個架構中身兼三職:資料庫、後台管理介面、權限資料源。三件事被同一個 SaaS 服務承擔,意味著它一掛、三件事一起掛。
具體說:
- 資料層 — 可以 fallback 到 Sheet(前面 dual-write 解了)
- 後台介面 — Manager 編輯走 Notion UI、Notion 掛了 Manager 連 checkbox 都按不到
- 權限源 — N8N 每次寫入要讀 Notion 拿最新權限、Notion 掛了讀不到、要嘛 cache、要嘛 fallback Sheet、要嘛降級拒絕
Sheet 補上其中一件(資料層),另外兩件還是綁死在 Notion 身上。「Notion 掛了系統不中斷」這句話的範圍其實沒有那麼廣。
「不能安裝任何東西」的真正邊界
原文的設計起點是「不能要求安裝任何東西」。仔細想:這個約束的範圍只在使用者端。
把整個 stack 的「安裝行為」攤開:
User side Operator side (the author)
| |
v v
[ Browser ] [ Zeabur account + paid plan ]
| |
v v
open GAS web app self-host N8N container
| |
v v
open Notion / Sheet upgrades / monitor / downtime
| |
v v
zero install heavy install + ongoing ops
GAS、Notion、Sheet 都是 SaaS、零維運。N8N 才是這個 stack 裡最違反「零安裝」精神的元件 — 要安裝、付費、升級、監控、處理當機。
「零安裝」這個賣點被擴大解釋成整個 stack 的屬性,可是實際上它只是「把安裝負擔從使用者端轉移到雲端」。任何系統都需要有人維運,這點原架構並不特別;只是這份負擔具體落在哪、未來交接的成本是什麼,後面結論會再回來算一次。
量化驗證
質性觀察可以再用數字驗一次。挑各元件的可用性、組合起來、再看看 rate limit 對 throughput 的影響。
各元件每月可用性
數字是估計、不是合約 SLA:
| 元件 | 估計 |
|---|---|
| GAS | ~99.9% |
| N8N(Zeabur 自架) | ~99% 樂觀 |
| Notion | ~99.5% |
| Google Sheet | ~99.9% |
組合可用性的三種狀態
系統可分三種運作狀態,每種需要的元件不同:
- 完全運作(寫兩邊都成功 + 讀走 Notion):0.999 × 0.99 × 0.995 × 0.999 ≈ 98.3% → 每月 12.4 小時 downtime
- 寫入可運作(dual-write 至少寫進一邊):~98.9% → 每月 7.9 小時
- 讀取可運作(讀到任一邊):~99.9% → 每月 44 分鐘
如果 N8N 含維運失誤實際只有 98%,完全運作可用性掉到 ~97.3%、每月 ~19.5 小時 downtime。
關鍵發現:N8N 自架是整個架構的可用性瓶頸 — SaaS 元件再高可用,自架那塊會把總體拉低。實務上這份 downtime 可以靠維運排程(夜間升級、週末維護)吸收掉一大部分,使用者多半在工作時段操作的內部系統,感受不會像數字看起來那麼嚴重。
Notion API 3 req/s 的吞吐天花板
可用性是時間維度的限制,rate limit 是流量維度的限制。Notion 的 3 req/s 是最緊的那個。
每筆使用者寫入觸發的 API call:
1 user write ->
GAS -> N8N (N8N itself unlimited)
N8N -> Notion: read perm (1 req)
N8N -> Notion: write record (1 req)
N8N -> Sheet: write mirror (1 req)
= Notion: 2 reqs total, Sheet: 1 req total
寫入吞吐天花板 ≈ 90 筆/分鐘。
對日常使用 OK,但任何「同時段事件」(活動報名、月初繳費)會立刻撞牆。100 人同一分鐘報名 = 200 個 Notion req/min ≈ 3.3 req/s、撐不住。撞牆後 N8N 開始 retry 或 queue,使用者看到延遲或失敗。
更微妙的是:失敗 fallback 到 Sheet 不會緩解,因為瓶頸在 Notion 那邊 — 連權限都讀不過去。
Notion 三重身份不只是可用性風險集中,throughput 也是壓力集中點。
整合測試的隱性負擔
到目前為止講的問題(dual-write 的 partial failure、Notion 掛了的 fallback、權限傳播時機)每一個都需要對應的測試。沒有測試保障,這套架構的承諾就只是口號。
問題是:multi-service 架構的測試難度不是線性增加、是組合爆炸。
每個外部服務各有它的測試困境:
- GAS 沒有本機模擬器、deploy 完才測得到、log 在 Apps Script editor 裡看、unit test 工具薄弱
- N8N 要跑一個真實 instance、webhook URL / credentials / external connections 都要對齊
- Notion API 有 rate limit、沒有官方 sandbox / test workspace 概念、測試會污染 workspace
- Google Sheets API 同樣有 rate limit + quota,多測幾次就撞額度
- 跨系統 async flow 是非同步的,timing / ordering / retry 都要測
「Notion 掛了系統不中斷」這句話要驗證,得能跑這 7 個失敗路徑情境:
| # | 情境 |
|---|---|
| 1 | happy path:寫 Notion ✅、寫 Sheet ✅ |
| 2 | Notion 寫失敗、Sheet 成功 → N8N flow 怎麼回應? |
| 3 | Sheet 寫失敗、Notion 成功 → 對帳機制? |
| 4 | 兩邊都失敗 → 使用者畫面顯示什麼?資料丟了嗎? |
| 5 | Notion 讀失敗、GAS fallback Sheet → 觸發條件是 timeout 還是 error code? |
| 6 | 權限讀失敗(Notion 掛時 N8N 嘗試讀) → 降級拒絕、cache、還是 fallback Sheet? |
| 7 | Manager 改了權限的傳播時機 → 多久內 N8N 寫入會讀到? |
要可靠地測這 7 個情境,需要能人為製造每個服務的失敗(攔截 outbound HTTPS?wireshark?mock layer?),需要能對 N8N flow 做 input / output 斷言,需要跨服務追蹤 trace。
這套測試基礎建設本身就是個專案。對非營利組織來說,做不做得起來是另一個問題 — 而沒有這套基礎建設,前面所有的「系統不中斷」承諾就沒有驗證機制。
對照組:經典三層架構
到這裡累積了不少結構代價:dual-write 的 partial failure、Notion 復原回填、三重身份集中、零安裝邊界、可用性瓶頸、rate limit 撞牆、測試矩陣組合爆炸。每一塊都不是無解,但解都不便宜。
退一步想:如果這套 stack 的訴求只是「讓非技術使用者可以填表單、看資料、Manager 可以管理權限」,業界長年的預設答案其實是另一套 — 經典三層架構。
frontend → backend api → stateful data (database)
具體一點:
[ Staff ] [ Manager ]
| |
| open web + Google auth | open admin + Google auth
v v
+----------------------------------+
| Web App (frontend) |
| forms / list / edit / admin UI |
+--------------+-------------------+
|
| HTTPS / JWT
v
+--------------+-------------------+
| Backend API (self-host) |
| business logic / perm / CRUD |
+--------------+-------------------+
|
| SQL
v
+--------------+-------------------+
| Postgres (Zeabur addon) |
| transaction / backup built-in |
+----------------------------------+
部署仍在 Zeabur(跟原架構同樣的自架前提)。前端的 Google auth 是一行 OAuth 重導向、不是核心。
moving parts 對比
| 原架構(C'') | 經典三層 | |
|---|---|---|
| 主要元件 | 4 個 + 多條同步線 | 3 層、單向資料流 |
| 資料層 | Notion + Sheet + 同步 | 一個 Postgres + 自帶 backup |
| 寫入路徑 | dual-write + partial failure 處理 | 單寫 + DB transaction |
| 讀取路徑 | 首選 Notion / fallback Sheet | 直讀 |
| 權限管理 | Notion checkbox(被 Notion 可用性綁定) | 標準 RBAC |
哪些原架構的成本在三層下消失
- dual-write 的 partial failure → DB transaction 原子性
- Notion 復原回填難題 → 沒有第二份資料、沒有回填問題
- Notion 三重身份集中 → DB / admin UI / 權限源各自獨立、可以分別保護
- Sheet 鏡像權限 / N8N 讀權限 fallback → 權限就在 DB 裡
- Notion 3 req/s 卡 throughput → 自架 DB 沒有外部 rate limit、線性 scale
- 7 個失敗路徑測試矩陣 → 塌縮成 1-2 個(DB 連線失敗、權限失敗)
- N8N 變單點瓶頸 → 沒有 N8N
複雜度沒消失,是「不該存在的複雜度根本沒被引入」。
三層架構不是免費午餐
當然,這條路有它的代價:要寫程式(不是拉 flow)、開發初期成本高一點、維運仍然要懂 backend 與 DB。
但反過來看:原架構也要懂 N8N、懂 Notion API quirks、懂 Sheet quota、懂 partial failure 處理、懂 rate limit。自架的代價本來就要付,差別只在「換來的是 visual flow,還是換來經典 backend」。
適用條件是「有工程師能持續維運」— 跟原架構自架 N8N 是同等前提。如果完全沒人懂程式、沒人維運,那其實該選的是純 SaaS 工具(Zapier、Make、Airtable、Glide),完全不要自架。
換個角度看 — 可以在 Local 完整跑起來的三層式架構,在 AI Agent 普及之後其實是一份相當好的午餐。
整套系統能在本機啟動、有完整的測試環境,AI Agent 就可以接手整個開發迴圈:寫 feature、跑測試、看 log、debug、再跑一次、commit,整輪可以自動跑。對比原架構,N8N flow 編輯、Notion schema 調整、跨 SaaS 整合測試這些事情,AI Agent 沒辦法接過去自己迭代 — 每一步都要人工打開不同服務的 UI 點來點去,開發迴圈在這裡接不起來。
「要寫程式」這個門檻在 AI Agent 普及之後降低不少。工程師的工作往「定義介面、code review、把關 merge」收,逐行打字、跑測試、改 bug 這類重複性循環交給 Agent。三層 + Local,剛好是這套新開發模式最會的場域。
結論
質性觀察、量化指標、整合測試難度,前面三個維度的審視,最後可以收成一個簡單的選擇題:要不要繼續用 GAS + N8N + Notion + Sheet 這套組合?
兩條合理的路徑都成立,差別在於把複雜度放在哪裡:
- 維持原作者的提案 — 用 SaaS 工具的編排(N8N flow、Notion schema、Sheet 鏡像)處理業務邏輯;要回答的設計題目落在 dual-write、復原回填、跨服務整合測試這些事
- 換成經典三層架構(frontend + backend api + stateful data)— 用 codebase 裡集中的程式碼處理業務邏輯;要回答的設計題目落在資料模型、API 邊界、frontend、自架 backend 的營運上
如果是我負責設計 + 實作這套系統的完整交付,會選後者。
想像一下使用者拿到的部署手冊長什麼樣。
經典三層版本:一行 docker compose up,前端、後端、資料庫一起啟動;連備份還原都可以寫在同一份 compose 設定裡,使用者按一個指令就執行。
未來要從 Zeabur 搬到別的 VPS 或 VM、或維運責任要轉手給其他人,也都只是把 container image + 一份 SQL dump 交出去而已。
對比之下,原架構的交付手冊大概要這樣寫:
- 先去 GAS 開 project、複製這段 code 上去、deploy 成 web app
- 再到 Zeabur 起 N8N 容器、import flow JSON、設定 webhook URL
- 再到 Notion 開 workspace、複製 database template、把 N8N 的 integration token 接上去
- 最後到 Google Drive 開 Sheet、設定 sharing、把 Sheet ID 抄回 N8N
一堆畫面截圖、一堆要點開的設定面板。備份也類似 — 要嘛附截圖教使用者打開每個服務匯出資料、要嘛另外寫一個備份工具給他用。
還有一件事是 scale。經典三層流量上來要加機器、加 DB replica、甚至換更大的 VPS,都是自己掌握的選項。
原架構依賴 Notion,3 req/s 是寫死在 SaaS 端的天花板,沒辦法臨時決定要放寬。受限的不只是當前的吞吐天花板,而是「需要時能不能自己調整」這件能力本身。
至於「為什麼不用視覺化編排省事一點」 — 既然已經接受「需要工程師長期維運」這個前提(不然 Zeabur 上的 N8N 也維運不下去),那把工程師的能力直接拿來寫經典三層,整體結構更乾淨、隱性成本更少、測試更可控。
順著這個方向再多想一步:Notion 在這套架構裡身兼 DB、admin UI、權限源三職,但每件事都不是它原本的設計目的。
具體看三個限制:3 req/s 的 rate limit 從量化分析看是最緊的天花板;資料多了 page 載入會明顯變慢,這是用過大型 Notion database 的常見體感;可用性又跟 Notion 服務本身綁死。
如果 Manager 在這套系統的需求單純就是「打 checkbox 調權限」,那刻一個簡單的 admin 頁面 vibe-code 半小時就完成了,沒 Notion 也行 — 換來的是穩定的延遲、可預期的可用性、權限資料留在自己手上。
每次面對這種選型,我自己會先問兩個問題:一是這個複雜度有沒有換到等量的好處;二是這個選擇主要的風險是什麼、我願不願意為了好處承擔它。這兩個問題拿去評估自己手上的設計也適用。
純粹結構觀察,給有興趣的人參考。