
系列:奇幻塔防開發實錄:用 Claude 打造一款有靈魂的塔防遊戲
今日工具:Claude Cowork(彙整 30 份 day-log)/ Claude Code(最後一次部署)
今日進度:《薪火要塞》正式版上線;Day 1 的六個承諾逐項驗收;30 天數據攤開
Day 28 把部署雷排成表、算完那張 US$1.35 的月費單,剩下的事只有一件:把最後一版推上去,然後誠實地對帳。今天不寫新功能——deploy-api 第 21 次、deploy-web 第 24 次跑完,Day 28 補的部署後煙霧測試第一次在 CI 裡用真實 token 打了 /api/v1/saves/{id}/story,綠了。理由很簡單:API Gateway 的 payload 1.0、CloudFront 的 /api/*,這兩件事在我這台筆電上一件都驗不到。
這篇要做三件事:帶你走一遍 demo、把 30 天蓋出來的東西畫成一張圖、然後回到 Day 1 那六個「做不到我會誠實列出」的承諾。數據全部來自 Day 1 用 Cowork 建的 day-log。
網址是 CloudFront 的網域(連結在 README),手機橫向開啟即可。流程:
POST /api/v1/saves 拿到存檔與 token(Day 27)。n_final_gate,route 節點依 flags 分流(Day 10、21 坑 #4)→ 薪火王城 boss 依路線變化 → 三個結局之一。坦白交代第 4–6 關的狀態:關卡資料、波次、boss 變體全部就位、可玩、通關率跑過(棄守修道院 79.5%、黑岩隘口 91.0%、薪火王城 73.5%);但劇情圖 60 個節點只定稿 52 個,第 4–6 關還有 8 個節點是 Day 7 就承認的草稿。
從 Day 16 上線至今 13 天,戰鬥稽核 item 累計 58 場、7 位玩家(含我;Day 23 時是 23 場、3 人),三個結局各至少有一筆真人存檔——這是承諾二的證據。

圖上只有 S3 帶尾巴:bucket = "${var.name}-web-${var.aws_account_id}"。bucket 名稱全球唯一,不像其他資源「同帳號同區不撞就好」,那截帳號 ID 不是裝飾。
每個箭頭都對應一篇文章:靜態站與 /api/* 同源(Day 22)、API Gateway REST API、ECR 容器映像與 Lambda(Day 16)、DynamoDB 單表(Day 13)、告警(Day 24)、WAF 與 Authorization 轉發(Day 27、28 雷 #1)、OIDC 免金鑰部署(Day 16)。整張圖 Terraform 六個 module、51 個資源可 plan,46 個真的 apply 上去過,月費 US$1.35(Day 28)。
值得說一次的是這張圖裡沒有的東西:沒有 VPC、沒有子網、沒有 NAT、沒有安全群組、沒有一個按小時計費的資源。Day 9 那條分界線(「會留下資料的東西 → 隨時可重建的東西 → 會叫的東西」)到今天還撐得住——六個 module 的邊界一次都沒重畫。

| # | Day 1 的承諾 | 結果 | 證據 |
|---|---|---|---|
| 1 | 瀏覽器(含手機)可玩,至少 3 關完整 | ✅ | 前三關對白定稿、Redmi Note 8 第 5 波 58.9 FPS(Day 26) |
| 2 | 三條路線、三種結局,可從存檔查證 | ✅ | routes_test.go 三路線全綠(Day 25);GSI1 三個結局節點各有真人存檔 |
| 3 | Go API 在 AWS,Terraform 全程可重建 | ⚠️ | 從零 apply 46 個、玩到結局、再 destroy 掃到淨空;沒做的是 destroy 後再 apply 的回程 |
| 4 | CI/CD 一鍵部署、告警實際觸發過 | ✅ | api 21 次、web 24 次自動部署;告警 2 次演練 + 1 次真實(Day 24、26) |
| 5 | worktree 對照數據 | ✅ | 四筆:−38%、−44%、+13%、−41%(Day 12、14、26) |
| 6 | 可複製的 /ultracode(我自訂的 slash command,不是官方功能) |
✅ | 兩次實戰 41 與 24 分鐘(Day 20、26),指令與 subagent 全文公開 |
第 2 項的「可查證」是字面意義的——三個結局各下一次 GSI1 查詢,數字對得上劇情稽核 item 裡的選項序列:
# dawn 換成 ash / kindling 再跑兩次
aws dynamodb query --table-name emberhold-prod --index-name GSI1 \
--key-condition-expression 'GSI1PK = :n' \
--expression-attribute-values '{":n":{"S":"NODE#n_ending_dawn"}}' \
--select COUNT
從一句 SQL 變成三次 Query,是單表設計的代價:關聯式資料庫可以事後想出新的 GROUP BY,DynamoDB 得先想好存取模式再建 GSI(Day 13)。
第 3 項打 ⚠️ 是因為「可重建」我只證明了單程:51 個資源 plan 乾淨,46 個從零 apply 起來(cicd 那五個排除),跑完一輪真實存檔,最後 terraform destroy 全數拆掉、掃描確認區域淨空。缺的是回程——destroy 之後再 apply 一次、確認它長得回來。表上 deletion_protection_enabled = true 要先手動關掉,這趟往返我沒有在最後三天再跑,所以它留在下面的未完成清單裡。
量測方式沿用 Day 7:專注分鐘來自 day-log 的時間表;session 數含 subagent 與 Day 7 的 6 個實驗 session;token 是每個 session 結束時 /cost 的輸出 token。下表每一週都含當週的週記日,所以會比週記當天的數字大一些。
| 週 | 專注分鐘 | Claude session | commit | 部署(api / web / infra) |
|---|---|---|---|---|
| 1(Day 1–7) | 950 | 18 | 31 | 0 |
| 2(Day 8–14) | 870 | 16 | 58 | 0 |
| 3(Day 15–21) | 1,210 | 16 | 67 | 9 / 14 / 1 |
| 4(Day 22–28) | 1,105 | 14 | 49 | 11 / 9 / 6 |
| 終章(Day 29–30) | 230 | 2 | 9 | 1 / 1 / 0 |
| 合計 | 4,365(≈ 72.8 小時) | 66 | 214 | 21 / 24 / 7 |
表格有兩個形狀值得看。第一,專注分鐘與 commit 數不成正比:第二週 870 分鐘產出 58 個 commit,第四週 1,105 分鐘只有 49 個——第四週多出來的時間花在排雷(260 分鐘)與演練,那些工作不產生 commit,但產生 runbook。第二,session 數逐週遞減而產出沒減少:第一週 18 個裡有 5 個是「反問型」長對話,第四週 14 個裡一半是十分鐘的短問答。session 變短,是 CLAUDE.md 累積四週規則的結果——Claude 需要被解釋的事越來越少。
其他總數:輸出 token 約 162 萬;worktree 4 次(序列估 365 分鐘 → 實測 240 分鐘,−34%);/ultracode 2 次;測試 Go 62、vitest 20、Playwright 9;記錄在案的 bug 與雷 31 個(整合坑 6、部署雷 12、/ultracode 處理 2、其他 11);平均每天 145 分鐘。
哪裡加速、哪裡沒有,用數據說:
| Claude 明顯加速 | 數據 | 沒加速、甚至變慢 | 數據 |
|---|---|---|---|
| 設計稿→元件(附意圖說明) | 91% 可直接用、8.5 分鐘(Day 7) | 實機測試 | 210 分鐘,無工具可省(Day 19) |
| worktree 平行獨立任務 | −38%~−44%(Day 12–14、26) | worktree 平行糾纏任務 | +13%、3 次語意衝突(Day 14) |
| 骨架生成(Plan mode) | 事前改 2 個決定 vs 事後改 14 檔(Day 8) | 契約決策 | 六個整合坑有四個是契約(Day 21) |
| 排雷:把查文件壓成一個問題 | 平均 29 分鐘/雷(Day 28) | 數值與設計決策 | /sim(同樣是我自訂的指令)只給三條建議,決定權在人(Day 23) |
最後一份工作交給 Cowork:
Prompt(給 Claude Cowork,指定
~/emberhold-notes/)
「讀daylog/day01.md到day30.md。彙整成同一層的retrospective.md:一、每週專注分鐘、session、commit 的表;二、所有『踩雷』欄位依『契約/預設值/程式邏輯/其他』分類計數;三、每天『明日計畫』與隔天『實際做了什麼』不一致的日子列出來。只要事實,不要評論。」
報告刻意留在 ~/emberhold-notes/、不進 repo:docs/ 只放讀 code 的人需要的東西,寫作素材混進去,第一個受害的是 CLAUDE.md 的 context 預算。產出 4 分鐘。第二項的分類結果:契約 11、預設值 9、程式邏輯 7、其他 4——程式邏輯錯誤只占兩成,今天才看到全貌。第三項抓出 6 天計畫與實際不符,其中 4 天在第三週,跟 Day 1 標的高風險區完全吻合。
repo 最終長這樣(比 Day 6 的骨架只多了每天在長的 PITFALLS.md 與 docs/ 兩個子目錄):
project/
├── CLAUDE.md Makefile README.md PITFALLS.md
├── .claude/ settings.json、commands/{ultracode,review,sim}.md、agents/、hooks/
├── frontend/ Vue 3 + Canvas,vitest 20、Playwright 9
├── backend/ Go Clean Architecture,go test 62,cmd/{api,sim,storylint}
├── infra/terraform/ envs/prod + modules/{foundation,compute,cdn,cicd,monitoring,waf}
├── data/ towers / enemies / levels×6 / story(v0.2)
├── docs/ gdd、api、architecture、balance、qa-matrix、adr/×6、runbook/
├── scripts/ contract-test、lambda-image、tf-plan-offline、e2e-fixture(.sh)
└── .github/workflows/ ci / deploy-api / deploy-web / infra
docs/ 底下只有 adr/ 與 runbook/ 兩個目錄,其餘都是單檔:sim-*.csv 該進 artifact,不是進 git。
未完成清單,明天不會再提第二次:兵營塔與士兵阻擋(Day 3 就割捨)、第 4–6 關 8 個節點對白定稿、destroy 之後再 apply 的回程演練、重播式反作弊(Day 12 留的門)、lambda-duration-p99 的 800 ms 閾值要等真實流量校正(Day 24)、合成探測(Day 24 那個盲點:「完全沒有被呼叫」是沒有指標的,六個告警都不會叫)、排行榜、SNS 加 Slack 訂閱。
上線這天最大的感受不是「做完了」,是「對得起 Day 1 的清單」:六項裡五項有證據、一項誠實打折。30 天 72.8 小時、66 個 session、214 個 commit 蓋出一個能玩、能查、能監控、每月一塊多美金的東西——但 Cowork 那份報告提醒我,31 個雷裡只有 7 個是程式寫錯,其餘都是「兩邊各自正確」與「預設值」。Claude 寫程式的部分幾乎沒讓我失望,讓我失望的都是我沒問的問題。這句話明天展開。
deploy-api.yml
~/emberhold-notes/retrospective.md(Cowork 彙整 30 份 day-log,不進 repo)、docs/architecture.md(本篇兩張圖)Day 30:【終章】30 天後的我——Claude 全流程開發心得,與這場鐵人賽留給我的東西。