Vibe Coding — Stage 3 · 造系統
M3-3

Vibe Coding 實戰課 — Stage 3 · 造系統

問題集大成
spec.md 架構思維

所有的坑走過一遍 — 然後用一份文件避開它們

M3-3 3 小時 6 輪循環 諮詢預約系統

按 → 或空白鍵開始

六輪循環,逐層遞進

Round 1
自由發揮預約系統
Round 2
坑的總整理
Round 3
一起寫 spec.md
Round 4
用 spec.md 重做
Round 5
前後對比
Round 6
spec.md 模板

這堂課的節奏
先自由發揮注意事項 → 分類所有問題 → 引出 spec.md → 用 spec.md 重做 → 體感差距
每一輪新增一層理解,前面遇到的問題都是教材

今天的題目:諮詢時段預約系統

這不是練習題 — 是講師自己真的要用的系統
做得好的版本,會直接上線

預約者

選時段、填資料
收到確認信

講師

設定可預約時段
查看預約清單

系統

防衝突、防過期
自動寄通知信

ROUND 1 · 0:00–0:25

不給規格
直接做

用一句話指令,看 AI 自由發揮的結果

操作指令

你的指令
做一個諮詢預約系統
讓別人可以選時段預約
我能看到預約清單
操作條件

不給架構指引、不指定技術選型、不定義資料結構
用最自然的方式描述需求,看會發生什麼事

25 min
操作時間

觀察:5 個人的架構完全不同

同樣的需求、同樣的工具、同樣的時間

5
種不同架構
0
個完整可用
6+
類共同問題

AI 沒有收到規格 → 每次自由發揮 → 每個人拿到完全不同的東西

自由發揮踩到的坑(上)

1
資料存前端 → 重新整理消失

M2-2 踩過的坑又來了 — 沒有指定儲存方式,AI 預設用 localStorage

2
同一個時段被多人預約

沒有時段衝突防護 — 兩個人同時點同一個時段,都預約成功

3
已過期的時段還能選

沒有時間驗證 — 昨天的時段今天還顯示「可預約」

自由發揮踩到的坑(下)

4
預約後沒有確認通知

使用者不確定預約是否成功 — 只有畫面閃一下

5
前後端混在一起

改一個功能壞全部 — 資料邏輯和畫面邏輯纏在一起

6
AI 每次給不同架構

加功能時前後矛盾 — 第一次用物件,第二次用陣列,第三次又改回來

Round 1 小結

沒有藍圖 → AI 每次亂蓋 → 改到後來改不動
一句話需求
AI 自由發揮
每次不同架構
越改越壞

問題不在 AI 的能力 — 而是你沒有給它規格
接下來把所有坑攤開,找出共同根因

ROUND 2 · 0:25–0:45

三個 Stage
的坑攤開

不只是預約系統 — 是整個課程遇到的所有問題

六大類問題,一個共同根因

類別典型問題根本原因
資料消失 / 不一致 / 時段衝突沒定義資料結構
安全Key 外洩 / 重複提交沒定義安全規則
架構前後端混亂 / 改壞沒定義分工
AI每次不同方案 / 衝突沒給明確規格
範圍越加越多 / 失控沒定義功能邊界
驗證過期時段還能選 / 沒通知沒定義業務規則

資料類:消失、不一致、衝突

沒定義 → 發生什麼
  • 資料存 localStorage,重整消失
  • 兩個人同時預約同一時段
  • 前端顯示的時段跟後端不同步
有定義 → 應該怎樣
  • 指定 Google Sheet 作為唯一資料源
  • 後端鎖定時段,寫入前再檢查一次
  • 前端每次從後端拉最新狀態

安全類:Key 外洩、重複提交

沒定義 → 發生什麼
  • API Key 寫在前端 JavaScript 裡
  • 按鈕連點三次 → 三筆重複預約
  • 任何人都能打 admin 端點
有定義 → 應該怎樣
  • Key 只放在 GAS 後端 PropertiesService
  • 提交後停用按鈕 + 後端去重
  • admin 端點加 Key 驗證

架構 + AI:混亂、矛盾、改壞

沒定義 → 發生什麼
  • 前後端邏輯混在同一個檔案
  • AI 第一次用物件、第二次用陣列
  • 加功能時跟原有邏輯衝突
有定義 → 應該怎樣
  • 前端只管顯示、後端只管邏輯
  • API 端點和資料格式寫死在規格裡
  • 加功能前先更新 spec,再讓 AI 照做

範圍 + 驗證:失控、無效

沒定義 → 發生什麼
  • 「順便加個評分功能」→ 系統越長越大
  • 過期時段還能選
  • 預約成功但沒有任何確認
