事故調查 · VIBE CODING 的雲端帳單 · 2026-10
每加一分,
就扣一分
一位國小老師用 AI 做了一個「加分」工具,每月 5.4 萬人在用,雲端帳單一個月 NT$2,854。他的產品機制是加分,但每加一個功能、技術選型就錯一項,帳單上就扣一分。這份報告用同一張計分板,把加分和扣分並排看。
TL;DR
三句話
- 錢不是 Cloudflare 收的。workers.dev 只負責送網頁;NT$2,854 幾乎全是 Firebase Realtime Database 的下載流量。
- 扣分的那一步只有一個:把「整班壓成一塊」的備份格式,直接拿來當即時廣播的格式。老師加一分,全班 30 台裝置各自重新下載整塊。按位元組計費的資料庫,這樣做大約貴 400 倍。
- 最短的修法不用搬家:多開一個只放即時數字的小節點給學生端監聽,整塊改成開艙讀一次。估計下載量從每天 1.2 GB 降到 0.1–0.3 GB,回到免費額度內。
月活躍使用者(含匿名)
9 月一路線性上升
單日活躍最高
週末掉到 1,200 左右
RTDB 單日下載
免費額度約 360 MB/日
Firestore 讀取/日
不到免費額度 0.1%
01 · 計分板
加分欄和扣分欄,同一張表
左欄是作者做對的事,右欄是同一個時期做錯的技術決定。每一列都是一個功能被加進來的時刻。這張表就是整份報告的主軸,後面的章節只是把每一列攤開。
| 時間 | +1 · 做對的 | -1 · 選錯的 | 淨分 |
|---|---|---|---|
| 2025-10 | 先做出老師自己要用的加分工具,資料正規化存進 Firestore。 | — | +1 |
| 2026-05 | 資料改為本機優先,雲端只當備份;整班壓成一份文件、每天限存 3 次。按次計費的 Firestore 這樣做很省。 | — | +1 |
| 2026-05 | 加學生遊戲艙:掃 QR 進艙,加分變代幣,寵物、轉蛋、Boss 戰。使用者從老師變成全班。 | 同步層改用按位元組計費的 Realtime Database,卻沿用整班壓縮塊,每台學生裝置常駐監聽整塊。 | −1 |
| 2026-05 | 所有學生操作走 Cloud Functions 判定,防作弊。 | 每個操作都多一次函式呼叫和一次資料庫往返;學生每台用匿名登入,月活躍衝到 5.4 萬。 | 0 |
| 2026 夏 | 發現一天燒 300 多元,做了底層改造;分數加緩衝、寫入加冷卻、內容沒變不重發。 | 修的是「發布頻率」,沒有修「每次發布的大小」。 | 0 |
| 2026-09 | 自己找到「拆開存」的方向,開始試行。 | 只對一個帳號開放;正式環境仍是整塊廣播。 | 0 |
| 全程 | 工具完全免費、不鎖功能、伺服器費自付。 | 贊助收入連一週伺服器費都不夠;寫給 AI 的技能規定「新手沒問成本就不教定價」,所以沒人在選型時問過單位成本。 | −1 |
功能一直在加分,架構一直在扣分。產品的加分機制設計得很好;少的是一個會在每次選型時扣分的機制。
02 · 現況架構
三張圖看懂錢從哪裡流出去
C4 模型由外往內三層:L0 是誰在用、依賴哪些外部服務;L1 是系統由哪幾個部分組成;L2 是一次加分在程式裡經過哪些元件。藍色粗線是花錢的那條路。
L0 · 系統情境
老師管理班級,學生用自己的裝置進遊戲艙;FunClass 只依賴三個外部服務。
L1 · 容器
後端幾乎都在 Firebase。老師把整班壓縮塊寫進 Realtime Database,每台學生裝置各自監聽同一塊。
L2 · 元件:一次「7 號 +1 分」走過的路
分數有緩衝、內容沒變不會重新發布,這些都做對了;但只要有變,送出去的就是整塊。
03 · 扣分的那一步
同一招,換了計費單位就從省錢變燒錢
兩個資料庫的計費方式不同,決定了同一個技巧的命運:
- Firestore 按「次」計費。讀一份文件算一次,不管多大。整班壓成一份文件,讀一次拿到全部,越壓越省。第二代這樣做完全正確。
- Realtime Database 按「位元組」計費。下載多少 GB 付多少,約每 GB 1 美元。它只能比對 JSON 節點的差異,一段 base64 字串改一個字元,整段都算新的。
| 一次「7 號 +1 分」 | 送出的資料 | × 監聽裝置 | 總下載 |
|---|---|---|---|
| 整班壓縮塊(現況)classPublic/{classId} | 約 40 KB | 30 | 約 1.2 MB |
| 拆成每人一個節點students/07/score | 約 100 B | 30 | 約 3 KB |
整塊大小是假設值,線上實際大小沒辦法在未登入時量到。但帳單上的 1.2 GB/日反推,約等於每天重新下載整塊 3 萬次;以每天 3,000 多位學生算,每人約 10 次,大致就是「開艙一次,加上班上每次有人加分」。
AI 為什麼沒提醒他
作者寫給 Codex 的技能 build-firebase-cloudflare-app 有一條:使用者是新手、沒提到成本時,選不用付費的路線,而且不要教定價。本意是不嚇跑新手,結果是 agent 選資料庫、設計同步格式時,沒有人回頭問「每多一位學生要多付多少」。agent 預設優先讓功能動起來;單位成本不在它會檢查的項目裡。
04 · 把分加回來
先走最短的路:A1 冷熱分離
不動資料模型,整塊壓縮資料照舊,只把「需要即時跳動的數字」抽出來另外走一條小路:
- 新增小節點
classLive/{班級}:只放每人的能力值和代幣,一般 JSON,不壓縮。老師加分時順手更新這一格。RTDB 只會把變動的那一格推給監聽者。 - 學生艙改監聽
classLive;整塊改成開艙時get()讀一次,不再常駐監聽。 - 整塊加版本號:學生端把整塊留在本機,開艙時先比對版本,有變才下載。他已經有
classPublicMeta這個節點了。 - 整塊的發布改成節流:名單或設定改了、每隔幾分鐘、或老師按「下課」時才發布。
現況 vs A1:差別只在藍色那條路
A1 多了一個小節點,學生端從「常駐監聽整塊」改成「監聽小節點、開艙才讀整塊」。
| 現況 | A1(估算) | |
|---|---|---|
| 每次加分推送的資料 | 整塊 × 30 台 | 一格(約 100 B)× 30 台 |
| 整塊被下載的時機 | 開艙+每次分數變動 | 只有開艙,而且版本變了才下載 |
| RTDB 下載量/日 | 1.2 GB(帳單實測) | 約 0.1–0.3 GB |
| 對照免費額度(約 360 MB/日) | 超出約 3 倍 | 落在額度內 |
| 改動範圍 | — | 多 1 個寫入、換 1 個監聽、加 1 個節流計時器;不搬資料 |
其他四條路
| 做法 | 怎麼做 | 放棄什麼 | 估計月費 |
|---|---|---|---|
| A · 全面拆資料留在 Firebase | 每位學生一個節點、排行榜一個節點,學生只監聽自己的和排行榜。接近他正在試行的 split-storage,但要改整個資料模型和既有資料。 | 幾乎不用放棄什麼 | NT$0–300 |
| B · Firestore 小文件按次計費 | 每人一份文件、排行榜一份,onSnapshot 只掛這兩個。每次變動算 30 次讀取,跟大小無關;估每天約 60 萬次,超過免費 5 萬次。 | 要重寫同步層 | 約 NT$200–350 |
| C · Cloudflare Durable Objects一班一個房間 | 每班一個 DO,WebSocket 加 hibernation 推差異;狀態存 DO 的 SQLite,備份進 D1,寵物圖當靜態檔。流出流量不收費。免費方案就能跑,但超過額度會直接報錯,上課中斷比多付錢糟;建議付每月 US$5 換掉硬上限。 | 重寫後端;登入改房間代碼加簽章 token | NT$0 或 US$5 起 |
| D · 不做即時 | 學生艙開啟時讀一次自己的資料,不常駐監聽;排行榜由老師在教室投影。 | 學生裝置上的即時跳分 | NT$0 |
只能做一件事就做 A1。規模再大一個數量級,或想讓費用完全不隨人數成長,再考慮 C。
05 · 鎚子與釘子
換到 Cloudflare 不是重點,別只有一把鎚子才是
這份報告前面算了 Cloudflare 的帳,很容易讀成「Firebase 不好,搬去 Cloudflare 就對了」。這個結論是錯的,而且錯的方式跟作者當初一樣。
作者的技能裡寫死了一條預設路線:點子進來,Firebase 當後端,Cloudflare 送前端。所以不管加什麼功能,答案都是 Firebase。遊戲艙需要即時同步,Firebase 有 Realtime Database,就用它;格式是現成的壓縮塊,就沿用。每一步都是「手上有什麼就用什麼」,沒有一步是「這個問題的計費單位是什麼」。如果他當初的鎚子是 Cloudflare,一樣會有另一種釘子:Durable Object 忘了 hibernation,掛一整天的房間照樣能燒掉上百美元。
所以綁定本身不是問題。Firebase 的 SDK 綁得很深,Durable Objects 的程式模型也綁得很深,兩邊換過去都是重寫。該省思的是另一件事:
- 選型的單位是「功能」,不是「專案」。備份和即時廣播是兩個功能,計費單位不同,可以用同一家,但不該用同一個格式。
- 每個新功能上線前,各算一次「使用者多十倍,這一項多幾倍」。線性成長的項目要先想誰付錢,再決定要不要做。
- 把會隨人數成長的部分留在可以換的位置。作者的本機優先設計其實很好:資料在瀏覽器裡,雲端只是同步層。同步層如果是薄的,換資料庫就只是換一個模組;他現在換不動,是因為壓縮塊格式、Cloud Functions、匿名登入三件事綁在一起。
回到計分板:每加一個功能,就有一次選型。選型沒有扣分機制,最後扣的就是帳單。
06 · 變現
先把成本降到零,再談收入
作者說過,訂閱和贊助的收入連一週伺服器費都付不起。一個月 NT$2,854 靠小額贊助本來就很難打平;先把成本壓到每月 US$5 以下,用愛發電才撐得住,之後的收入才是收入。
| 方式 | 怎麼做 | 門檻與風險 |
|---|---|---|
| 1 · 老師端 freemium | 本機版永久免費;真正花雲端錢的學生遊戲艙改成付費或限班級數。例如每年 NT$990,300 位老師付費約 NT$30 萬/年。 | 付費功能得是老師離不開的那一塊;要有個人可申請的金流。 |
| 2 · 學校與縣市授權 | 縣市用「推動中小學數位學習精進方案」經費統一採購教學軟體;屏東縣 114 年度清單就有 PaGamO、加分吧、LoiLoNote。也可申請上架教育部「校園數位內容與教學軟體」選購平台。 | 要成立公司或工作室,並符合未成年學生的個資與資安要求。門檻最高,金額也最大。 |
| 3 · 研習與課程 | 作者已有「FunFun.AI」品牌和公開的 Codex 技能,適合開「老師用 AI 做工具」的研習。這張帳單本身就是教材。 | 收入跟著作者的時間走,但最快能開始。 |
| 4 · 出版社或平台合作 | 授權給教科書出版社或既有班級經營平台。 | Classcraft 在 2023 年被 HMH 收購,2024 年 6 月原版停止服務。合約要寫清楚原產品是否繼續維運。 |
| 5 · 家長端加值 | 參考 ClassDojo:老師學生免費,家長訂閱 ClassDojo Plus(每月 US$4.99),學校另買授權。 | 台灣家長付費加上轉蛋機制容易引發爭議,排最後。 |
不建議的方向
不要讓學生花錢買轉蛋、寵物或道具,也不要放廣告。使用者是小學生,學校和家長的反彈會大於收入;一旦被教育局列為不宜使用,免費用戶也會跟著流失。
07 · 給用 AI 寫工具的人
把扣分機制裝進流程
下次讓 AI 加「即時同步」「多人連線」之前,要求它先回答三個問題,答不出來就不准動手:
- 計費單位是什麼?按次、按位元組、按人頭,還是按秒。同一個技巧換了單位,結果可能相反。
- 使用者做一個動作,幾台裝置各下載多少?扇出數乘每次資料量,就是帳單成長的速度。
- 使用者變成 100 倍,帳單變幾倍?線性成長就要先想誰付錢。
自己寫 agent 技能的人,可以把這三題寫成一道關卡:加入任何即時或多人功能前,agent 必須寫出計費單位、估 10 倍和 100 倍時的月費,再讓使用者決定。這就是作者的加分機制少掉的那一半:功能加一分,選型答不出來就扣一分。
附 · 證據與限制
哪些是看到的,哪些是推的
- 直接看到的:帳單與用量截圖;GitHub 上三代程式碼;線上前端裡的 RTDB 路徑、整班壓縮塊的寫法、內容指紋判斷、寫入冷卻、18 個 Cloud Functions 名稱,以及
rtdb-cost-p2、split-storage的版本標記。 - 推論:整塊大小(文中用 40 KB 示意)、費用在 RTDB、Cloud Functions、Auth 之間怎麼分(截圖下半部被截掉)、匿名登入是否已按人頭計費。
- 沒做的:沒有登入、沒有讀寫任何雲端資料,也沒有測量真實流量。
- GitHub · CLASSROOMHUB(簡約版原始碼)
- GitHub · class-powerhouse-2.0(早期 Firestore 版)
- GitHub · build-firebase-cloudflare-app(Codex 技能)
- 翻轉教育 · FunClass 教師系統使用說明
- Firebase · Realtime Database 計費說明
- Cloudflare · Durable Objects 定價
- Cloudflare · Workers 定價
- 屏東縣 · 114 年數位學習精進方案軟體研習計畫
- 校園數位內容與教學軟體選購平台
- HMH · HMH Classcraft 發布(原版 2024-06-30 停止)
- Vator · How does ClassDojo make money