🌾 農場遊戲交接手冊 v1.0

D1 三張表 · Worker 四個 API · 懶結算 · GitHub Actions
2026-10-28 · 開心農場正式上線

一、系統總覽

項目值
前端網址https://farm.ahpal.com
Worker URLhttps://ahpal-farm-api.praystone.workers.dev
Pages 專案ahpal-farm
D1 資料庫ahpal-farm-db(database_id 見 wrangler.toml)
GitHub repopraystone/ahpal-farm
部署方式GitHub Actions(push 即部署)
子網域farm.ahpal.com(CNAME 橘雲)
ID 不寫死在手冊:database_id 見 worker/wrangler.toml,account_id 見 GitHub Secret CLOUDFLARE_ACCOUNT_ID。手冊會上網站,公開,所以不寫死。

二、D1 三張表

#表名用途
1crops農作物靜態資料(id, name, grow_seconds, icon, sell_price)
2farms每塊田(id, nickname, crop_id, planted_at, harvested, stolen_by)
3farm_logs播種/收成/被偷紀錄(id, nickname, action, crop_id, created_at)

5 種基礎農作物:🥕蘿蔔 60 秒 / 🍅番茄 300 秒 / 🌽玉米 1800 秒 / 🍓草莓 7200 秒 / 🍉西瓜 28800 秒

三、Worker 四個 API

#端點方法用途
1/api/cropsGET農作物清單
2/api/plantPOST種植(body: nickname, cropId)
3/api/farmGET查看自己的田(query: nickname)
4/api/harvestPOST收成(body: id, nickname)
參數名注意:/api/harvest 讀的是 body.id,不是 body.farmId。前端若送 farmId,會回「找不到這塊田」。

四、懶結算(核心設計)

農場跟寵物最大的差異:離線也在長。種下去,8 小時後回來就能收。

實作方式:不要用排程器。種下去時 D1 存 planted_at,玩家來看時 Worker 算 now - planted_at,超過 grow_seconds 就回「已成熟」,收成時才寫 D1。

零成本、離線也在長:時間是算出來的,不是跑出來的。D1 只在播種/收成時寫入,不會爆寫入額度。

五、部署入口(照 SOP 一章,不能混用)

目標指令觸發
前端 Pagesgit push → GitHub Actions自動
Worker 後端wrangler deploy永遠手動
D1 資料庫wrangler d1 execute --remote永遠手動
今天踩過的坑(完整版見 SOP 第 31 節):
  1. wrangler pages deploy 沒有 --account-id 參數
  2. Pages 專案不讀 wrangler.toml 的 account_id,只認環境變數 CLOUDFLARE_ACCOUNT_ID
  3. Wrangler 4 要求 Node.js ≥ 22
  4. GitHub Secret 沒設,${{ secrets.CLOUDFLARE_ACCOUNT_ID }} 展開成空字串
  5. onclick="fn(' + JSON.stringify(id) + ')" 雙引號打架,SyntaxError: Unexpected end of input
  6. CSP 少 static.cloudflareinsights.com

六、MVP 現況(誠實說明)

功能狀態
種植✅ 已上線
查看✅ 已上線
收成✅ 已上線(回 sell_price)
金幣機制⚠️ 還沒做(收成回 sell_price 但沒寫進玩家表)
偷菜❌ 第二期(原定第二期)
結構正常 ≠ 內容正確:MVP 能種、能看、能收,但金幣跟偷菜還沒做。下一個 AI 不要以為「能收成就全好了」。

七、給下一個 AI 的話

🦕 2009 年,你在偷誰的菜?

2009 年,Facebook 開心農場。你半夜設鬧鐘起來,就為了偷同學那顆快熟的番茄。那時候,我們都還年輕。放學衝回家,打開電腦,偷菜、種菜、被偷,一個都不能少。

17 年後,開心農場回來了。不是 Facebook,是 AHPAL。

你的菜,還在長。你的青春,還在等你。