有定義 → 應該怎樣
  • spec.md 列出功能邊界,超出範圍不做
  • 後端驗證時段是否在未來 + 是否可用
  • 預約後觸發 Email 通知雙方

六類問題,一個根因

開始前沒有定義清楚
沒有規格
AI 自行決定
每次不同
系統壞掉

spec.md = 系統藍圖

spec.md = 你跟 AI 的溝通契約
寫清楚了,AI 照著做
沒寫清楚,AI 自己決定

不是文件

不是寫給人看的文件
是寫給 AI 執行的規格

不是選配

沒有 spec.md 的系統
等於沒有藍圖的建築

Round 2 小結

問題不在 AI,在你的規格

資料、安全、架構、AI、範圍、驗證
六類問題的解法都是同一個:
開始前寫清楚

ROUND 3 · 0:45–1:10

一起寫
spec.md

用 Claude Code 輔助,為預約系統寫規格書

spec.md 的五大區塊

1
功能需求

系統要做什麼 — 列出所有功能點

2
技術選型

前端、後端、儲存、通知 — 每一層用什麼

3
資料結構

哪些 Sheet、哪些欄位、狀態怎麼定義

4
API 端點

幾支 API、輸入什麼、回傳什麼

5
安全規則

誰能做什麼、怎麼驗證、Key 放哪裡

區塊一:功能需求

spec.md — 功能需求
# 諮詢預約系統 spec.md

## 功能需求
- 顯示可預約時段(排除已過期、已被預約的)
- 預約(填姓名 + Email + 選時段)
- 預約後寄確認信給預約者
- 講師收到通知信(含預約者資訊)
- 講師可查看所有預約清單
為什麼要列這麼細

每一條就是一個驗收標準
沒列到的,AI 不會主動做

區塊二:技術選型

spec.md — 技術選型
## 技術選型
- 前端:HTML / CSS / JS(GitHub Pages)
- 後端:GAS(API Proxy + 資料存取 + 寄信)
- 儲存:Google Sheet
- 通知:GmailApp
關鍵決策

技術選型必須由人類決定,不是 AI
AI 會根據你的選型建立一致的架構
不指定 → AI 每次選不同的,後續改不動

區塊三:資料結構

spec.md — 資料結構
## 資料結構
- Sheet "時段"
  日期 / 開始時間 / 結束時間 / 狀態(可預約/已預約/已過期)

- Sheet "預約"
  時段ID / 姓名 / Email / 預約時間 / 確認信狀態
對應 R1 的坑

資料消失 → 因為沒指定儲存位置
時段衝突 → 因為沒有「狀態」欄位
寫清楚資料結構 = 一次解決兩個問題

區塊四:API 端點

spec.md — API 端點
## API 端點
- GET /slots
  → 取得可預約時段(自動排除過期 + 已預約)

- POST /book
  → 預約(帶時段ID + 姓名 + Email)
  → 寫入 Sheet + 寄確認信

- GET /admin
  → 講師查看預約清單
  → 後端檢查 admin session / token

不要把 key 放在 URL
secret 放 GAS PropertiesService
前端只送一次性或表單驗證資料

區塊五:安全規則

spec.md — 安全規則
## 安全規則
- 後端驗證時段是否仍可預約(不信任前端)
- 同一 Email 同一時段不能重複預約
- admin 端點需要 Key 驗證
- 前端不存任何 Key
這段最容易被忽略

安全規則不寫 → AI 不會主動幫你想
「不信任前端」這四個字,值整個系統的安全

完整的 spec.md

諮詢預約系統 spec.md(完整版)
# 諮詢預約系統 spec.md

## 功能需求
- 顯示可預約時段(排除已過期、已被預約的)
- 預約(填姓名 + Email + 選時段)
- 預約後寄確認信給預約者
- 講師收到通知信(含預約者資訊)
- 講師可查看所有預約清單

## 技術選型
- 前端:HTML / CSS / JS(GitHub Pages)
- 後端:GAS(API Proxy + 資料存取 + 寄信)
- 儲存:Google Sheet
- 通知:GmailApp

## 資料結構
- Sheet "時段"
  日期 / 開始時間 / 結束時間 / 狀態

- Sheet "預約"
  時段ID / 姓名 / Email / 預約時間 / 確認信狀態

## API 端點
- GET /slots → 取得可預約時段
- POST /book → 預約 + 寫入 + 寄信
- GET /admin → 講師查看清單,後端檢查 admin session / token

## 安全規則
- 後端驗證時段是否仍可預約
- 同一 Email 同一時段不能重複預約
- admin 端點檢查 admin session / token
- 不要把 key 放在 URL
- secret 放 GAS PropertiesService
- 前端只送一次性或表單驗證資料

