規則:可以查前六課、官方文件,也可以使用 Codex、Claude Code、AGY 等 coding agent;但你必須能說出資料怎麼流、身份怎麼被辨認、權限在哪裡被檢查、schema 怎麼部署,以及 production 壞掉時先查哪一層。
你的任務:Private Taskboard
做一個私人 task 管理 Web App。每個使用者都可以建立帳號、登入、建立自己的 tasks、修改完成狀態、刪除,並且永遠不能看到或操作其他使用者的資料。
最終 production data flow:
↓ same-origin request
Worker API
↓ validate / authenticate / authorize
D1
↓ rows
Worker JSON response
↓
Frontend state / DOM
產品本身可以很簡單。這一關評的是系統邊界,不是 UI 特效。
先建立新專案,不要直接改 lesson playground
private-taskboard/
├─ public/
│ ├─ index.html
│ ├─ styles.css
│ └─ script.js
├─ src/
│ └─ index.js
├─ migrations/
├─ wrangler.jsonc
├─ package.json
├─ package-lock.json
├─ .gitignore
├─ .dev.vars.example
└─ README.md
這個 repository 最後要能讓另一個開發者只看 README、環境欄位與 migrations,就知道怎麼把本機版本跑起來。
Checkpoint A|先畫清楚系統,不要先狂寫 code
在 README 放一個最小架構說明:
Browser cookie → session lookup → current user
current user → owner-scoped task query
至少列出你準備做的 routes:
POST /api/register
POST /api/login
POST /api/logout
GET /api/me
GET /api/tasks
POST /api/tasks
PATCH /api/tasks/:id
DELETE /api/tasks/:id
如果你不知道某個 route 的 input、output 與權限需求,先不要急著寫。
Checkpoint B|建立 versioned schema
用 migration 建立至少三張 tables:
users:id、email、password hash / salt、created_at。
sessions:token hash、user_id、expires_at、created_at。
tasks:id、user_id、title、done、created_at。
至少要有:
tasks.user_id → owner identity
NOT NULL constraints
primary keys
不要在 production Worker 每次收到 request 時才臨時 CREATE TABLE。
Checkpoint C|Register:原始密碼不能落地
POST /api/register 至少必須:
驗證 body 是 object。
normalize email。
驗證 email / password 基本格式。
使用 password hashing / KDF,不存 plain password。
拒絕重複 email。
response 不包含 hash、salt 或其他內部欄位。
至少測三種情況:正常註冊、重複 email、錯誤輸入。
Checkpoint D|Login:建立可撤銷 session
POST /api/login 必須完成:
↓ 查 user
↓ verify password
↓ random session token
↓ database 存 token hash
↓ Set-Cookie
Cookie 至少要考慮:
HttpOnly
Secure # production HTTPS
SameSite=Lax
Path=/
Max-Age=...
錯誤 email 與錯誤 password 不要回兩種過度詳細的外部錯誤。
Checkpoint E|GET /api/me:身份必須來自 session
登入後:
GET /api/me
應該由 cookie → session → user 得到目前登入者,而不是讓 frontend 自己傳:
?user_id=3
未登入必須得到合理的 401。
Checkpoint F|Tasks 必須真正是 private data
GET /api/tasks 的 database query 必須帶 current user:
WHERE user_id = ?
建立 task 時,owner 也必須由 session 決定:
就算 client body 偷塞:
{
"title": "steal ownership",
"user_id": 999
}
backend 也不能採用 client 提供的 owner。
Checkpoint G|完成 owner-scoped CRUD
你的 task resource 至少支援:
Read → GET /api/tasks
Update → PATCH /api/tasks/:id
Delete → DELETE /api/tasks/:id
PATCH / DELETE 不能只有:
WHERE id = ?
至少要把 owner boundary 帶進 operation:
WHERE id = ? AND user_id = ?
如果 user B 猜到 user A 的 task id,也不能因此操作成功。
Checkpoint H|Frontend 不只是 API 測試器
做一個實際可以使用的 UI,至少包含:
Register form。
Login form。
目前使用者資訊。
Logout。
新增 task。
task list。
切換 done。
刪除 task。
Loading / empty / error states。
不要用 frontend localStorage 假裝資料持久化;資料真相必須在 production database。
Checkpoint I|Frontend state 和 server state 要分清楚
Frontend 可以保存:
tasks
isLoading
errorMessage
但真正的身份與權限仍由 backend 決定。
例如 UI 可以根據 currentUser 顯示不同畫面,但任何 protected API 仍要重新從 session 驗證。
Checkpoint J|Validation 要在邊界發生
Task title 至少限制:
必須是 string。
trim 後不能空白。
設定合理最大長度,例如 200。
API 不應該接受:
{ "title": null }
{ "title": 123 }
{ "title": "" }
{ "title": "...超長..." }
Frontend validation 可以改善 UX,但 backend validation 才是 trust boundary。
Checkpoint K|錯誤格式必須可預期
至少統一成類似:
{
"error": {
"code": "INVALID_INPUT",
"message": "title is required"
}
}
500 response 不可以把 production stack、SQL、secret、filesystem path 原封不動回給 browser。
Server log 可以有更詳細資訊,但不得記錄完整 password、session token 或 API key。
Checkpoint L|Secret 與 config 不進 source
Repository 必須有:
.dev.vars.example
但不能 commit:
.dev.vars
.env
真實 API key
真實 session token
在 commit 前至少檢查一次:
git status
git diff
如果 secret 曾經進 Git history,要 rotate,不是只刪當前檔案。
Checkpoint M|Local D1 和 production D1 分開
先用 local development 驗證:
再把 migration 套到 remote production database。
你必須知道「deploy code」和「apply schema migration」是兩個不同動作。
Checkpoint N|Production deploy
部署後應該形成:
↓ build / deploy
Cloudflare Worker + Static Assets
↓
D1 + platform secrets
↓
HTTPS production URL
Frontend API call 使用 relative URL:
fetch("/api/tasks", ...)
避免把 production hostname 硬寫進每個 frontend request。
Checkpoint O|真正做兩個帳號的權限測試
這不是可選項。
User A:註冊、登入、建立 task A1 / A2。
User A:確認重新整理後資料仍在。
User A:登出。
User B:建立另一個帳號並登入。
User B:看不到 A1 / A2。
User B:就算知道 A1 的 id,也不能 PATCH / DELETE。
User B:只能看到自己的 tasks。
如果只測一個帳號,你根本還沒驗證 authorization。
Checkpoint P|Logout 要真的讓 session 失效
Logout 後:
+ expire browser cookie
→ protected request 回 401
不能只是 frontend 把 task list 隱藏起來。
Checkpoint Q|做 production smoke test
部署完成後從頭走一次:
□ 首頁載入正常。
□ Register 正常。
□ Login 正常,cookie 有 Secure / HttpOnly。
□ /api/me 正確。
□ Create / Read / Update / Delete 都正常。
□ Refresh 後資料仍在。
□ Logout 後 protected request 失敗。
□ 第二個帳號無法讀寫第一個帳號資料。
□ Network 沒有意外 500。
□ Production log 沒有 secret。
Checkpoint R|README 要讓作品可被理解
README 至少說清楚:
這個產品解決什麼問題。
Frontend / backend / database 架構。
Local development 怎麼啟動。
需要哪些 environment variables / bindings。
Migration 怎麼套用。
Production deployment 流程。
目前已知限制。
README 不是裝飾,它是讓專案可以被另一個人接手的最低文件。
Git history 也要像真的專案
至少拆出幾個可理解的 commits,例如:
database schema + migrations
register / login / sessions
owner-scoped task API
frontend task UI
validation + error handling
production deployment config
不要最後只留下:
final
這一條 commit。
可以用 AI coding agent,但驗收標準更高
Agent 可以幫你建立 Worker routes、D1 queries、frontend UI 或 deployment config,但你必須能回答:
這個 request 的 current user 從哪裡來?
原始 session token 存在哪裡?Database 存的是什麼?
為什麼 user B 無法更新 user A 的 task?
Migration 和 deploy 的先後關係是什麼?
哪一些值可以 commit,哪一些不能?
如果 production API 回 500,你先看哪裡?
如果只能說「agent 幫我寫的」,這一關還沒有通過。
不要把 Final 做成大型 SaaS
這一關不要求:
OAuth / Google Login。
Email verification。
Password reset。
Teams / organizations。
Payments。
WebSocket。
React / Next.js。
那些都可以以後加。現在最重要的是先把一個小系統做完整,而不是把十個功能都做到一半。
最終驗收清單
□ Frontend 與 API 可以完整互動。
□ Production 使用持久 database,不依賴 server RAM。
□ Schema 有 versioned migration。
□ Password 不以明文保存。
□ Session token 隨機產生,server 能 revoke。
□ Cookie 有合理的 HttpOnly / Secure / SameSite 屬性。
□ Protected route 未登入會被拒絕。
□ Tasks 由 current user 擁有。
□ Query / PATCH / DELETE 都守 owner boundary。
□ Client 不能自行指定 owner / admin 權限。
□ Request input 有 backend validation。
□ SQL / database access 使用 bound parameters。
□ Public 500 不洩漏內部錯誤。
□ Secret 不在 Git / frontend / logs。
□ Production 已完成兩帳號 isolation test。
□ GitHub 有可理解的 commit history。
□ README 能讓別人理解與啟動專案。
如果全部做到,你現在已經跨過哪條線?
Web Basics 結束時,你會做「會互動、會讀 API 的網站」。
Web App 結束時,你已經能做:
↕
HTTP API
↕
Validation / Auth / Permissions
↕
Persistent Database
↕
Production Environment
這代表你不再只是把畫面做出來,而是可以把一個小型產品從 browser 一路做到 production data layer。
下一條路徑是 AI Builder:不是重新學一套網站,而是在你現在已有的 Web App 邊界上加入模型 API、Prompt、Context、Structured Output、RAG 與 Tool Calling。
Web App 完成條件:你能從零做出並部署一個有 frontend、API、持久 database、register / login / logout、server-side session、owner-based authorization、validation、safe errors、secrets 與 migrations 的小型 Web App,而且能自己說明它為什麼能工作。