總覽
0 / 0
client + server tsc 錯誤
1. 自動化測試
| 項目 | 結果 |
npm test — 引擎冒煙(輸入/退格/輕聲 ˙ 與 ˉ 雙軌/canon 比對/score 唯一寫入者) | 45 通過 / 0 失敗 |
內建題庫 validate-wordbook(66 字結構、無簡體、無重複) | 全過 |
88 音節可打驗證(含 ˙ 輕聲) | 88/88 |
2. 型別 & 建置
| 項目 | 結果 |
client tsc --noEmit(React + Vite + TS) | 0 錯 |
server tsc --noEmit(Fastify + TS,拆分後 13 檔案) | 0 錯 |
npm run build(vite prod,PWA 含 workbox) | 83 modules,233ms,產出 dist/ |
3. 全 API route 實機煙測
server/smoke-split.py — 對真實 server(內嵌 PostgreSQL + JWT)打全部端點,
確認 e8c23b6 拆分(1,131 行 → 182 行 composition root + 6 plugins)後
端點 shape 零改動、行為等價。
| Plugin | 端點 | 斷言 | 結果 |
| auth | POST /api/debug/login | 200 + token 簽發 | PASS |
GET /api/auth/me(JWT / 無 token) | 200 回 name / 401 | PASS |
GET /api/health · GET /api/site-features | 200 pg 連線 / 開關清單 | PASS |
| sync(SRS) | GET /api/srs/due | 200 到期清單 | PASS |
GET /api/sync/learning | 200 學習紀錄 | PASS |
POST /api/srs/reviews(raw array) | 200 批量複習 | PASS |
POST /api/sync/ratings(raw array) | 200 學習寫入 | PASS |
| admin | GET /api/admin/stats(player token) | 403 拒絕非 admin | PASS |
| words | GET /api/words/1 | 200 單字(數字 id) | PASS |
GET /api/words/不存在的id | 400(zod coerce 失敗,與原始一致) | PASS |
POST /api/words/upload(token) | 201 + created=1 | PASS |
POST /api/words/upload(無 token) | 401 | PASS |
| oauth | GET /api/auth/oauth/unknown | 400 unknown_provider | PASS |
GET /api/auth/oauth/google(未設 env) | 503 provider_disabled | PASS |
| daily | POST /api/daily/submit(未登入) | 401 | PASS |
GET /api/daily/board | 200 榜單 | PASS |
| 組裝根 | GET /some/route | 200 SPA fallback(index.html) | PASS |
GET /api/nope | 404 JSON | PASS |
另驗 socket.io(P3):polling handshake 回 sid → WebSocket 路徑在拆分後正常。
4. UI 實機截圖(12 畫面)
Playwright + Chromium 跑真實 build(VITE_ZIDAN_DEBUG=1 版),admin 真實 token
(經 /api/debug/login),後台/榜單/統計皆為真實資料(235 用戶 / 10,751 有效字 /
6 待審上傳 / 全球榜 13 人 / 本機 5 次練習)。無 page error。
首頁(左側 11 項導覽 + 功能卡)
新手教學
練習設定:中打(注音)
練習設定:整句打字
題庫(內建/公開/自訂,含上傳)
每日挑戰
1v1 對戰
排行榜(全球/今日)
模擬考
統計(本機 Dexie 紀錄)
設定(每日目標/提示/帳號)
管理後台(總覽/開關/審核/訪客)
5. 本次 commit 鏈(2026-09-07)
| hash | 訊息 |
e8c23b6 | refactor(server): server.ts 1131 行上帝模組拆成 Fastify plugins |
32ba83c | docs: README 對齊實作(4 模式/整句/45 測試/公開上傳)+ OAuth 簽名限制標註 |
88f6f80 | refactor(client): 清死碼/去 as any/設定單一所有權 + 接上公開題庫上傳 |
bde41a2 | refactor(server): 清死碼 + CORS 白名單統一 + 繁中註解 + admin 安全閥 |
85fae0e | fix(battle): 對戰結算分數歸零 — 引擎累計 g.score 為唯一事實來源 |
6. 結論
- 12 項 code review 全數落地(4 個 commit)+ server.ts 上帝模組拆分(
e8c23b6,1,131 → 182 行,6 plugins,端點零改動)
- 45/45 冒煙、雙端 tsc 0 錯、prod build 成功、18/18 API route 實機通過、socket.io 正常、12 頁面 UI 全數渲染正常
- 已知限制(README 已標):OAuth MVP 的
verifyIdToken 只驗 aud/iss、不驗 JWT 簽名(獨立 ticket 待接 JWKS)
- smoke-split.py 已入庫,可作 server 端點回歸工具(需 live DB + server)