寫 spec.md 約 15 分鐘

15
分鐘寫規格
品質天壤之別
後續 AI 產出差距
投資報酬率

15 分鐘的規格 → 省下 3 小時的除錯和重做
這就是「先規劃再動手」的體感

spec.md 也有坑

spec.md 太簡略 → AI 還是自己補
關鍵決策不能讓 AI 決定
太簡略

## 功能
預約系統

AI 只知道「預約」兩個字
其餘全部自行決定

剛好的粒度

## 功能需求
- 顯示可預約時段
- 排除已過期+已預約
- 預約後寄確認信

每一條都可驗收
AI 不需要猜

spec.md 不是文件,是契約

你跟 AI 之間的溝通協議

寫在 spec.md 裡的 → AI 照著做
沒寫在 spec.md 裡的 → AI 自己決定
你不想讓 AI 決定的事,就寫進去

ROUND 4 · 1:10–1:35

用 spec.md
重做一次

同一個系統、同樣的時間 — 感受差距

操作指令

這次的指令
清空專案 → spec.md 放進去

「按 spec.md 建這個預約系統」
操作條件

把 R1 的成品全部清掉
只放 spec.md 進去,一句話啟動
25 分鐘,跟 R1 完全相同的時間

25 min
與 R1 相同時間

觀察:AI 的行為完全不同

1
AI 問的問題少了

規格清楚 → 不需要反覆確認

2
時段衝突有防了

spec 有寫 → AI 照做

3
確認信有寄了

spec 有寫 → AI 照做

4
過期時段自動隱藏了

spec 有寫 → AI 照做

規律浮現

spec 有寫 → AI 照做
spec 沒寫 → AI 自己決定
spec.md
AI 照做
一致的架構
可擴展

升級測試:加上取消預約功能

追加指令
在現有系統上加上「取消預約」功能
預約者收到確認信後,信裡有取消連結
點取消 → 時段恢復為可預約
R1 加功能

架構亂 → 不知道改哪裡
改了一個 → 壞了三個
AI 重新生一版 → 跟原本矛盾

R4 加功能

API 結構清楚 → 加一支端點
資料結構清楚 → 加一個狀態
AI 照架構加 → 不壞原有功能

彩蛋

做得好的版本
講師真的會拿去上線用
這不是練習題 — 這是真的要用的系統

有 spec.md 的版本 → 功能完整、架構乾淨、可擴展
講師下課後直接部署,省下自己開發的時間

R1 vs R4:時間相同,品質天壤之別

R1
25 分鐘亂做
6 個坑、無法加功能
R4
25 分鐘有藍圖
完整可用、可擴展

差別不在時間、不在工具、不在 AI 的能力
差別在你有沒有先寫規格

Round 4 小結

15 分鐘的規格 → 省下 3 小時的除錯

spec.md 不是增加工作量
是把「後面會踩到的坑」提前在前面解決

ROUND 5 · 1:35–1:50

六維度
前後對比

R1 和 R4 並排 — 用數據看差距

R1 vs R4:六維度評分

R1(自由發揮)
  • 功能完整度:部分缺失
  • 時段衝突防護:無
  • 通知機制:無
  • 可擴展性:加功能就壞
  • 程式碼品質:前後端混雜
  • AI 協作效率:反覆修正
R4(有 spec.md)
  • 功能完整度:全部實作
  • 時段衝突防護:後端驗證
  • 通知機制:雙向 Email
  • 可擴展性:加功能不壞
  • 程式碼品質:職責分離
  • AI 協作效率:一次到位

功能完整度 + 時段衝突防護

功能完整度
R1 35%
R4 95%
衝突防護
0
R4 90%

R1 的 35% 功能裡,還有一半是壞的
R4 的 95% 功能,全部通過手動測試

通知機制 + 可擴展性

通知機制
0
R4 85%
可擴展性
R1 15%
R4 88%

R4 加「取消預約」功能只花 3 分鐘
R1 試了 15 分鐘,加完反而壞了原有功能

程式碼品質 + AI 協作效率

程式碼品質
R1 20%
R4 82%
AI 協作效率
R1 25%
R4 90%
AI 協作效率的意思

R1:你說一句,AI 問三句,做出來不對,再改
R4:你給 spec,AI 直接做,一次到位

真實世界的規格文件

PRD

Product Requirements Document
產品經理寫的功能需求書
定義「做什麼」

RFC

Request for Comments
工程師寫的技術提案
定義「怎麼做」

spec.md

我們的簡化版
PRD + RFC 的精華
一個檔案搞定

spec.md 是工程界數十年經驗的簡化版
不需要學 PRD 的完整格式,掌握核心就夠

M3-3 注意事項總表

#常見問題學到什麼
1同時段被多人預約業務邏輯驗證(後端防衝突)
2過期時段還能選時間驗證要在後端做
3AI 每次給不同架構沒有藍圖 = AI 亂蓋
4加功能改壞原有功能API 規格 + 可擴展性
5spec.md 太簡略關鍵決策要人類做

Round 5 小結

差距不是靠更厲害的 AI 拉開的
是靠 15 分鐘的規格書拉開的

六個維度全面碾壓 — 因為規格清楚
AI 的能力一直都在,差的是你給它的指引

ROUND 6 · 1:50–2:00

spec.md 模板
三層定位

帶走模板 + 理解三份文件的分工

spec.md 通用模板(上)

模板上半部 — 功能 + 技術 + 資料
# [專案名稱] spec.md

## 功能需求
- [ ] 功能 1:描述 + 驗收條件
- [ ] 功能 2:描述 + 驗收條件
- [ ] 功能 3:描述 + 驗收條件

## 技術選型
- 前端:(框架 / 部署位置)
- 後端:(語言 / 服務)
- 儲存:(資料庫 / Sheet / JSON)
- 通知:(Email / TG / Line)

## 資料結構
- 表/集合名稱
  欄位 1 / 欄位 2 / 欄位 3 / 狀態

spec.md 通用模板(下)

模板下半部 — API + 安全 + 範圍
## API 端點
- GET /endpoint1 → 說明
- POST /endpoint2 → 說明 + 輸入 + 回傳

## 安全規則
- 驗證邏輯(後端不信任前端)
- 權限控制(誰能做什麼)
- Key 管理(放哪裡、不放哪裡)

## 範圍定義
- 第一版做:功能 A / B / C
- 第一版不做:功能 D / E
- 未來考慮:功能 F
範圍定義是新增的

明確寫出「不做什麼」
防止 AI 自行加功能 → 系統膨脹失控

練習:寫自己的 spec.md

操作

用模板,為你下一個想做的系統寫 spec.md 大綱
不用寫完 — 先把五大區塊的標題和重點列出來

10
分鐘
5
大區塊

三層定位:三份文件各管什麼

CLAUDE.md

AI 的個性和偏好
跨專案不變
「你是什麼樣的 AI」

spec.md

這個專案的規格
每個專案獨立
「這次要做什麼」

Skills

AI 的技能方法
跨專案共用
「用什麼方法做」

CLAUDE.md — AI 的個性設定

CLAUDE.md 範例
# 開發偏好
- 使用繁體中文回應
- 程式碼加註解
- 優先使用 GAS + Google Sheet
- 錯誤訊息要對使用者友善
- 不要用 emoji

放在 ~/.claude/CLAUDE.md
所有專案共用 — AI 在任何專案都會遵守這些偏好

spec.md — 專案級規格

放置位置
你的專案/
├── spec.md          ← 這個專案的規格
├── index.html       ← 前端
├── gas/             ← 後端
│   └── Code.gs
└── README.md

spec.md 放在專案根目錄
AI 開始工作前會先讀這份文件
後續所有決策都以 spec.md 為準

Skills — AI 的可重用技能

Skills 範例
# GAS API 部署 Skill
1. 建立 GAS 專案
2. 寫 doGet / doPost 處理函式
3. 部署為 Web App(設為所有人可存取)
4. 測試 API 端點回應
5. 把 URL 貼回前端設定

Skills 定義「怎麼做」— 標準化的工作流程
寫一次,所有專案都能用
不需要每次重新教 AI 同樣的步驟

三者互補,缺一不可

CLAUDE.md
定性格
+
spec.md
定規格
+
Skills
定方法
比喻

CLAUDE.md = 員工的個性(他是什麼樣的人)
spec.md = 這次的工作單(今天要做什麼)
Skills = 公司的 SOP(用什麼方法做)

帶走清單

本堂定位 SDD 驅動、TDD 驅動

不只學了什麼,是想法怎麼變了
從「請 AI 幫我做事」→ 設計 AI 能執行的系統

從「先叫 AI 做看看」
模糊會放大混亂
從「坑是 AI 不夠強」
坑多半來自未定義
從「需求在我腦中」
規格是共享邊界
從「重做就是浪費」
重做是校準系統
從「結果好壞看運氣」
對比能暴露結構
從「spec 只是文件」
spec 是 AI 作業系統

下一堂課 — M3-4

你的系統做好了
但電腦關機就停了

下一堂課:GitHub Actions + Cloudflare Worker + 永遠有選擇

自動排程 事件驅動 閉環通知

M3-3 完成

1 / 56
章節