Skip to content

C9 Platform — QA 測試規格書

版本:v1.0 目標讀者:QA 工程師、測試人員 涵蓋範圍:前台 (c9-ec)、後台 (c9-ims)、後端 (c9-be) 全功能測試 最後更新:2026-03-01


目錄


第 1 章:測試環境

1.1 系統需求

1.1.1 硬體需求

項目最低需求建議配置
CPU4 核心8 核心以上
記憶體8 GB16 GB 以上
硬碟20 GB 可用空間50 GB SSD
網路穩定寬頻連線100 Mbps 以上

1.1.2 軟體需求

軟體版本用途安裝方式
Node.js20.x 以上JavaScript 執行環境nvm install 20 或官網下載
Yarn1.22.xc9-ec / c9-be 套件管理npm install -g yarn
pnpm8.x 以上c9-ims 套件管理npm install -g pnpm
MySQL8.0 以上主資料庫brew install mysql (macOS)
Redis7.x 以上快取伺服器brew install redis (macOS)
Git2.40 以上版本控制brew install git (macOS)
GitHub CLI2.xGitHub 操作brew install gh (macOS)

1.1.3 瀏覽器需求(前端測試)

瀏覽器版本優先級
Google Chrome最新穩定版P1(主要測試瀏覽器)
Mozilla Firefox最新穩定版P2
Safari最新版P2(macOS / iOS)
Microsoft Edge最新版P3
Chrome Mobile最新版P1(行動版測試)
Safari Mobile最新版P2(iOS 測試)

1.1.4 開發工具

工具用途說明
VS Code程式碼編輯建議安裝 ESLint、Prettier、Vue Official、i18n Ally 擴充
Postman / InsomniaAPI 測試手動 API 呼叫與除錯
MySQL Workbench資料庫管理查看資料表與資料內容
Redis Desktop ManagerRedis 管理查看快取資料
Chrome DevTools前端除錯網路、Console、Application(Cookie)檢查

1.2 環境安裝

1.2.1 專案下載

bash
# 1. 克隆主專案(含子模組)
git clone --recurse-submodules <repo-url> c9
cd c9

# 2. 若子模組未初始化
git submodule init
git submodule update

1.2.2 依賴安裝

bash
# 根目錄(安裝 concurrently 等工具)
cd c9
yarn install

# 前台 (c9-ec)
cd c9-ec
yarn install

# 後台 (c9-ims)
cd c9-ims
pnpm install

# 後端 (c9-be)
cd c9-be
yarn install

1.2.3 環境變數設定

c9-be(後端)

c9-be/ 目錄下建立 .env 檔案:

env
# 資料庫
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=your_password
DB_DATABASE=c9_dev

# Redis
REDIS_URL=redis://localhost:6379

# JWT
JWT_SECRET=your_jwt_secret
ADMIN_JWT_SECRET=your_admin_jwt_secret

# 站點
SITE_CODE=C9

# R2 存儲(Cloudflare)
R2_ACCESS_KEY_ID=your_r2_key
R2_SECRET_ACCESS_KEY=your_r2_secret
R2_ENDPOINT=your_r2_endpoint
R2_BUCKET=your_r2_bucket

# 其他服務(可選)
RESEND_API_KEY=your_resend_key
TWILIO_ACCOUNT_SID=your_twilio_sid
TWILIO_AUTH_TOKEN=your_twilio_token

c9-ims(後台)

c9-ims/ 目錄下建立 .env.local 檔案:

env
NEXT_PUBLIC_SITE_ID=a1
NEXT_PUBLIC_API_BASE_URL=http://localhost:8080/api
NEXTAUTH_SECRET=your_nextauth_secret
NEXTAUTH_URL=http://localhost:3011

c9-ec(前台)

c9-ec/ 目錄下建立 .env 檔案:

env
NUXT_PUBLIC_API_BASE=http://localhost:8080/api
NUXT_PUBLIC_SITE_NAME=C9

1.2.4 資料庫初始化

bash
# 1. 建立資料庫
mysql -u root -p -e "CREATE DATABASE c9_dev CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

# 2. 啟動後端(TypeORM 自動同步 Schema)
cd c9-be
yarn dev

# 3. 執行 Seed 腳本(產生測試資料)
npx ts-node scripts/seed-all.ts

Seed 資料說明

  • 涵蓋 37+ 張資料表
  • 建立 5 個站點配置(C9, A1, B2, D3, E4)
  • 每站建立 30 名測試用戶
  • 包含 VIP 等級、返水設定、活動、遊戲商等基礎資料
  • 建立管理員帳號(含 root / super_admin / general_admin 各群組)

1.3 啟動服務

1.3.1 一鍵啟動(推薦)

bash
# 在 c9/ 根目錄
yarn dev

同時啟動三個專案,終端顯示彩色標籤:

  • [ec] 藍色 — 前台
  • [ims] 綠色 — 後台
  • [be] 黃色 — 後端

1.3.2 個別啟動

指令說明存取位址
yarn dev:ec啟動前台http://localhost:3010
yarn dev:ims啟動後台http://localhost:3011
yarn dev:be啟動後端http://localhost:8080/api

1.3.3 服務埠號對照

服務埠號說明
c9-ec(前台)3010Nuxt 開發伺服器
c9-ims(後台)3011Next.js 開發伺服器(Turbopack)
c9-be(後端 API)8080NestJS 開發伺服器
Swagger UI8080/api/docs互動式 API 文件
MySQL3306資料庫
Redis6379快取

1.3.4 健康檢查

啟動後進行以下驗證:

檢查項目方法預期結果
後端 APIcurl http://localhost:8080/api回傳 JSON 回應
Swagger UI瀏覽器開啟 http://localhost:8080/api/docs顯示 Swagger 頁面
前台首頁瀏覽器開啟 http://localhost:3010顯示首頁畫面
後台登入瀏覽器開啟 http://localhost:3011顯示登入頁面
資料庫連線後端啟動日誌無錯誤TypeORM 連線成功訊息
Redis 連線後端啟動日誌無錯誤Redis 連線成功訊息

1.4 測試工具與指令

1.4.1 測試框架對照

專案測試框架測試類型說明
c9-ecVitest單元測試Composable、工具函數測試
c9-ecVitest + @nuxt/test-utils元件測試Vue 元件渲染測試
c9-ecPlaywrightE2E 測試瀏覽器端對端自動化測試
c9-imsTypeScript Compiler型別檢查yarn typecheck 確保型別正確
c9-beJest單元測試Service / Controller 單元測試
c9-beJest + SupertestE2E 測試API 端對端整合測試

1.4.2 測試指令總表

c9-ec(前台)

指令說明涵蓋範圍
yarn test執行所有測試單元 + 元件
yarn test:unit只跑單元測試Composable、工具函數
yarn test:nuxt只跑元件測試Vue 元件渲染與互動
yarn test:e2eE2E 測試Playwright 瀏覽器自動化
yarn lint程式碼檢查ESLint 規則
yarn format格式化Prettier 格式化

c9-ims(後台)

指令說明涵蓋範圍
yarn typecheckTypeScript 型別檢查全專案型別正確性
yarn lint程式碼檢查ESLint 規則
yarn format格式化Prettier 格式化

c9-be(後端)

指令說明涵蓋範圍
yarn test執行所有單元測試Jest 單元測試
yarn test:e2e執行 E2E 測試API 整合測試
yarn lint程式碼檢查ESLint 規則
yarn format格式化Prettier 格式化

1.4.3 Seed 測試資料

bash
# 在 c9-be/ 目錄下執行
npx ts-node scripts/seed-all.ts

產生的測試資料

類別數量說明
站點配置5 個C9(預設站)、A1、B2、D3、E4
前台用戶150 人每站 30 人(含各 VIP 等級)
管理員10+ 人root / super_admin / general_admin / custom 各群組
管理員群組4 個root / super_admin / general_admin / custom
VIP 等級每站 16 級VIP 0 ~ VIP 15
VIP 反水每站 128 筆16 等級 x 8 遊戲類型
遊戲供應商每站 5+ 個BetSolutions / RSG 等
遊戲分類每站 8 個SPORTS / SLOT / LIVE / LOTTERY / CHESS / ESPORTS / CRYPTO / FISH
活動每站 10+ 個各類優惠活動
活動標籤每站 5+ 個分類標籤
站點主題每站 2+ 個預設 + 自訂主題
金流群組每站 2+ 個金流通道分組
金流通道每站 5+ 個ATM / 信用卡 / USDT
代理等級每站 4 個bronze / silver / gold / platinum
佣金費率每站 96 筆4 等級 x 3 級別 x 8 遊戲類型

測試帳號(由 Seed 產生):

角色帳號格式密碼說明
前台用戶testuser01 ~ testuser30Test123456每站 30 人
Root 管理員root_adminAdmin123456最高權限
Super Adminsuper_adminAdmin123456除站點設定外全權限
General Admingeneral_adminAdmin123456唯讀權限
Custom Admincustom_adminAdmin123456自訂權限

注意:以上帳號密碼僅供開發測試環境使用,正式環境請務必更換。


1.5 測試優先級定義

優先級代號說明回歸測試頻率
最高P1核心業務流程,阻斷性問題每次部署
P2重要功能,影響用戶體驗每週
P3次要功能,不影響主流程每月
P4美觀、文案等非功能性問題視情況

1.6 測試嚴重程度定義

嚴重程度代號說明範例
致命Critical系統崩潰、資料遺失、金流錯誤存款金額計算錯誤、系統無法啟動
嚴重Major主要功能無法使用無法登入、無法存款、遊戲無法啟動
一般Minor次要功能異常或 UI 瑕疵篩選結果不正確、排序錯誤
輕微Trivial文案錯字、美觀問題按鈕對齊偏移、翻譯缺漏

第 2 章:前台測試案例 (c9-ec)

測試對象http://localhost:3010框架:Nuxt 4.2 (Vue 3.5 + TypeScript) 支援語系:zh-TW, en-US, zh-CN, th-TH, vi-VN


2.1 首頁測試

前置條件

  • 前台服務已啟動 (port 3010)
  • 後端 API 服務已啟動 (port 8080)
  • 已有 Seed 測試資料
TC-ID測試說明測試步驟預期結果優先級
TC-HOME-001首頁正常載入並顯示 Banner1. 開啟瀏覽器 2. 輸入 http://localhost:3010 3. 等待頁面載入完成1. 頁面成功載入,無 Console 錯誤 2. Banner 區域顯示至少一張輪播圖 3. 頁面標題正確顯示站點名稱P1
TC-HOME-002Banner 輪播自動切換1. 開啟首頁 2. 觀察 Banner 區域 3. 等待約 5 秒1. Banner 圖片自動切換至下一張 2. 切換動畫流暢 3. 輪播指示點同步更新 4. 手動點擊指示點可跳轉P3
TC-HOME-003即時賽事區顯示比賽資料1. 開啟首頁 2. 捲動至即時賽事區域 3. 檢查賽事卡片內容1. 顯示當前即時賽事列表 2. 每個賽事卡片包含:隊伍名稱、比分、聯賽名稱 3. 資料每 30 分鐘自動更新(API-Football 快取)P2
TC-HOME-004精選活動正確顯示1. 開啟首頁 2. 捲動至精選活動區域 3. 檢查活動卡片1. 顯示當前站點的活動列表 2. 每個活動卡片含標題、縮圖、描述 3. 點擊卡片可進入活動詳情頁 4. 僅顯示 enabled 狀態的活動P2
TC-HOME-005導航至遊戲大廳1. 開啟首頁 2. 點擊導航列「遊戲大廳」或遊戲分類快捷入口1. 成功跳轉至遊戲大廳頁面 2. URL 變更為對應路由 3. 遊戲分類 Tab 正確顯示P1
TC-HOME-006未登入點擊存款導航1. 確認未登入狀態 2. 開啟首頁 3. 點擊「存款」按鈕或導航項目1. 自動導向登入頁面 2. 登入後自動跳轉回存款頁面 3. URL 帶有 redirect 參數P1
TC-HOME-007底部導航列正確顯示(行動版)1. 使用 Chrome DevTools 切換至行動裝置模式(375px) 2. 開啟首頁1. 底部導航列顯示 2. 包含首頁、遊戲、存款、我的等項目 3. 點擊各項目可正常導航P2
TC-HOME-008頁尾資訊顯示1. 捲動至頁面底部 2. 檢查頁尾區域1. 顯示站點 Logo 2. 顯示版權資訊 3. 顯示相關連結(了解更多、客服等) 4. 連結可正常點擊P3
TC-HOME-009客服入口顯示1. 開啟首頁 2. 檢查客服浮動按鈕1. 客服浮動圖示顯示在右下角 2. 點擊展開客服管道列表 3. 各管道連結可正常開啟 4. LiveChat 嵌入腳本正常載入(若啟用)P2
TC-HOME-010吉祥物動畫顯示1. 開啟首頁 2. 檢查吉祥物區域1. 吉祥物圖片/動畫正確載入 2. 互動動畫流暢 3. 不影響頁面其他元素操作P4

2.2 註冊流程測試

前置條件

  • 前台服務已啟動
  • 後端 API 服務已啟動
  • 未登入狀態
TC-ID測試說明測試步驟預期結果優先級
TC-REG-001有效帳密郵箱註冊1. 進入註冊頁面 2. 輸入帳號:testqa001(6-20 英數字) 3. 輸入密碼:Qa123456!(8+ 位含大小寫數字) 4. 輸入 Email:testqa001@test.com 5. 勾選同意條款 6. 點擊「註冊」按鈕1. 表單驗證通過(Zod) 2. 成功建立帳號 3. 自動登入並跳轉至首頁 4. JWT Token 寫入 Cookie 5. 用戶資料寫入資料庫P1
TC-REG-002重複帳號註冊1. 進入註冊頁面 2. 輸入已存在的帳號(如 testuser01) 3. 填寫其他欄位 4. 點擊「註冊」1. 顯示錯誤訊息「帳號已存在」 2. 錯誤訊息透過 ERROR_CODES 查表取得 3. 不建立新帳號 4. 錯誤訊息語系與當前語系一致P1
TC-REG-003無效 Email 格式1. 進入註冊頁面 2. 輸入 Email:invalid-email 3. 點擊其他欄位觸發驗證1. Zod 驗證攔截 2. Email 欄位顯示紅色外框 3. 顯示格式錯誤提示 4. 註冊按鈕不可點擊或提交後被擋P2
TC-REG-004弱密碼驗證1. 進入註冊頁面 2. 依序測試以下密碼:a. 123(太短) b. abcdefgh(無數字) c. 12345678(無字母) 3. 觀察驗證提示1. 每種弱密碼都顯示對應錯誤提示 2. 密碼強度指示器更新 3. 表單無法提交P2
TC-REG-005推薦碼綁定代理1. 透過帶有 refCode 的連結進入:http://localhost:3010?ref=ABC123 2. 進入註冊頁面 3. 確認推薦碼欄位已自動填入 4. 完成註冊1. refCode 自動帶入推薦碼欄位 2. 註冊成功後自動綁定上線代理 3. 在代理系統中可查到下線關係 4. affiliate-bind-log 寫入紀錄P1
TC-REG-006Google OAuth 註冊1. 進入註冊頁面 2. 點擊「Google 登入」按鈕 3. 完成 Google OAuth 授權流程1. 導向 Google OAuth 授權頁面 2. 授權後回調至前台 3. 自動建立帳號(若首次) 4. 自動登入並跳轉至首頁 5. 用戶資料含 Google 關聯資訊P1
TC-REG-007Telegram OAuth 註冊1. 進入註冊頁面 2. 點擊「Telegram 登入」按鈕 3. 完成 Telegram OAuth 授權流程1. 導向 Telegram 授權 Widget 2. 授權後回調至前台 3. 自動建立帳號(若首次) 4. 自動登入並跳轉至首頁P2
TC-REG-008裝置指紋擷取1. 進入註冊頁面 2. 使用瀏覽器開發者工具監控網路請求 3. 完成註冊流程1. FingerprintJS v5 初始化成功 2. 註冊 API 請求包含 deviceFingerprint 欄位 3. 指紋寫入 auth-user 表 4. Console 無 FingerprintJS 錯誤P2
TC-REG-009依語系自動分配金流群組1. 切換語系至 en-US 2. 完成新用戶註冊 3. 登入後檢查可用金流通道1. 用戶自動分配至對應語系的金流群組 2. 存款頁面顯示對應群組的通道 3. 不同語系用戶可能看到不同金流選項P2
TC-REG-010空白必填欄位提交1. 進入註冊頁面 2. 不填寫任何欄位 3. 直接點擊「註冊」按鈕1. 所有必填欄位顯示驗證錯誤 2. 表單不提交 3. 各欄位錯誤提示文字正確(當前語系)P2
TC-REG-011帳號長度邊界值1. 測試帳號長度 5 字元(低於最小值) 2. 測試帳號長度 6 字元(最小值) 3. 測試帳號長度 20 字元(最大值) 4. 測試帳號長度 21 字元(超過最大值)1. 5 字元 → 驗證失敗 2. 6 字元 → 驗證通過 3. 20 字元 → 驗證通過 4. 21 字元 → 驗證失敗P3
TC-REG-012帳號特殊字元1. 輸入包含特殊字元的帳號:test@#$ 2. 嘗試提交1. 帳號只允許英文字母和數字 2. 特殊字元被拒絕 3. 顯示格式錯誤提示P3

2.3 登入流程測試

前置條件

  • 已有註冊帳號(使用 Seed 資料 testuser01
  • 未登入狀態
TC-ID測試說明測試步驟預期結果優先級
TC-LOGIN-001有效帳密登入1. 進入登入頁面 2. 輸入帳號:testuser01 3. 輸入密碼:Test123456 4. 點擊「登入」按鈕1. 登入成功 2. JWT Token 寫入 Cookie(7 天過期) 3. 自動跳轉至首頁 4. 導航列顯示用戶資訊 5. auth-user-login-log 寫入登入紀錄P1
TC-LOGIN-002密碼錯誤1. 進入登入頁面 2. 輸入帳號:testuser01 3. 輸入錯誤密碼 4. 點擊「登入」1. 顯示錯誤訊息(透過 ERROR_CODES 查表) 2. 不建立 Session 3. 停留在登入頁面 4. 登入失敗紀錄寫入資料庫P1
TC-LOGIN-003不存在的帳號1. 進入登入頁面 2. 輸入帳號:nonexistent_user 3. 輸入任意密碼 4. 點擊「登入」1. 顯示錯誤訊息 2. 錯誤訊息不洩漏帳號是否存在(安全考量) 3. 停留在登入頁面P1
TC-LOGIN-004Google OAuth 登入1. 進入登入頁面 2. 點擊「Google 登入」按鈕 3. 使用已綁定的 Google 帳號授權1. 導向 Google OAuth 頁面 2. 授權後回調成功 3. 已綁定帳號直接登入 4. JWT Token 正確寫入P1
TC-LOGIN-005Telegram OAuth 登入1. 進入登入頁面 2. 點擊「Telegram 登入」Widget 3. 使用已綁定的 Telegram 帳號授權1. Telegram Widget 載入正常 2. 授權後回調成功 3. 已綁定帳號直接登入P2
TC-LOGIN-0062FA 驗證(Google Authenticator)1. 使用已啟用 2FA 的帳號 2. 輸入正確帳密 3. 系統要求輸入 6 位 TOTP 驗證碼 4. 輸入正確驗證碼1. 帳密驗證通過後,顯示 2FA 輸入介面 2. 輸入正確 TOTP → 登入成功 3. 輸入錯誤 TOTP → 顯示驗證失敗 4. TOTP 有 30 秒有效期P1
TC-LOGIN-007裝置指紋隨登入傳送1. 使用瀏覽器開發者工具監控網路請求 2. 進行正常登入流程 3. 檢查登入 API 請求 Body1. 登入請求包含 deviceFingerprint 欄位 2. 指紋值為 FingerprintJS 產生的字串 3. 後端儲存至登入紀錄P2
TC-LOGIN-008JWT Token 有效期1. 正常登入 2. 使用 Chrome DevTools > Application > Cookies 檢查 Token 3. 驗證過期時間1. JWT Token 存在於 Cookie 中 2. Token 過期時間為 7 天 3. Token 內含用戶 ID 和角色資訊P2
TC-LOGIN-009受保護頁面重導向1. 確認未登入狀態 2. 直接存取 http://localhost:3010/deposit 3. 完成登入流程1. 未登入時自動跳轉至登入頁 2. URL 帶有 redirect 參數指向原始頁面 3. 登入成功後自動跳轉回存款頁面P1
TC-LOGIN-010登出功能1. 已登入狀態 2. 點擊導航列「登出」按鈕1. JWT Token 從 Cookie 中移除 2. 跳轉至首頁或登入頁 3. 無法再存取受保護頁面 4. 後端 Token 失效P1
TC-LOGIN-011多次登入失敗1. 使用正確帳號 2. 連續輸入 5 次錯誤密碼 3. 觀察系統反應1. 每次失敗都寫入登入失敗紀錄 2. 後台可查到失敗紀錄(含 IP 和時間) 3. 視風控設定可能觸發帳號鎖定或驗證碼P2
TC-LOGIN-012Token 過期後行為1. 登入成功取得 Token 2. 手動修改 Cookie 中 Token 的過期時間為過去 3. 重新載入頁面1. 過期 Token 被後端拒絕(401) 2. 前端自動清除 Token 3. 重導向至登入頁面P1

2.4 遊戲大廳測試

前置條件

  • 已登入狀態
  • Seed 資料含遊戲供應商和遊戲分類
TC-ID測試說明測試步驟預期結果優先級
TC-GAME-001遊戲大廳載入 8 個分類 Tab1. 導航至遊戲大廳 2. 檢查分類 Tab 列1. 顯示 8 個遊戲分類 Tab:體育(SPORTS)、老虎機(SLOT)、真人(LIVE)、彩票(LOTTERY)、棋牌(CHESS)、電競(ESPORTS)、加密(CRYPTO)、捕魚(FISH) 2. 預設選中第一個 Tab 3. Tab 圖示和文字正確P1
TC-GAME-002切換遊戲分類 Tab1. 在遊戲大廳頁面 2. 依序點擊每個分類 Tab1. 每次切換顯示對應分類的供應商列表 2. 供應商卡片含 Logo 和名稱 3. 切換動畫流暢 4. 無已提供的遊戲商 → 顯示空狀態P1
TC-GAME-003搜尋遊戲名稱1. 在遊戲大廳頁面 2. 在搜尋框輸入遊戲名稱關鍵字 3. 觀察搜尋結果1. 即時篩選顯示匹配的遊戲 2. 支援模糊搜尋 3. 無結果時顯示空狀態提示 4. 清除搜尋框後恢復完整列表P2
TC-GAME-004點擊供應商展開遊戲列表1. 在遊戲大廳選擇某分類 2. 點擊某個供應商卡片1. 展開或跳轉至該供應商的遊戲列表 2. 遊戲列表含遊戲名稱、縮圖 3. 可點擊單一遊戲進入P1
TC-GAME-005最近遊玩顯示1. 先啟動並遊玩幾款遊戲 2. 回到遊戲大廳 3. 檢查「最近遊玩」區域1. 顯示最近遊玩的遊戲(最多 10 款) 2. 按遊玩時間倒序排列 3. 點擊可重新進入遊戲 4. 未遊玩過任何遊戲時不顯示此區域P3
TC-GAME-006排行榜顯示1. 導航至遊戲大廳 2. 檢查排行榜區域1. 顯示排行榜資料(大贏家等) 2. 包含用戶名稱(部分遮罩)、金額、遊戲名稱 3. 資料正確排序P3
TC-GAME-007啟動遊戲(iframe)1. 已登入狀態 2. 選擇一款遊戲 3. 點擊「進入遊戲」1. 遊戲 iframe 成功載入 2. 遊戲介面正確顯示 3. 餘額資訊正確 4. API 呼叫 /game/launch 成功 5. game-play-log 寫入紀錄P1
TC-GAME-008試玩模式(Demo)1. 未登入或已登入狀態 2. 選擇支援試玩的遊戲 3. 點擊「試玩」按鈕1. 遊戲以試玩模式啟動 2. 使用虛擬餘額 3. 不影響真實帳戶餘額 4. 部分遊戲可能不支援試玩P2
TC-GAME-009風控黑名單阻擋1. 透過後台將測試用戶加入遊戲黑名單 2. 使用該用戶登入前台 3. 嘗試啟動被封鎖的遊戲1. 遊戲啟動被阻擋 2. 返回錯誤碼 5010 3. 顯示對應錯誤訊息 4. 全封鎖用戶無法啟動任何遊戲P1
TC-GAME-010代表遊戲顯示(子分類)1. 在遊戲大廳查看分類 2. 檢查有子分類的遊戲類型1. 子分類顯示代表遊戲(第一款) 2. 點擊可展開完整子分類遊戲列表 3. 無子分類的類型直接顯示遊戲列表P3
TC-GAME-011未登入時啟動遊戲1. 未登入狀態 2. 嘗試點擊「進入遊戲」1. 跳轉至登入頁面 2. 登入後回到遊戲頁面 3. 可重新點擊進入遊戲P1
TC-GAME-012遊戲載入失敗處理1. 模擬遊戲供應商 API 異常 2. 嘗試啟動遊戲1. 顯示友善的錯誤提示 2. 提供重試按鈕 3. 不出現白畫面或無限載入P2

2.5 存款流程測試

前置條件

  • 已登入狀態
  • 用戶已分配金流群組
  • 有可用的金流通道
TC-ID測試說明測試步驟預期結果優先級
TC-DEP-001法幣存款(ATM)1. 進入存款頁面 2. 選擇「銀行轉帳 / ATM」通道 3. 輸入存款金額 4. 確認提交1. 通道列表正確載入(依金流群組篩選) 2. 顯示匯率資訊(TWD → USD) 3. 產生存款訂單 4. 顯示付款資訊(銀行帳號等) 5. 訂單狀態為「待處理」P1
TC-DEP-002信用卡存款1. 進入存款頁面 2. 選擇「信用卡」通道 3. 輸入存款金額 4. 確認提交1. 跳轉至信用卡付款頁面 2. 顯示金額與匯率 3. 產生存款訂單 4. 付款完成後回調更新狀態P1
TC-DEP-003加密貨幣存款(USDT)1. 進入存款頁面 2. 選擇「USDT」通道 3. 輸入存款金額1. 顯示 USDT 存款地址(TRC-20 或 ERC-20) 2. 顯示 QR Code 3. 顯示匯率(USDT → USD) 4. 產生存款訂單P1
TC-DEP-004匯率顯示正確性1. 進入存款頁面 2. 輸入 1000 TWD 3. 檢查換算結果1. 顯示台灣銀行即時匯率 2. 換算後 USD 金額正確 3. 使用無條件捨去(Math.floor(value * 1e6) / 1e6) 4. 顯示精度為小數 6 位P1
TC-DEP-005建立存款訂單1. 選擇通道並輸入金額 2. 確認提交 3. 檢查訂單1. API 回應 code: 200 2. deposit-order 表新增一筆紀錄 3. 訂單狀態為 pending 4. 訂單含正確金額(USD)和匯率 5. 訂單含 siteCodeP1
TC-DEP-006存款歷史紀錄1. 完成一筆或多筆存款 2. 進入交易紀錄頁面 3. 查看存款歷史1. 列出所有存款訂單 2. 每筆含:訂單編號、金額、狀態、時間 3. 支援分頁瀏覽 4. 可篩選狀態P2
TC-DEP-007最小/最大金額驗證1. 輸入低於最小存款金額(如 0 或 1) 2. 輸入高於最大存款金額 3. 嘗試提交1. 低於最小值 → 顯示最小金額限制提示 2. 高於最大值 → 顯示最大金額限制提示 3. 表單不提交 4. 邊界值(等於最小/最大)→ 允許P2
TC-DEP-008幣值轉換精度1. 輸入會產生長小數的金額 2. 完成存款流程 3. 檢查資料庫中的金額1. USD 金額精度為 decimal(18,6) 2. 使用截斷而非四捨五入 3. 匯率精度為 decimal(18,10) 4. 計算結果與前端顯示一致P1
TC-DEP-009無可用通道時顯示1. 使用未分配金流群組的帳號 2. 進入存款頁面1. 顯示「暫無可用存款方式」提示 2. 不顯示空白頁面 3. 提供聯絡客服引導P3
TC-DEP-010存款後餘額更新1. 記錄當前餘額 2. 完成一筆存款(待管理員審核通過) 3. 審核通過後重新載入1. 審核通過前餘額不變 2. 審核通過後餘額增加(存款 USD 金額) 3. 餘額顯示精度正確P1

2.6 提款流程測試

前置條件

  • 已登入狀態
  • 帳戶有足夠餘額
  • 已綁定至少一張銀行卡或加密錢包
TC-ID測試說明測試步驟預期結果優先級
TC-WD-001銀行卡提款1. 進入提款頁面 2. 選擇已審核通過的銀行卡 3. 輸入提款金額 4. 確認提交1. 銀行卡列表僅顯示審核通過的卡片 2. 顯示可提款餘額 3. 訂單建立成功,狀態為 pending 4. withdrawal-order 表新增紀錄P1
TC-WD-002加密錢包提款1. 進入提款頁面 2. 選擇已審核通過的加密地址(TRC-20 / ERC-20) 3. 輸入提款金額 4. 確認提交1. 加密地址列表正確顯示 2. 顯示鏈類型(TRC-20 / ERC-20) 3. 訂單建立成功 4. 顯示預估到帳時間P1
TC-WD-003超額提款1. 進入提款頁面 2. 輸入金額超過可用餘額 3. 嘗試提交1. 前端驗證攔截 2. 顯示「餘額不足」提示 3. 訂單不建立 4. 即使繞過前端驗證,後端也會拒絕P1
TC-WD-004提款訂單狀態1. 成功建立提款訂單 2. 檢查訂單狀態1. 初始狀態為 pending(待審核) 2. 管理員審核後變為 approvedrejected 3. 完成後變為 completed 4. 各狀態轉換時間記錄正確P1
TC-WD-005提款歷史紀錄1. 進入交易紀錄頁面 2. 切換至提款歷史分頁1. 列出所有提款訂單 2. 含訂單編號、金額、狀態、提款方式、時間 3. 支援分頁 4. 可篩選狀態P2
TC-WD-006凍結餘額更新1. 記錄當前餘額和凍結餘額 2. 建立提款訂單 3. 檢查餘額變化1. 可用餘額減少(扣除提款金額) 2. 凍結餘額增加(加上提款金額) 3. 總餘額不變 4. 提款拒絕後凍結餘額退回可用餘額P1
TC-WD-007無綁定卡片時提款1. 使用未綁定任何銀行卡/加密地址的帳號 2. 進入提款頁面1. 顯示「請先綁定提款方式」提示 2. 提供跳轉至錢包管理的連結 3. 無法直接提交提款P2
TC-WD-008提款最小金額限制1. 輸入低於最小提款金額 2. 嘗試提交1. 顯示最小提款金額限制 2. 表單不提交 3. 邊界值等於最小值 → 允許P2

2.7 錢包管理測試

前置條件

  • 已登入狀態
TC-ID測試說明測試步驟預期結果優先級
TC-WALLET-001新增銀行卡(有效資料)1. 進入錢包管理頁面 2. 點擊「新增銀行卡」 3. 填寫:銀行名稱、分行、帳號、持卡人姓名 4. 提交1. 表單驗證通過 2. 銀行卡建立成功 3. 狀態為 pending(待審核) 4. 列表中顯示新卡片P1
TC-WALLET-002新增銀行卡(無效資料)1. 進入新增銀行卡表單 2. 輸入無效銀行帳號格式 3. 留空必填欄位 4. 嘗試提交1. Zod 驗證攔截 2. 各欄位顯示對應錯誤提示 3. 表單不提交P2
TC-WALLET-003刪除銀行卡1. 在銀行卡列表中 2. 點擊某張卡片的「刪除」按鈕 3. 確認刪除1. 顯示確認對話框 2. 確認後卡片從列表移除 3. 資料庫標記為刪除 4. 若有進行中的提款使用此卡 → 不允許刪除P2
TC-WALLET-004新增信用卡1. 進入錢包管理 2. 點擊「新增信用卡」 3. 填寫卡號、有效期、CVV、持卡人 4. 提交1. 卡號格式驗證(Luhn 演算法) 2. 信用卡建立成功 3. 卡號部分遮罩顯示 4. 狀態為 pendingP1
TC-WALLET-005新增加密地址(TRC-20)1. 進入錢包管理 2. 點擊「新增加密地址」 3. 選擇網路:TRC-20 4. 輸入 USDT 地址 5. 提交1. 地址格式驗證(TRC-20 格式) 2. 地址建立成功 3. 顯示鏈類型標籤 4. 狀態為 pendingP1
TC-WALLET-006銀行卡審核狀態顯示1. 新增一張銀行卡 2. 查看列表中的狀態標籤1. 待審核 → 黃色/橙色標籤 pending 2. 審核通過 → 綠色標籤 approved 3. 審核拒絕 → 紅色標籤 rejected 4. 只有 approved 狀態的卡片可用於提款P2
TC-WALLET-007查看卡片詳情1. 點擊某張卡片查看詳情1. 顯示完整卡片資訊 2. 敏感資訊部分遮罩(如卡號中間位數) 3. 顯示建立時間和審核狀態P3
TC-WALLET-008新增加密地址(ERC-20)1. 進入錢包管理 2. 選擇網路:ERC-20 3. 輸入以 0x 開頭的地址 4. 提交1. 地址格式驗證(ERC-20 格式,0x 開頭) 2. 地址建立成功 3. 與 TRC-20 地址區分顯示P2

2.8 VIP 頁面測試

前置條件

  • 已登入狀態
  • 用戶有 VIP 等級資料
TC-ID測試說明測試步驟預期結果優先級
TC-VIP-001VIP 狀態卡顯示1. 進入 VIP 頁面 2. 檢查 VIP 狀態卡1. 顯示當前 VIP 等級(如 VIP 3) 2. 顯示等級圖示/徽章 3. 顯示距離下一等級的進度條 4. 顯示累計投注金額 5. 顯示下一等級門檻金額P1
TC-VIP-002等級列表展示1. 在 VIP 頁面檢查等級列表區域1. 顯示所有 VIP 等級(動態取得,不限 15 級) 2. 每個等級含名稱、門檻、圖示 3. 當前等級高亮顯示 4. 已達成等級與未達成等級視覺區分P1
TC-VIP-003福利說明顯示1. 在 VIP 頁面檢查福利區域1. 每個等級的福利內容正確顯示 2. 包含返水比例、生日禮金等資訊 3. 資料與後端設定一致P2
TC-VIP-004我的返水紀錄1. 在 VIP 頁面切換至「我的返水」分頁 2. 檢查返水紀錄列表1. 顯示返水發放紀錄 2. 每筆含日期、遊戲類型、投注金額、返水金額 3. 支援分頁 4. 僅顯示當前用戶的紀錄P2
TC-VIP-005返水比例表1. 在 VIP 頁面查看返水比例表1. 顯示各等級 x 各遊戲類型的返水比例 2. 8 種遊戲類型對應列 3. 當前等級行高亮 4. 比例精度 decimal(5,2)P2
TC-VIP-006VIP 等級動態取得1. 檢查 VIP 頁面的等級數量 2. 對照後端資料庫設定1. 等級數量由後端動態決定(不硬編碼) 2. 若後端新增等級,前端自動顯示 3. 下拉選項等也同步更新P2
TC-VIP-007保級資訊顯示1. VIP 5+ 用戶檢查保級資訊1. 顯示保級所需的月度投注門檻 2. 顯示當月已投注金額 3. 顯示保級截止日期 4. VIP 5 以下不顯示保級資訊P3

2.9 代理中心測試

前置條件

  • 已登入且為代理身分的帳號
TC-ID測試說明測試步驟預期結果優先級
TC-AFF-001代理儀表板顯示1. 進入代理中心 2. 檢查儀表板資訊1. 顯示下線總人數 2. 顯示本週/本月佣金 3. 顯示累計佣金 4. 顯示代理等級(bronze/silver/gold/platinum) 5. 資料正確且即時P1
TC-AFF-002下線樹狀顯示1. 進入代理中心 2. 查看「我的下線」1. 以樹狀或列表顯示下線結構 2. 最多 3 層代理結構 3. 下線帳號經遮罩處理(maskAccount) 4. 顯示各層下線人數P1
TC-AFF-003佣金紀錄列表1. 進入代理中心 2. 查看「佣金紀錄」1. 列出佣金發放紀錄 2. 每筆含來源下線、遊戲類型、金額、日期 3. 支援日期篩選 4. 支援分頁P2
TC-AFF-004結算紀錄與狀態1. 進入代理中心 2. 查看「結算紀錄」1. 顯示週結/日結紀錄 2. 狀態:pending → approved/rejected → completed 3. 含結算金額、下線人數、風控結果 4. 可查看結算明細P1
TC-AFF-005代理餘額提款1. 代理帳戶有佣金餘額 2. 在代理中心點擊「提款」 3. 輸入金額並提交1. 顯示可提款佣金餘額 2. 輸入金額驗證(不超過餘額) 3. 建立代理提款訂單 4. 訂單狀態為 pending 5. 代理餘額凍結對應金額P1
TC-AFF-006聯盟資訊頁面1. 在代理中心查看「聯盟資訊」1. 顯示代理等級資訊(agent-tier) 2. 顯示佣金費率表(按等級 x 遊戲類型) 3. 顯示 VIP 里程碑獎勵列表 4. 公開 API 資料正確P2
TC-AFF-007推薦碼管理1. 進入代理中心 2. 查看「推薦碼管理」1. 顯示已建立的推薦碼列表(含短碼和連結) 2. 可新增推薦碼(最多 10 個) 3. 可刪除推薦碼 4. 每個推薦碼可追蹤點擊數 5. 超過 10 個 → 顯示上限提示P1
TC-AFF-008非代理用戶存取1. 使用非代理身分帳號 2. 嘗試存取代理中心頁面1. 顯示代理申請頁面或提示 2. 無法查看代理資料 3. 提供申請成為代理的入口P2

2.10 任務系統測試

前置條件

  • 已登入狀態
  • 有進行中的任務
TC-ID測試說明測試步驟預期結果優先級
TC-MISSION-001任務列表顯示1. 進入任務頁面 2. 檢查任務列表1. 分類顯示每日/每週/每月任務 2. 每個任務含名稱、描述、獎勵金額 3. 顯示任務條件(存款/投注金額) 4. 顯示任務有效期P1
TC-MISSION-002進度條正確更新1. 查看某個投注任務的進度 2. 進行一筆投注 3. 返回任務頁面檢查進度1. 進度條百分比更新 2. 已完成/總量數字更新 3. 投注後自動連動更新(無需手動刷新)P1
TC-MISSION-003領取已完成任務獎勵1. 完成一個任務(進度 100%) 2. 點擊「領取」按鈕1. 獎勵金額加入帳戶餘額 2. 任務狀態變為「已領取」 3. mission-claim 表寫入紀錄 4. 不可重複領取P1
TC-MISSION-004未完成任務無法領取1. 查看進度未達 100% 的任務 2. 嘗試點擊「領取」1. 領取按鈕為禁用狀態(disabled) 2. 或點擊後提示「任務尚未完成」 3. 不發放獎勵P2
TC-MISSION-005存款任務連動1. 查看存款任務進度 2. 完成一筆存款(審核通過) 3. 檢查任務進度1. 存款確認後自動更新存款任務進度 2. 金額正確累計 3. 達標後可領取獎勵P1
TC-MISSION-006每日任務重置1. 完成並領取今日任務 2. 等待隔日(或調整系統時間) 3. 檢查任務列表1. 每日任務進度重置為 0 2. 可重新完成 3. 領取狀態重置P2

2.11 站內信測試

前置條件

  • 已登入狀態
TC-ID測試說明測試步驟預期結果優先級
TC-INBOX-001通知列表載入1. 點擊導航列的通知圖示 2. 檢查通知列表1. 列出所有站內信 2. 按時間倒序排列 3. 未讀與已讀視覺區分 4. 顯示發送時間P1
TC-INBOX-002點擊標記已讀1. 在通知列表中 2. 點擊一封未讀通知1. 通知內容展開/跳轉至詳情 2. 該通知狀態變為已讀 3. notification-read 表寫入紀錄 4. 未讀計數減 1P1
TC-INBOX-003未讀計數 Badge1. 有未讀通知時 2. 檢查導航列通知圖示1. 顯示紅色數字 Badge 2. 數字為未讀通知數量 3. 全部已讀後 Badge 消失 4. 新通知即時更新計數P2
TC-INBOX-004多語系通知內容1. 切換語系至 en-US 2. 查看通知列表 3. 切回 zh-TW 查看1. 通知標題/內容依當前語系顯示 2. 若通知有多語系版本則切換 3. 若無對應語系則使用預設語系P3
TC-INBOX-005通知分頁1. 有大量通知(20+) 2. 捲動或翻頁1. 支援分頁或無限捲動載入 2. 資料正確載入 3. 不重複顯示P3

2.12 KYC 測試

前置條件

  • 已登入狀態
  • 帳號未完成 KYC 驗證
TC-ID測試說明測試步驟預期結果優先級
TC-KYC-001步驟一:基本資料填寫1. 進入 KYC 驗證頁面 2. 填寫基本資料(姓名、生日、地址等) 3. 點擊「下一步」1. 表單驗證通過 2. 資料暫存 3. 進入步驟二 4. 必填欄位未填寫 → 驗證攔截P1
TC-KYC-002步驟二:證件上傳1. 在步驟二頁面 2. 上傳身份證正面/反面照片 3. 上傳自拍照1. 支援 JPG / PNG 格式 2. 檔案大小限制(如 5MB) 3. 預覽上傳圖片 4. 格式或大小不符 → 錯誤提示P1
TC-KYC-003步驟三:活體偵測1. 在步驟三頁面 2. 開啟攝影機 3. 依指示完成活體偵測1. 攝影機權限請求 2. 活體偵測指引顯示 3. 完成偵測後進入下一步 4. 偵測失敗 → 可重試P2
TC-KYC-004步驟四:確認送審1. 完成前三步驟 2. 確認資料無誤 3. 點擊「送審」1. 顯示所有已填資料摘要 2. 可返回修改 3. 送審後狀態變為「審核中」 4. 無法重複送審P1
TC-KYC-005進度保留1. 完成步驟一後離開頁面 2. 重新進入 KYC 頁面1. 自動跳到最後一個未完成步驟 2. 已填資料保留不遺失 3. 進度指示器正確顯示P2

2.13 主題切換測試

前置條件

  • 前台服務已啟動
TC-ID測試說明測試步驟預期結果優先級
TC-THEME-001主題選擇器顯示1. 開啟前台 2. 找到主題切換器(設定或個人選單中)1. 顯示 6 組預設主題選項 2. 每個主題有預覽色塊 3. 當前主題已選中標記P2
TC-THEME-002切換主題生效1. 選擇不同主題 2. 觀察頁面變化1. CSS 變數即時更新 2. 主色調(primary)變更 3. 強調色(accent)變更 4. 表面色(surface)變更 5. 文字色(text)變更 6. 邊框色(border)變更 7. 過渡動畫流暢P2
TC-THEME-003主題持久化1. 選擇某個主題 2. 重新載入頁面 3. 開新分頁1. 刷新後主題不還原 2. Cookie 中保存主題選擇 3. 新分頁也使用相同主題P2
TC-THEME-004主題與各頁面相容性1. 切換至非預設主題 2. 瀏覽各主要頁面1. 所有頁面配色協調 2. 文字對比度足夠(可閱讀) 3. 按鈕狀態(hover/active/disabled)明確 4. 無色彩衝突P3

2.14 多語系測試

前置條件

  • 前台服務已啟動
TC-ID測試說明測試步驟預期結果優先級
TC-I18N-001切換全部 5 種語系1. 依序切換至:zh-TW、en-US、zh-CN、th-TH、vi-VN 2. 每次切換後檢查頁面1. 每種語系都可正常切換 2. 無 Console 錯誤 3. 語系選擇器更新為當前語系 4. Cookie NEXT_LOCALE 正確設定P1
TC-I18N-002頁面文字更新1. 切換語系 2. 檢查:導航列、按鈕、表單標籤、提示訊息1. 所有可見文字都翻譯為對應語系 2. 無殘留其他語系文字 3. 無翻譯 key 直接顯示(如 common.saveP1
TC-I18N-003Locale Cookie 設定1. 切換語系至 en-US 2. 檢查 Cookie1. Cookie 名稱正確 2. Cookie 值為 en-US 3. 重新載入後語系維持 en-US 4. 策略為 no_prefix(URL 不顯示語系)P2
TC-I18N-004後端錯誤訊息語系1. 切換語系至 en-US 2. 觸發一個業務錯誤(如重複帳號註冊) 3. 檢查錯誤訊息1. 錯誤訊息為英文 2. 後端根據 Request Header locales 返回對應語系訊息 3. 前端透過 ERROR_CODES 查表顯示P1
TC-I18N-005日期/數字格式化1. 切換不同語系 2. 檢查日期和金額顯示1. zh-TW:2026/03/01、$1,234.56 2. en-US:03/01/2026、$1,234.56 3. 各語系遵循當地格式慣例 4. 數字千分位分隔正確P3
TC-I18N-006站點語系限制1. 若站點 supportedLocales 僅支援部分語系 2. 嘗試切換至不支援的語系1. 不支援的語系在切換器中隱藏或禁用 2. 直接修改 Cookie 至不支援語系 → 自動導向預設語系 3. localeGuard 正確運作P2

2.15 響應式設計測試

前置條件

  • 使用 Chrome DevTools Device Toolbar 模擬各種螢幕尺寸
TC-ID測試說明測試步驟預期結果優先級
TC-RWD-001手機版(320px)1. 設定螢幕寬度 320px 2. 瀏覽首頁、遊戲大廳、存款、個人中心1. 佈局正確不溢出 2. 文字不被截斷(重要資訊) 3. 按鈕可點擊(touch target >= 44px) 4. 無水平捲動條 5. 圖片自適應縮放P1
TC-RWD-002平板版(768px)1. 設定螢幕寬度 768px 2. 瀏覽各主要頁面1. 佈局切換為平板模式 2. 側邊欄可收合 3. 內容區域利用更多空間 4. 表格可能需要水平捲動P2
TC-RWD-003桌面版(1280px)1. 設定螢幕寬度 1280px 2. 瀏覽各主要頁面1. 完整佈局顯示 2. 側邊欄永久顯示 3. 內容居中或最大寬度限制 4. 所有功能可正常操作P1
TC-RWD-004底部導航列(手機)1. 設定螢幕寬度 375px 2. 檢查底部導航列 3. 設定 1024px 檢查1. 手機版顯示底部導航列 2. 桌面版隱藏底部導航列 3. 切換斷點正確(通常 768px)P2
TC-RWD-005側邊欄覆蓋(手機)1. 手機版模式 2. 開啟側邊欄(漢堡選單) 3. 與側邊欄互動1. 側邊欄以覆蓋模式出現 2. 背景遮罩顯示 3. 點擊遮罩關閉側邊欄 4. 側邊欄滑入/滑出動畫流暢P2
TC-RWD-006橫向模式(手機)1. 設定螢幕為手機橫向(667x375) 2. 瀏覽各頁面1. 佈局正確適配 2. 遊戲 iframe 佔滿可用空間 3. 表單可正常操作P3

第 3 章:後台測試案例 (c9-ims)

測試對象http://localhost:3011框架:Next.js 16 (React 19 + TypeScript) 支援語系:zh-TW, en-US, zh-CN, th-TH, vi-VN 認證方式:NextAuth 5 beta (JWT 策略 + Credentials Provider)


3.1 登入與 2FA 測試

前置條件

  • 後台服務已啟動 (port 3011)
  • 後端 API 服務已啟動 (port 8080)
  • 已有管理員 Seed 資料
TC-ID測試說明測試步驟預期結果優先級
TC-ADMIN-LOGIN-001管理員正常登入1. 開啟 http://localhost:3011 2. 輸入帳號:root_admin 3. 輸入密碼:Admin123456 4. 點擊「登入」1. 登入成功 2. 跳轉至 Dashboard 頁面 3. Header 顯示管理員名稱 4. 側邊欄導航完整顯示 5. AdminJWT Token 正確取得P1
TC-ADMIN-LOGIN-002錯誤密碼登入1. 輸入正確帳號 2. 輸入錯誤密碼 3. 點擊「登入」1. 顯示錯誤訊息 2. 停留在登入頁面 3. 登入失敗紀錄寫入資料庫 4. 密碼欄位清空P1
TC-ADMIN-LOGIN-003空白欄位提交1. 不填寫帳號密碼 2. 點擊「登入」1. 表單驗證攔截 2. 顯示必填欄位提示 3. 不發送 API 請求P2
TC-ADMIN-LOGIN-0042FA 啟用流程1. 登入後進入個人資料頁 2. 點擊「啟用 Google Authenticator」 3. 掃描 QR Code 4. 輸入 6 位驗證碼 5. 確認啟用1. 顯示 QR Code 和 Secret 字串 2. 對話框狀態:idle → qr → verify 3. 輸入正確 TOTP → 啟用成功 4. 輸入錯誤 TOTP → 提示錯誤 5. 啟用後下次登入需 2FAP1
TC-ADMIN-LOGIN-0052FA 停用流程1. 已啟用 2FA 的管理員登入 2. 進入個人資料頁 3. 點擊「停用 Google Authenticator」 4. 輸入當前 TOTP 驗證碼1. 需驗證當前 TOTP 才能停用 2. 驗證通過 → 2FA 停用成功 3. 下次登入不再要求 2FA 4. 驗證失敗 → 無法停用P1
TC-ADMIN-LOGIN-0062FA 登入驗證1. 使用已啟用 2FA 的帳號 2. 輸入正確帳密 3. 系統要求 TOTP 4. 輸入 Google Authenticator 產生的 6 位碼1. 帳密正確後顯示 TOTP 輸入介面 2. 正確 TOTP → 登入成功 3. 錯誤 TOTP → 提示驗證失敗 4. TOTP 30 秒更新,前後各一個有效P1
TC-ADMIN-LOGIN-007登出功能1. 已登入狀態 2. 點擊右上角登出1. Session 清除 2. Token 失效 3. 跳轉至登入頁面 4. 無法直接存取管理頁面P1
TC-ADMIN-LOGIN-008Session 過期1. 登入後等待 Session 過期 2. 嘗試操作1. API 回傳 401 2. 自動清除 Token 3. 重導向至登入頁面 4. 顯示 Session 過期提示P1
TC-ADMIN-LOGIN-009未授權存取1. 未登入狀態 2. 直接存取 http://localhost:3011/dashboard1. 自動重導向至登入頁面 2. 登入後跳回原頁面P1
TC-ADMIN-LOGIN-010個人資料修改1. 登入後進入個人資料 2. 修改暱稱/密碼 3. 儲存1. 修改成功顯示 Toast 通知 2. 資料庫更新 3. Header 顯示新暱稱 4. 若修改密碼需重新登入P2

3.2 多站點切換測試

前置條件

  • 已登入管理員帳號
  • Seed 資料含多個站點(C9, A1, B2, D3, E4)
TC-ID測試說明測試步驟預期結果優先級
TC-SITE-001全部站點模式 — SiteTabs 顯示1. 在 Header 的 SiteSelector 選擇「全部站點」 2. 進入任一支援多站點的頁面(如玩家列表)1. 頁面頂部出現 SiteTabs 2. 每個站點一個 Tab(C9, A1, B2...) 3. 預設選中第一個 Tab 4. Tab 上顯示站點名稱P1
TC-SITE-002獨立站點模式 — 資料篩選1. 在 SiteSelector 選擇某站點(如 A1) 2. 進入玩家列表頁面1. SiteTabs 僅顯示一個 Tab (A1) 2. 資料自動篩選為 A1 站的資料 3. API 請求 Header 帶有 x-site-code: A1 4. 不顯示其他站點資料P1
TC-SITE-003站點切換資料刷新1. 在「全部站點」模式下查看玩家列表 2. Header 切換到「A1」站 3. 再切回「全部站點」1. 每次切換 AdminContentWrapper 重新掛載(key 變更) 2. 頁面資料完全重新載入 3. TanStack Query cache 被清除 4. 無殘留舊站點資料P1
TC-SITE-004SiteTabs 點擊切換1. 選擇「全部站點」 2. 進入有 SiteTabs 的頁面 3. 依序點擊各 Tab1. 點擊 Tab 後資料切換為該站點 2. API 請求帶入對應 siteCode 3. 分頁重置為第一頁 4. 篩選條件保留P1
TC-SITE-005SiteSelector 隱藏頁面1. 進入管理員列表頁面 (/system/admins) 2. 進入群組管理頁面 (/system/groups) 3. 進入操作紀錄頁面 (/system/logs)1. 以上三個頁面 Header 不顯示 SiteSelector 2. 這些頁面為全站共用設定 3. 資料不區分站點P2
TC-SITE-006Query Cache 清除1. 在 A1 站查看玩家列表 2. 切換至 B2 站 3. 切回 A1 站1. 每次切換清除 TanStack Query cache 2. 不使用舊的快取資料 3. 重新發送 API 請求 4. 資料一致性保證P2
TC-SITE-007站點初始化流程1. 重新載入後台頁面 2. 觀察 Network 請求1. SiteFilterInitializer 發送 /site-config/admin/list 請求 2. 站點列表正確填入 siteFilterStore 3. SiteSelector 下拉選單包含所有站點 4. 預設選擇「全部站點」或上次選擇(sessionStorage)P2
TC-SITE-008站點資料隔離(列表)1. 在「全部站點」模式切換到 C9 Tab 2. 記錄玩家數量 3. 切換到 A1 Tab 4. 記錄玩家數量1. 各站點玩家數量不同 2. C9 站不顯示 A1 的玩家 3. 與資料庫實際資料一致 4. 分頁總數正確P1

3.3 權限管理測試

前置條件

  • 有不同群組的管理員帳號(root / super_admin / general_admin / custom)
TC-ID測試說明測試步驟預期結果優先級
TC-PERM-001Root 用戶全權限1. 以 root_admin 登入 2. 檢查側邊欄選單 3. 嘗試存取所有頁面1. 側邊欄顯示所有 14+ 選單群組 2. 所有頁面可正常存取 3. 所有 CRUD 操作可執行 4. 包含站點設定(site-config)P1
TC-PERM-002Super Admin 權限1. 以 super_admin 登入 2. 檢查側邊欄選單1. 顯示大部分選單 2. 「站點設定」相關頁面不顯示 3. 其他功能可正常操作P1
TC-PERM-003General Admin 唯讀1. 以 general_admin 登入 2. 嘗試編輯操作(如修改玩家資料)1. 可查看列表和詳情 2. 新增/編輯/刪除按鈕隱藏或禁用 3. 直接呼叫 API 也被後端 Guard 擋下 4. 顯示「無權限」提示P1
TC-PERM-004Custom 群組自訂權限1. 以 custom_admin 登入 2. 該群組僅有 user:readdeposit:read 權限 3. 檢查側邊欄1. 僅顯示玩家管理和存款相關選單 2. 其他選單隱藏 3. 直接存取無權限頁面 → 顯示 AccessDenied 元件P1
TC-PERM-005無權限頁面顯示1. 以受限帳號登入 2. 直接輸入無權限頁面的 URL 3. 嘗試存取1. 顯示 AccessDenied 元件 2. 提示「您沒有權限存取此頁面」 3. 不洩漏頁面內容 4. 提供返回首頁連結P1
TC-PERM-006寫入操作權限阻擋1. 以 general_admin(唯讀)登入 2. 使用開發者工具直接呼叫寫入 API 3. 觀察回應1. 後端 PermissionsGuard 攔截 2. 回傳 403 Forbidden 3. 操作不執行 4. 操作紀錄記錄此次嘗試P1
TC-PERM-007權限模組列表1. 以 root 登入 2. 進入群組管理 3. 查看權限勾選列表1. 顯示 16 個權限模組 2. 每個模組含 read/write 權限 3. 模組:admin, admin-group, admin-log, user, deposit, withdrawal, promo, promo-tag, affiliate, vip, game, risk, report, vendor, finance, site-configP2
TC-PERM-008動態權限更新1. 以 root 登入修改 custom 群組權限 2. 以 custom_admin 重新登入 3. 檢查可存取頁面1. 權限修改立即生效 2. 新增的權限對應選單出現 3. 移除的權限對應選單消失 4. 不需重新部署P2

3.4 系統管理測試

3.4.1 管理員管理

前置條件

  • 以 root 或有 admin:write 權限的帳號登入
TC-ID測試說明測試步驟預期結果優先級
TC-SYS-ADMIN-001管理員列表顯示1. 進入系統管理 > 管理員列表 2. 檢查列表內容1. 顯示所有管理員(不區分站點) 2. 含帳號、暱稱、群組、狀態、建立時間 3. 支援分頁 4. SiteSelector 不顯示P1
TC-SYS-ADMIN-002新增管理員1. 點擊「新增管理員」 2. 填寫帳號、密碼、暱稱 3. 選擇群組 4. 提交1. 表單驗證通過 2. 管理員建立成功 3. Toast 通知「新增成功」 4. 列表刷新 5. 新管理員可登入P1
TC-SYS-ADMIN-003編輯管理員1. 在列表中點擊某管理員的「編輯」 2. 修改暱稱或群組 3. 儲存1. 彈出編輯對話框或跳轉 2. 顯示當前資訊 3. 修改成功更新列表 4. 不可修改帳號P1
TC-SYS-ADMIN-004停用管理員1. 對某管理員點擊「停用」 2. 確認操作1. 確認對話框顯示 2. 停用後狀態變更 3. 被停用管理員無法登入 4. 列表狀態標籤更新P1
TC-SYS-ADMIN-005刪除管理員1. 對某管理員點擊「刪除」 2. 確認刪除1. 確認對話框(variant: destructive) 2. 刪除後從列表消失 3. 不可刪除自己 4. 不可刪除最後一個 root 管理員P1

3.4.2 群組管理

TC-ID測試說明測試步驟預期結果優先級
TC-SYS-GROUP-001群組列表顯示1. 進入系統管理 > 群組管理1. 顯示所有群組 2. 含群組名稱、類型、成員數、權限數 3. 預設群組:root / super_admin / general_adminP1
TC-SYS-GROUP-002新增自訂群組1. 點擊「新增群組」 2. 輸入群組名稱 3. 勾選權限 4. 提交1. 群組建立成功 2. 權限列表正確勾選 3. 可分配給管理員 4. 類型為 customP1
TC-SYS-GROUP-003編輯群組權限1. 點擊 custom 群組「編輯」 2. 修改權限勾選 3. 儲存1. 權限修改成功 2. 影響該群組所有管理員 3. 不可編輯預設群組(root / super_admin / general_admin)P1
TC-SYS-GROUP-004刪除群組1. 對無成員的自訂群組點擊「刪除」 2. 確認1. 刪除成功 2. 有成員的群組不可刪除(需先移除成員) 3. 預設群組不可刪除P2

3.4.3 操作紀錄

TC-ID測試說明測試步驟預期結果優先級
TC-SYS-LOG-001操作紀錄列表1. 進入系統管理 > 操作紀錄1. 顯示管理員操作紀錄 2. 含操作者、動作、模組、時間、IP 3. 按時間倒序 4. 不區分站點(全站共用)P2
TC-SYS-LOG-002篩選操作紀錄1. 使用日期範圍篩選 2. 使用管理員帳號篩選 3. 使用操作類型篩選1. 篩選結果正確 2. 多條件組合篩選有效 3. 分頁正確P2

3.4.4 站點設定

TC-ID測試說明測試步驟預期結果優先級
TC-SYS-SITE-001站點列表顯示1. 進入系統管理 > 站點設定1. 顯示所有站點(C9, A1...) 2. 含站點代碼、名稱、狀態 3. 含主題配置預覽P1
TC-SYS-SITE-002新增站點1. 點擊「新增站點」 2. 填寫站點代碼、名稱等 3. 提交1. 站點建立成功 2. 自動出現在 SiteSelector 下拉 3. siteCode 唯一不重複P1
TC-SYS-SITE-003編輯站點設定1. 點擊某站點「編輯」 2. 修改站點名稱或設定 3. 儲存1. 設定更新成功 2. 影響前台顯示 3. features 開關正確生效P1
TC-SYS-SITE-004刪除站點1. 刪除非預設站點 2. 確認操作1. 確認對話框(含 cascade 提醒) 2. 站點刪除 3. 相關主題 cascade 刪除 4. 預設站點不可刪除P1

3.4.5 客服配置

TC-ID測試說明測試步驟預期結果優先級
TC-SYS-CS-001客服管道設定1. 進入系統管理 > 客服配置 2. 選擇站點 Tab1. 顯示 8 種客服管道設定(line / telegram / wechat / facebook / instagram / twitter / discord / custom) 2. 每管道含 label、link、icon、sortOrder、enabled 3. 支援多語系 labelP1
TC-SYS-CS-002編輯客服管道1. 修改某管道的連結和標籤 2. 切換啟用/停用 3. 儲存1. 修改成功 2. 前台即時反映(客服浮動按鈕) 3. 停用的管道在前台隱藏P1
TC-SYS-CS-003LiveChat 設定1. 啟用 LiveChat 功能 2. 輸入嵌入腳本 3. 儲存1. LiveChat 開關獨立 2. 腳本正確儲存 3. 前台載入 LiveChat WidgetP2
TC-SYS-CS-004同預設站點複製1. 在非預設站 Tab 點擊「同預設站點」 2. 確認複製1. 預設站客服設定複製至當前站 2. 前端狀態拷貝(需手動儲存) 3. 不影響預設站設定P2

3.4.6 域名設置

TC-ID測試說明測試步驟預期結果優先級
TC-SYS-DOMAIN-001域名列表顯示1. 進入系統管理 > 域名設置 2. 選擇站點1. 顯示各站點域名配置 2. 含 hostname、Logo(大/小)、Favicon 3. 含支援語系列表P1
TC-SYS-DOMAIN-002上傳域名素材1. 點擊上傳 Logo 或 Favicon 2. 選擇圖片檔案1. 圖片上傳至 R2 2. 預覽正確顯示 3. 支援 logoSmall / logoBig / faviconP1
TC-SYS-DOMAIN-003同預設站點複製1. 在非預設站點擊「同預設站點」1. 複製時保留 hostname 和 supportedLocales 2. 同步 Logo、Favicon 等素材 3. 直接 API 寫入P2

3.4.7 三方登入配置

TC-ID測試說明測試步驟預期結果優先級
TC-SYS-OAUTH-001OAuth 設定顯示1. 進入系統管理 > 三方登入 2. 選擇站點 Tab1. 顯示 Google / Telegram OAuth 設定 2. 含 Client ID、Client Secret、啟用狀態P1
TC-SYS-OAUTH-002修改 OAuth 設定1. 修改 Google OAuth 的 Client ID 2. 切換啟用狀態 3. 儲存1. 設定更新成功 2. 前台 OAuth 按鈕隨啟用/停用顯示/隱藏P1

3.4.8 雲端儲存

TC-ID測試說明測試步驟預期結果優先級
TC-SYS-R2-001檔案列表顯示1. 進入系統管理 > 雲端儲存 2. 選擇站點 Tab1. 顯示 R2 儲存空間的檔案/資料夾列表 2. 含檔名、大小、類型、修改時間 3. 支援資料夾導航P2
TC-SYS-R2-002上傳檔案1. 點擊「上傳」 2. 選擇檔案 3. 確認上傳1. 檔案上傳至 R2 2. 列表即時更新 3. 操作紀錄寫入 r2-operation-logP2
TC-SYS-R2-003建立資料夾1. 點擊「新增資料夾」 2. 輸入資料夾名稱1. 資料夾建立成功 2. 列表顯示新資料夾P3
TC-SYS-R2-004刪除檔案1. 選擇檔案 2. 點擊「刪除」 3. 確認1. 檔案從 R2 移除 2. 列表更新 3. 操作紀錄寫入P2
TC-SYS-R2-005移動檔案1. 選擇檔案 2. 選擇目標資料夾 3. 確認移動1. 檔案移至新位置 2. 原位置不再顯示 3. 新位置正確顯示P3

3.4.9 雲端儲存日誌

TC-ID測試說明測試步驟預期結果優先級
TC-SYS-R2LOG-001日誌列表顯示1. 進入系統管理 > 雲端儲存日誌1. 顯示 R2 操作紀錄 2. 含操作類型(上傳/刪除)、檔案名、操作者 3. 解析 OS / 瀏覽器(UA 解析) 4. 含 mimeType 資訊P2
TC-SYS-R2LOG-002日誌詳情1. 點擊某筆紀錄的「詳情」1. 顯示 Detail Dialog 2. 完整 User-Agent 字串 3. 操作時間、IP 等完整資訊P3

3.4.10 佈局配置

TC-ID測試說明測試步驟預期結果優先級
TC-SYS-LAYOUT-001底部導航列配置1. 進入系統管理 > 底部導航列 2. 選擇站點 Tab1. 顯示前台行動版底部 Tab 項目 2. 可新增/刪除/排序項目 3. 各項目含 icon、label、linkP2
TC-SYS-LAYOUT-002頁尾配置1. 進入系統管理 > 頁尾配置1. 顯示前台頁尾設定 2. 可設定連結、版權資訊 3. 支援多語系P3
TC-SYS-LAYOUT-003了解更多配置1. 進入系統管理 > 了解更多1. 顯示「了解更多」區塊配置 2. 可設定內容和連結 3. 支援多語系P3

3.5 玩家管理測試

3.5.1 全部玩家

TC-ID測試說明測試步驟預期結果優先級
TC-PLAYER-001玩家列表顯示1. 進入玩家管理 > 全部玩家 2. 選擇站點 Tab1. 顯示當前站點的玩家列表 2. 含帳號、暱稱、VIP 等級、餘額、狀態、註冊時間 3. 支援分頁 4. SiteTabs 正確運作P1
TC-PLAYER-002關鍵字搜尋1. 在 FilterBar 輸入帳號關鍵字 2. 點擊搜尋1. 列表篩選為匹配結果 2. 支援帳號/暱稱/Email 模糊搜尋 3. 無結果 → 顯示空狀態P1
TC-PLAYER-003VIP 等級篩選1. 在 FilterBar 選擇 VIP 等級 2. 搜尋1. 僅顯示該 VIP 等級的玩家 2. VIP 等級下拉選項動態取得(不硬編碼) 3. 結果正確P2
TC-PLAYER-004玩家詳情頁1. 點擊某玩家的帳號連結 2. 進入詳情頁 [id]1. 顯示完整玩家資料 2. 含基本資訊、餘額、VIP、投注統計 3. 含銀行卡/信用卡/加密地址列表 4. 含登入紀錄P1
TC-PLAYER-005編輯玩家資料1. 在玩家詳情頁點擊「編輯」 2. 修改部分欄位 3. 儲存1. 可修改暱稱、狀態等欄位 2. 不可修改帳號 3. 修改成功更新顯示 4. 操作紀錄寫入P1
TC-PLAYER-006日期範圍篩選1. 設定註冊日期範圍 2. 搜尋1. 僅顯示該日期範圍內註冊的玩家 2. 開始/結束日期選擇器正確 3. 結果正確排序P2

3.5.2 新註冊玩家

TC-ID測試說明測試步驟預期結果優先級
TC-PLAYER-NEW-001新註冊列表1. 進入玩家管理 > 新註冊玩家 2. 選擇站點 Tab1. 顯示近期新註冊玩家 2. 預設顯示今日/近 7 天註冊 3. 含註冊來源(直接/推薦碼)P1
TC-PLAYER-NEW-002VIP 篩選1. 選擇 VIP 等級篩選1. VIP 等級下拉選項動態取得 2. 篩選結果正確P2

3.5.3 線上玩家

TC-ID測試說明測試步驟預期結果優先級
TC-PLAYER-ONLINE-001線上玩家列表1. 進入玩家管理 > 線上玩家1. 顯示當前在線玩家 2. 含帳號、VIP、最後活動時間、IP 3. 資料即時更新P2

3.5.4 登入失敗紀錄

TC-ID測試說明測試步驟預期結果優先級
TC-PLAYER-FAIL-001登入失敗紀錄列表1. 進入玩家管理 > 登入失敗紀錄 2. 選擇站點 Tab1. 顯示登入失敗紀錄 2. 含帳號、IP、時間、失敗原因 3. 支援關鍵字和日期篩選P2
TC-PLAYER-FAIL-002日期篩選1. 設定日期範圍 2. 搜尋1. 僅顯示日期範圍內的紀錄 2. 結果正確P3

3.6 活動管理測試

3.6.1 優惠活動列表

TC-ID測試說明測試步驟預期結果優先級
TC-PROMO-001活動列表顯示1. 進入活動管理 > 優惠活動 2. 選擇站點 Tab1. 顯示當前站點的活動列表 2. 含標題、狀態、開始/結束日期、類型 3. 支援分頁P1
TC-PROMO-002新增活動1. 點擊「新增活動」 2. 填寫標題(多語系)、描述 3. 使用 Tiptap 編輯器編寫內容 4. 上傳活動圖片 5. 設定條件(如最低存款、打碼量) 6. 提交1. 多語系標題正確儲存 2. HTML 內容正確儲存 3. 圖片上傳至 R2 4. 條件規則正確設定 5. 活動建立成功,出現在列表中P1
TC-PROMO-003編輯活動1. 點擊某活動的「編輯」 2. 修改標題或內容 3. 儲存1. 編輯頁載入正確資料 2. Tiptap 編輯器正確渲染既有 HTML 3. 修改成功更新P1
TC-PROMO-004啟用/停用活動1. 切換活動的啟用狀態1. 狀態切換成功 2. 停用的活動在前台不顯示 3. 啟用後前台重新顯示P1
TC-PROMO-005刪除活動1. 對活動點擊「刪除」 2. 確認1. 確認對話框顯示 2. 刪除成功 3. 列表更新 4. 相關領取紀錄保留(軟刪除)P2

3.6.2 活動標籤

TC-ID測試說明測試步驟預期結果優先級
TC-PROMO-TAG-001標籤列表1. 進入活動管理 > 活動標籤 2. 選擇站點 Tab1. 顯示活動分類標籤列表 2. 含名稱、排序、使用數量P2
TC-PROMO-TAG-002CRUD 操作1. 新增標籤 2. 編輯標籤名稱 3. 刪除未使用的標籤1. 各操作正確執行 2. 已使用的標籤不可刪除 3. 新標籤可在活動編輯時選擇P2

3.7 財務管理測試

3.7.1 人工調節金額

TC-ID測試說明測試步驟預期結果優先級
TC-FIN-ADJUST-001調帳表單1. 進入財務管理 > 人工調帳 2. 選擇站點 Tab 3. 搜尋用戶 4. 輸入調整金額(正值增加/負值減少) 5. 填寫原因 6. 確認提交1. 用戶搜尋功能(帶 siteCode) 2. 金額驗證(decimal 精度) 3. 調帳成功更新用戶餘額 4. 操作紀錄寫入 5. Toast 通知P1
TC-FIN-ADJUST-002負值調帳超額1. 輸入負值超過用戶餘額 2. 提交1. 後端拒絕(餘額不足) 2. 顯示錯誤訊息 3. 餘額不變P1

3.7.2 存款設置

TC-ID測試說明測試步驟預期結果優先級
TC-FIN-DEPSETTING-001金流群組/通道1. 進入財務管理 > 存款設置 2. 選擇站點 Tab1. 顯示金流群組列表 2. 每群組下含通道列表 3. 按站點篩選P1
TC-FIN-DEPSETTING-002通道啟停1. 切換某通道啟用狀態1. 通道啟停即時生效 2. 停用後前台不顯示該通道P1

3.7.3 存款審核

TC-ID測試說明測試步驟預期結果優先級
TC-FIN-DEPOSIT-001存款訂單列表1. 進入財務管理 > 存款審核 2. 選擇站點 Tab1. 顯示存款訂單列表 2. 含訂單編號、用戶、金額(USD)、狀態、通道、時間 3. 支援多條件篩選:訂單ID、用戶ID、關鍵字、支付方式、狀態、日期P1
TC-FIN-DEPOSIT-002審核通過1. 選擇 pending 狀態訂單 2. 點擊「通過」 3. 確認1. 訂單狀態變為 approved 2. 用戶餘額增加(USD 金額) 3. 操作紀錄寫入 4. 列表即時更新P1
TC-FIN-DEPOSIT-003審核拒絕1. 選擇 pending 訂單 2. 點擊「拒絕」 3. 輸入拒絕原因 4. 確認1. 訂單狀態變為 rejected 2. 用戶餘額不變 3. 拒絕原因寫入P1
TC-FIN-DEPOSIT-004篩選組合1. 同時設定狀態 + 日期 + 關鍵字篩選 2. 搜尋1. 三個條件同時生效 2. 結果正確 3. 分頁總數正確P2

3.7.4 提款管理

TC-ID測試說明測試步驟預期結果優先級
TC-FIN-WD-001提款列表1. 進入財務管理 > 提款管理 2. 選擇站點 Tab1. 顯示提款訂單列表 2. 含訂單ID、狀態、用戶ID、金額、提款方式 3. 篩選:訂單ID、狀態、用戶ID、關鍵字、網路、日期P1
TC-FIN-WD-002審核通過1. 選擇 pending 提款 2. 點擊「核准」1. 狀態變為 approved 2. 凍結餘額不變(等待完成)P1
TC-FIN-WD-003上傳轉帳憑證1. 對 approved 訂單上傳憑證1. 圖片上傳至 R2 2. 憑證連結寫入訂單P2
TC-FIN-WD-004標記完成1. 對 approved 訂單點擊「完成」1. 狀態變為 completed 2. 凍結餘額釋放(扣除) 3. 完整提款流程結束P1
TC-FIN-WD-005審核拒絕1. 拒絕 pending 提款1. 狀態變為 rejected 2. 凍結餘額退回可用餘額 3. 用戶總餘額不變P1

3.7.5 銀行卡管理

TC-ID測試說明測試步驟預期結果優先級
TC-FIN-BANK-001銀行卡列表1. 進入財務管理 > 銀行卡列表 2. 選擇站點 Tab1. 顯示銀行卡列表 2. 篩選:關鍵字、用戶ID、狀態、銀行代碼、持卡人、日期 3. SiteTabs 正確P1
TC-FIN-BANK-002審核銀行卡1. 對 pending 銀行卡點擊「審核」 2. 選擇通過或拒絕1. 通過 → 用戶可用此卡提款 2. 拒絕 → 卡片不可用 3. 狀態標籤更新P1

3.7.6 信用卡管理

TC-ID測試說明測試步驟預期結果優先級
TC-FIN-CREDIT-001信用卡列表與審核同銀行卡管理模式,篩選:關鍵字、用戶ID、狀態、持卡人、日期同銀行卡管理預期結果P1

3.7.7 加密地址管理

TC-ID測試說明測試步驟預期結果優先級
TC-FIN-CRYPTO-001加密地址列表與審核同銀行卡管理模式,篩選:關鍵字、用戶ID、狀態、網路、幣種、日期同銀行卡管理預期結果,額外含鏈類型(TRC-20/ERC-20)篩選P1

3.8 遊戲管理測試

3.8.1 遊戲供應商

TC-ID測試說明測試步驟預期結果優先級
TC-GAME-PROV-001供應商列表1. 進入遊戲管理 > 遊戲供應商 2. 選擇站點 Tab1. 顯示當前站點的供應商列表 2. 含 providerCode、名稱、gameType、狀態 3. SiteTabs + siteCode 篩選P1
TC-GAME-PROV-002新增供應商1. 點擊「新增」 2. 填寫資訊 3. 提交1. 供應商建立成功 2. siteCode 自動帶入當前站點 3. 列表更新P1
TC-GAME-PROV-003編輯供應商1. 點擊「編輯」 2. 修改欄位 3. 儲存1. 更新成功 2. 不可修改 providerCode 3. 列表即時反映P1
TC-GAME-PROV-004刪除供應商1. 刪除供應商 2. 確認1. 確認對話框 2. 刪除成功 3. 相關遊戲資料影響評估P2
TC-GAME-PROV-005同預設站點(API 複製)1. 在非預設站 Tab 2. 點擊「同預設站點」 3. 確認1. 確認對話框顯示 source → target 站點 2. 呼叫 POST /game/admin/copy-site-data type=providers 3. Transaction 內先刪後插 4. 列表重新載入 5. 僅目標站點受影響P1
TC-GAME-PROV-006帶入模板1. 點擊「帶入模板」 2. 預覽模板內容(可編輯) 3. 確認帶入1. templatePreviewDialog 顯示預設供應商 2. 可修改後再確認 3. 依 AdminSiteCode 寫入指定站點 4. 列表更新P1

3.8.2 遊戲分類設定

TC-ID測試說明測試步驟預期結果優先級
TC-GAME-TYPE-001分類列表1. 進入遊戲管理 > 遊戲分類 2. 選擇站點 Tab1. 顯示 8 種遊戲分類設定 2. 含類型代碼、名稱、排序、狀態P1
TC-GAME-TYPE-002CRUD 操作1. 新增/編輯/刪除分類1. 各操作正確(同供應商模式) 2. gameType 正確(1-10 對應表)P1
TC-GAME-TYPE-003同預設站點同供應商模式,type=typeConfigs同供應商預期P1
TC-GAME-TYPE-004帶入模板同供應商模式同供應商預期P1

3.9 VIP 管理測試

3.9.1 VIP 等級

TC-ID測試說明測試步驟預期結果優先級
TC-VIP-LEVEL-001等級列表1. 進入 VIP 管理 > VIP 等級 2. 選擇站點 Tab1. 顯示各 VIP 等級設定 2. 含等級、名稱、門檻、福利 3. 等級數量由後端決定(不限 15 級)P1
TC-VIP-LEVEL-002新增等級1. 點擊「新增等級」 2. 設定門檻和福利 3. 提交1. 等級建立成功 2. 自動排序 3. 前台 VIP 頁面更新P1
TC-VIP-LEVEL-003編輯等級1. 修改某等級門檻 2. 儲存1. 門檻更新 2. 不影響已達此等級的用戶P1
TC-VIP-LEVEL-004同預設站點1. 非預設站 Tab 2. 點擊「同預設站點」1. POST /vip/admin/copy-site-data type=levels 2. 預設站等級複製至目標站 3. 目標站原有等級被取代P1
TC-VIP-LEVEL-005帶入模板1. 點擊「帶入模板」 2. 預覽並確認1. 模板預覽正確 2. 帶入後僅影響當前站 3. 等級設定更新P1

3.9.2 返水設定

TC-ID測試說明測試步驟預期結果優先級
TC-VIP-REBATE-001返水比例表1. 進入 VIP 管理 > 返水設定 2. 選擇站點 Tab1. 顯示 N 等級 x 8 遊戲類型的返水矩陣 2. 每個儲存格可內嵌編輯 3. 精度 decimal(5,2)P1
TC-VIP-REBATE-002行內編輯1. 直接點擊某個返水比例 2. 修改數值 3. Tab 到下一格1. 可直接在表格中修改 2. 修改即時顯示 3. 支援 Tab 切換輸入P1
TC-VIP-REBATE-003批次儲存1. 修改多個返水比例 2. 點擊「儲存」1. bulk upsert API 呼叫 2. 所有修改一次儲存 3. unique key: siteCode + level + gameType 4. 成功 Toast 通知P1
TC-VIP-REBATE-004同預設站點同 VIP 等級,type=rebates返水設定從預設站複製P1

3.9.3 VIP 玩家

TC-ID測試說明測試步驟預期結果優先級
TC-VIP-PLAYER-001VIP 玩家列表1. 進入 VIP 管理 > VIP 玩家 2. 選擇站點 Tab1. 顯示玩家 VIP 資訊 2. 含帳號、VIP 等級、累計投注、保級狀態 3. 支援篩選和排序P1

3.10 報表測試

3.10.1 總覽報表

TC-ID測試說明測試步驟預期結果優先級
TC-RPT-OVERVIEW-001總覽頁面1. 進入報表 > 總覽 2. 選擇站點 Tab(useMultiSiteTabs)1. 顯示統計卡片:總存款、總提款、總投注、活躍用戶等 2. 每日摘要表格 3. 支援日期範圍篩選P1
TC-RPT-OVERVIEW-002日期篩選1. 設定開始/結束日期 2. 搜尋1. 統計數據更新為指定日期範圍 2. 圖表/表格同步更新P1

3.10.2 玩家報表

TC-ID測試說明測試步驟預期結果優先級
TC-RPT-PLAYER-001玩家報表列表1. 進入報表 > 玩家報表 2. 選擇站點 Tab1. 顯示玩家統計資料 2. 篩選:關鍵字、VIP 等級(select 動態)、日期 3. 含存款/提款/投注總額P1
TC-RPT-PLAYER-002CSV 匯出1. 設定篩選條件 2. 點擊 ExportButton1. 下載 CSV 檔案 2. 資料與頁面顯示一致 3. 含所有欄位 4. 檔名含日期P2

3.10.3 投注紀錄

TC-ID測試說明測試步驟預期結果優先級
TC-RPT-BET-001投注紀錄列表1. 進入報表 > 投注紀錄 2. 選擇站點 Tab1. 顯示投注紀錄 2. 篩選:關鍵字、遊戲類型(select)、遊戲平台(select)、狀態、日期 3. 含投注/派彩金額(USD)P1
TC-RPT-BET-002遊戲類型篩選1. 選擇特定遊戲類型 2. 搜尋1. 僅顯示該類型投注 2. 類型選項完整(8 種)P2

3.10.4 遊戲報表

TC-ID測試說明測試步驟預期結果優先級
TC-RPT-GAME-001遊戲報表1. 進入報表 > 遊戲報表 2. 篩選遊戲類型/平台/日期1. 按遊戲類型或平台彙總 2. 含總投注、總派彩、利潤 3. 支援 CSV 匯出P1

3.10.5 損益報表

TC-ID測試說明測試步驟預期結果優先級
TC-RPT-PL-001損益報表1. 進入報表 > 損益報表 2. 選擇分組方式(日/週/月) 3. 選擇遊戲類型 4. 設定日期1. 按分組方式彙總損益 2. 含收入、支出、淨利 3. 數據正確(與其他報表交叉驗證)P1

3.10.6 玩家摘要

TC-ID測試說明測試步驟預期結果優先級
TC-RPT-SUMMARY-001玩家摘要1. 進入報表 > 玩家摘要 2. 篩選:關鍵字、VIP 等級、排序方式、排序方向、日期1. 顯示玩家綜合摘要 2. 支援排序(投注額/存款額等) 3. 支援 CSV 匯出P1

3.10.7 活動報表

TC-ID測試說明測試步驟預期結果優先級
TC-RPT-PROMO-001活動報表1. 進入報表 > 活動報表 2. 設定日期篩選1. 顯示活動領取統計 2. 含活動名稱、領取人數、發放金額 3. 目前尚未加入多站點P2

3.11 風控管理測試

3.11.1 IP 黑白名單

TC-ID測試說明測試步驟預期結果優先級
TC-RISK-IP-001IP 規則列表1. 進入風控管理 > IP 規則 2. 選擇站點 Tab1. 顯示 IP 黑白名單列表 2. 篩選:類型(黑/白名單)、IP 關鍵字、日期範圍 3. 含 IP、類型、備註、建立時間P1
TC-RISK-IP-002新增 IP 規則1. 點擊「新增」 2. 輸入 IP 地址 3. 選擇類型(黑名單/白名單) 4. 填寫備註 5. 提交1. 規則建立成功 2. 黑名單 IP 的用戶無法登入/操作 3. 白名單 IP 跳過風控檢查P1
TC-RISK-IP-003刪除 IP 規則1. 刪除某條 IP 規則1. 規則移除 2. 該 IP 不再被攔截/放行P1
TC-RISK-IP-004類型篩選1. 篩選僅顯示黑名單 2. 篩選僅顯示白名單1. 正確區分黑白名單 2. 結果正確P2

3.11.2 IP/FP 檢查

TC-ID測試說明測試步驟預期結果優先級
TC-RISK-LOOKUP-001IP 反查用戶1. 進入風控管理 > IP 檢查 2. 選擇站點 Tab 3. 輸入 IP 地址 4. 搜尋1. 顯示使用該 IP 登入的所有用戶 2. 含帳號、登入時間 3. 可識別共用 IP 的嫌疑帳號P1
TC-RISK-LOOKUP-002裝置指紋反查1. 輸入裝置指紋值 2. 搜尋1. 顯示使用該指紋的用戶 2. 可識別多重帳號嫌疑P1
TC-RISK-LOOKUP-003多條件搜尋1. 使用帳號/姓名/Email/手機搜尋1. FilterBar 支援多種搜尋條件 2. 結果按站點篩選P2

3.11.3 遊戲黑名單

TC-ID測試說明測試步驟預期結果優先級
TC-RISK-GAME-001遊戲黑名單列表1. 進入風控管理 > 遊戲黑名單 2. 選擇站點 Tab1. 顯示遊戲黑名單列表 2. 篩選:用戶ID、用戶帳號、遊戲類型、日期 3. 含封鎖類型(全封鎖/類型封鎖/特定遊戲封鎖)P1
TC-RISK-GAME-002新增遊戲黑名單1. 點擊「新增」 2. 選擇用戶 3. 選擇封鎖類型 4. 提交1. 全封鎖 → 用戶所有遊戲都無法啟動 2. 類型封鎖 → 特定遊戲類型無法啟動 3. 特定遊戲封鎖 → 單一遊戲無法啟動 4. 前台啟動遊戲回傳錯誤碼 5010P1
TC-RISK-GAME-003移除黑名單1. 刪除某條黑名單規則1. 用戶恢復遊戲存取 2. 即時生效P1

3.12 代理中心測試(後台)

3.12.1 代理列表

TC-ID測試說明測試步驟預期結果優先級
TC-AFF-ADMIN-001代理列表顯示1. 進入代理中心 > 代理列表 2. 選擇站點 Tab1. 顯示代理列表(AdminSiteCode 篩選) 2. 含代理帳號、等級、下線數、佣金累計 3. 支援分頁和篩選P1
TC-AFF-ADMIN-002手動建立代理1. 點擊「新增代理」 2. 選擇已存在的用戶 3. 提交1. 用戶升級為代理 2. 分配預設代理等級P1
TC-AFF-ADMIN-003手動綁定上下線1. 使用手動綁定功能 2. 指定上線和下線1. 綁定成功 2. affiliate-bind-log 寫入紀錄 3. 最多 3 層代理結構 4. 不可建立循環關係P1

3.12.2 佣金費率

TC-ID測試說明測試步驟預期結果優先級
TC-AFF-RATE-001費率列表1. 進入代理中心 > 佣金費率 2. 選擇站點 Tab1. 顯示按代理等級 x 遊戲類型的費率表 2. 4 等級 x 3 級別 x 8 遊戲類型 = 96 筆 3. 可編輯比例P1
TC-AFF-RATE-002帶入模板1. 點擊「帶入模板」 2. 預覽 3. 確認1. 預設費率模板載入 2. 確認後寫入資料庫 3. atomic transactionP1

3.12.3 結算紀錄

TC-ID測試說明測試步驟預期結果優先級
TC-AFF-SETTLE-001結算列表1. 進入代理中心 > 結算紀錄1. 顯示佣金結算紀錄 2. 含結算金額、狀態、日期 3. 篩選 status + 日期P1
TC-AFF-SETTLE-002結算審核1. 對 pending 結算點擊「審核」 2. 選擇 approve / reject1. 審核結果更新 2. approved → 佣金入帳 3. rejected → 不入帳P1
TC-AFF-SETTLE-003風控紀錄查看1. 點擊某結算的「風控紀錄」1. 顯示風控檢測結果 2. 含異常下線檢測、金額異常等 3. affiliate-risk-log 資料P2

3.12.4 代理提款

TC-ID測試說明測試步驟預期結果優先級
TC-AFF-WD-001代理提款列表1. 進入代理中心 > 代理提款1. 顯示代理提款訂單 2. 篩選 status + method 3. 三階段:待審核 → 已核准 → 已完成P1
TC-AFF-WD-002三階段流程1. 審核 → 核准 2. 完成 → 標記完成1. pending → approved → completed 2. 每階段狀態正確轉換 3. 佣金餘額正確扣除P1

3.12.5 其他代理頁面

TC-ID測試說明測試步驟預期結果優先級
TC-AFF-BIND-001綁定紀錄1. 進入綁定紀錄頁面 2. 篩選 action + refCode + 日期1. 顯示所有綁定/解綁紀錄 2. 篩選正確P2
TC-AFF-TIER-001代理等級管理1. 進入代理等級頁面 2. CRUD 操作1. 4 個預設等級:bronze / silver / gold / platinum 2. 可修改等級條件 3. 帶入模板可用P2
TC-AFF-VIP-MILE-001VIP 里程碑1. 進入 VIP 里程碑頁面 2. CRUD 操作1. 下線 VIP 等級達標獎勵配置 2. 帶入模板可用P2
TC-AFF-TOUR-001代理導覽1. 進入代理導覽頁面 2. 切換站點 Tab(模式 B)1. 每站獨立設定 2. 模式 B 設定頁正確運作P3
TC-AFF-MANUAL-001手動觸發結算1. 點擊「觸發週結」 2. 確認1. 手動執行週結排程 2. 結算紀錄產生 3. 含風控檢測P2
TC-AFF-MANUAL-002手動觸發日結1. 點擊「觸發日結」 2. 確認1. 手動執行日結排程 2. 日結紀錄產生P2
TC-AFF-SET-TIER-001手動設定代理等級1. 選擇代理 2. 設定新等級1. 等級手動調整成功 2. 不受自動升級邏輯影響P2

第 4 章:後端 API 測試案例 (c9-be)

測試對象http://localhost:8080/api框架:NestJS v11 (TypeScript 5.7 strict) Swagger UIhttp://localhost:8080/api/docs測試工具:Postman / Insomnia / Jest + Supertest 統一回應格式{ code: 200, message: "ok", result, timestamp, path }


4.1 認證 API(前台用戶)

Base: /api/auth Guard: JwtAuthGuard(需登入端點)/ 無(公開端點)

4.1.1 註冊與登入

TC-ID方法端點請求內容預期回應優先級
TC-API-AUTH-001POST/auth/register{ account: "qauser01", password: "Qa123456!", email: "qa01@test.com" }code: 200, result 含 token + userDetailP1
TC-API-AUTH-002POST/auth/register{ account: "testuser01" } (已存在帳號)code != 200, message 含帳號已存在錯誤P1
TC-API-AUTH-003POST/auth/register{ account: "qa", password: "123" } (太短)code != 200, 驗證錯誤P2
TC-API-AUTH-004POST/auth/register附帶 refCode: "ABC123"code: 200, 用戶自動綁定代理上線P1
TC-API-AUTH-005POST/auth/login{ account: "testuser01", password: "Test123456" }code: 200, result 含 token + userDetailP1
TC-API-AUTH-006POST/auth/login{ account: "testuser01", password: "wrong" }code != 200, 登入失敗訊息P1
TC-API-AUTH-007POST/auth/login{ account: "nonexistent" }code != 200, 錯誤訊息不洩漏帳號是否存在P1
TC-API-AUTH-008POST/auth/logindeviceFingerprint: "fp_xxxxx"code: 200, 指紋寫入 login-logP2

4.1.2 OAuth 登入

TC-ID方法端點請求內容預期回應優先級
TC-API-AUTH-009POST/auth/login/google{ idToken: "google_id_token" }code: 200, 自動建立/登入帳號P1
TC-API-AUTH-010POST/auth/login/telegram{ id, first_name, hash, auth_date }code: 200, Telegram 驗證 + 登入P2

4.1.3 驗證碼

TC-ID方法端點請求內容預期回應優先級
TC-API-AUTH-011POST/auth/send-email-verify{ email: "user@test.com" }code: 200, Resend API 發送驗證碼P2
TC-API-AUTH-012POST/auth/send-mobile-verify{ phone: "+886912345678" }code: 200, Twilio 發送 SMSP2
TC-API-AUTH-013POST/auth/verify-email{ email, verifyCode }code: 200, Email 驗證完成P2
TC-API-AUTH-014POST/auth/verify-mobile{ phone, verifyCode }code: 200, 手機驗證完成P2

4.1.4 用戶資料

TC-ID方法端點請求內容預期回應優先級
TC-API-AUTH-015GET/auth/user-detailBearer Tokencode: 200, 完整用戶資料P1
TC-API-AUTH-016PATCH/auth/user-detail{ nickname: "新暱稱" }code: 200, 資料更新P2
TC-API-AUTH-017PATCH/auth/avatarFormData 含圖片code: 200, 頭像上傳至 R2P3
TC-API-AUTH-018POST/auth/set-password{ oldPassword, newPassword }code: 200, 密碼變更P1

4.1.5 2FA (Google Authenticator)

TC-ID方法端點請求內容預期回應優先級
TC-API-AUTH-019POST/auth/google-auth/enableBearer Tokencode: 200, 回傳 QR Code URL + SecretP1
TC-API-AUTH-020POST/auth/google-auth/verify{ token: "123456" } (TOTP)code: 200, 2FA 啟用成功P1
TC-API-AUTH-021PATCH/auth/google-auth/disable{ token: "123456" }code: 200, 2FA 停用P1
TC-API-AUTH-022POST/auth/logoutBearer Tokencode: 200, Token 失效P1

4.1.6 Token 驗證

TC-ID方法端點請求內容預期回應優先級
TC-API-AUTH-023GET/auth/user-detail無 TokenHTTP 401, code: 401P1
TC-API-AUTH-024GET/auth/user-detail過期 TokenHTTP 401, code: 401P1
TC-API-AUTH-025GET/auth/user-detail無效 Token (亂碼)HTTP 401, code: 401P1
TC-API-AUTH-026GET/auth/user-detailAdminJWT Token (非前台 Token)HTTP 401, 前後台 Token 隔離P1

4.2 管理員 API(後台)

Base: /api/admin Guard: AdminJwtAuthGuard + PermissionsGuard Header: Authorization: Bearer <AdminJWT>

4.2.1 管理員認證

TC-ID方法端點請求內容預期回應優先級
TC-API-ADMIN-001POST/admin/login{ account: "root_admin", password: "Admin123456" }code: 200, AdminJWT TokenP1
TC-API-ADMIN-002POST/admin/login錯誤密碼code != 200, 登入失敗P1
TC-API-ADMIN-003POST/admin/register{ account, password, nickname, groupId }code: 200, 管理員建立P1
TC-API-ADMIN-004GET/admin/profileBearer AdminJWTcode: 200, 管理員個人資料P1

4.2.2 管理員 CRUD

TC-ID方法端點請求內容預期回應優先級
TC-API-ADMIN-005GET/admin/list?page=1&pageSize=20code: 200, result.items[] + result.paginationP1
TC-API-ADMIN-006GET/admin/:id有效 admin IDcode: 200, 單一管理員資料P1
TC-API-ADMIN-007PATCH/admin/:id{ nickname: "新名稱" }code: 200, 更新成功P1
TC-API-ADMIN-008DELETE/admin/:id有效 admin IDcode: 200, 刪除成功P1
TC-API-ADMIN-009DELETE/admin/:id自己的 IDcode != 200, 不可刪除自己P1

4.2.3 群組 CRUD

TC-ID方法端點請求內容預期回應優先級
TC-API-ADMIN-010GET/admin/groups/listcode: 200, 群組列表含權限P1
TC-API-ADMIN-011POST/admin/groups{ name, permissions: ["user:read", "deposit:read"] }code: 200, 群組建立P1
TC-API-ADMIN-012PATCH/admin/groups/:id{ permissions: [...] }code: 200, 權限更新P1
TC-API-ADMIN-013DELETE/admin/groups/:id無成員群組code: 200, 刪除成功P2
TC-API-ADMIN-014DELETE/admin/groups/:id有成員群組code != 200, 需先移除成員P2
TC-API-ADMIN-015GET/admin/permissions/allcode: 200, 16 個模組 × 2 權限(read/write)P2

4.2.4 操作紀錄

TC-ID方法端點請求內容預期回應優先級
TC-API-ADMIN-016GET/admin/logs/list?page=1&pageSize=20code: 200, 操作紀錄列表P2

4.2.5 財務管理 API

TC-ID方法端點請求內容預期回應優先級
TC-API-FIN-001GET/admin/finance/deposit-review/list?page=1&siteCode=C9code: 200, 存款訂單列表P1
TC-API-FIN-002POST/admin/finance/deposit-review/:id{ action: "approve" }code: 200, 訂單審核通過,用戶餘額增加P1
TC-API-FIN-003POST/admin/finance/deposit-review/:id{ action: "reject", reason: "..." }code: 200, 訂單拒絕P1
TC-API-FIN-004GET/admin/finance/users/list?page=1&siteCode=C9&keyword=testcode: 200, 用戶列表含篩選P1
TC-API-FIN-005PATCH/admin/finance/users/:userId{ nickname, status }code: 200, 用戶資料更新P1
TC-API-FIN-006GET/admin/finance/users/:userId有效用戶 IDcode: 200, 用戶詳情P1
TC-API-FIN-007POST/admin/finance/adjust-balance{ userId, amount: 100, reason: "..." }code: 200, 餘額增加 100 USDP1
TC-API-FIN-008POST/admin/finance/adjust-balance{ userId, amount: -99999 } (超額)code != 200, 餘額不足P1
TC-API-FIN-009GET/admin/finance/bank-cards/list?siteCode=C9&status=pendingcode: 200, 篩選銀行卡P1
TC-API-FIN-010POST/admin/finance/bank-cards/:id/review{ action: "approve" }code: 200, 審核通過P1
TC-API-FIN-011GET/admin/finance/credit-cards/list?siteCode=C9code: 200, 信用卡列表P1
TC-API-FIN-012POST/admin/finance/credit-cards/:id/review{ action: "approve" }code: 200, 審核通過P1
TC-API-FIN-013GET/admin/finance/crypto-addresses/list?siteCode=C9&network=TRC-20code: 200, 加密地址列表P1
TC-API-FIN-014POST/admin/finance/crypto-addresses/:id/review{ action: "approve" }code: 200, 審核通過P1
TC-API-FIN-015GET/admin/finance/withdrawals/list?siteCode=C9&status=pendingcode: 200, 提款列表P1
TC-API-FIN-016POST/admin/finance/withdrawals/:id/review{ action: "approve" }code: 200, 提款審核通過P1
TC-API-FIN-017POST/admin/finance/withdrawals/:id/review{ action: "reject" }code: 200, 提款拒絕,凍結餘額退回P1
TC-API-FIN-018POST/admin/finance/withdrawals/:id/upload-proofFormData 含憑證圖片code: 200, 憑證上傳至 R2P2
TC-API-FIN-019POST/admin/finance/withdrawals/:id/completecode: 200, 提款完成,凍結餘額扣除P1
TC-API-FIN-020PUT/admin/users/:userId/vendor-group{ vendorGroupId }code: 200, 金流群組分配P2

4.2.6 活動管理 API

TC-ID方法端點請求內容預期回應優先級
TC-API-PROMO-001GET/admin/promos/list?siteCode=C9&page=1code: 200, 活動列表P1
TC-API-PROMO-002POST/admin/promos{ title: {...}, content: {...}, siteCode }code: 200, 活動建立P1
TC-API-PROMO-003PATCH/admin/promos/:id{ title: {...} }code: 200, 活動更新P1
TC-API-PROMO-004DELETE/admin/promos/:idcode: 200, 活動刪除P2
TC-API-PROMO-005GET/admin/promo-tags/list?siteCode=C9code: 200, 標籤列表P2
TC-API-PROMO-006POST/admin/promo-tags{ name, siteCode }code: 200, 標籤建立P2
TC-API-PROMO-007PATCH/admin/promo-tags/:id{ name }code: 200, 標籤更新P2
TC-API-PROMO-008DELETE/admin/promo-tags/:idcode: 200, 標籤刪除P2

4.2.7 風控 API

TC-ID方法端點請求內容預期回應優先級
TC-API-RISK-001GET/admin/risk/ip-rules/list?siteCode=C9&type=blacklistcode: 200, IP 規則列表P1
TC-API-RISK-002POST/admin/risk/ip-rules{ ip: "1.2.3.4", type: "blacklist", note, siteCode }code: 200, 規則建立P1
TC-API-RISK-003DELETE/admin/risk/ip-rules/:idcode: 200, 規則刪除P1
TC-API-RISK-004PATCH/admin/risk/ip-rules/:id{ note: "..." }code: 200, 規則更新P2
TC-API-RISK-005GET/admin/risk/lookup?siteCode=C9&keyword=192.168code: 200, IP/FP 反查結果P1
TC-API-RISK-006GET/admin/risk/game-blacklist/list?siteCode=C9code: 200, 遊戲黑名單列表P1
TC-API-RISK-007POST/admin/risk/game-blacklist{ userId, blockType: "all", siteCode }code: 200, 遊戲黑名單建立P1
TC-API-RISK-008DELETE/admin/risk/game-blacklist/:idcode: 200, 黑名單移除P1
TC-API-RISK-009GET/admin/risk/login-failures?siteCode=C9&keyword=test&startDate&endDatecode: 200, 登入失敗紀錄P2

4.2.8 報表 API

TC-ID方法端點請求內容預期回應優先級
TC-API-RPT-001GET/admin/reports/overview?siteCode=C9&startDate&endDatecode: 200, 總覽統計(卡片 + 每日摘要)P1
TC-API-RPT-002GET/admin/reports/players?siteCode=C9&vipLevel=5&page=1code: 200, 玩家報表P1
TC-API-RPT-003GET/admin/reports/vip-players?siteCode=C9 (@AdminSiteCode)code: 200, VIP 玩家報表P1
TC-API-RPT-004GET/admin/reports/bet-records?siteCode=C9&gameType=SLOT&page=1code: 200, 投注紀錄P1
TC-API-RPT-005GET/admin/reports/games?siteCode=C9&gameType=LIVEcode: 200, 遊戲報表P1
TC-API-RPT-006GET/admin/reports/profit-loss?siteCode=C9&groupBy=dailycode: 200, 損益報表P1
TC-API-RPT-007GET/admin/reports/player-summary?siteCode=C9&sortBy=totalBet&sortOrder=desccode: 200, 玩家摘要P1
TC-API-RPT-008GET/admin/reports/promos?startDate&endDatecode: 200, 活動報表P2
TC-API-RPT-009GET/admin/reports/r2-logs?page=1&pageSize=20code: 200, R2 操作紀錄P2
TC-API-RPT-010GET/admin/reports/export?type=players&siteCode=C9回傳 CSV 檔案下載P2

4.2.9 R2 檔案操作 API

TC-ID方法端點請求內容預期回應優先級
TC-API-R2-001GET/admin/r2/list?prefix=images/code: 200, 檔案列表P2
TC-API-R2-002POST/admin/r2/uploadFormData 含檔案code: 200, 檔案 URLP2
TC-API-R2-003DELETE/admin/r2/delete{ key: "images/xxx.png" }code: 200, 刪除成功P2
TC-API-R2-004POST/admin/r2/move{ sourceKey, targetKey }code: 200, 移動成功P3
TC-API-R2-005POST/admin/r2/create-folder{ prefix: "images/new/" }code: 200, 資料夾建立P3
TC-API-R2-006DELETE/admin/r2/delete-folder{ prefix: "images/old/" }code: 200, 資料夾刪除P3

4.2.10 金流商 API

TC-ID方法端點請求內容預期回應優先級
TC-API-VENDOR-001GET/admin/vendor-groups/list?siteCode=C9code: 200, 金流群組列表P1
TC-API-VENDOR-002POST/admin/vendor-groups{ name, siteCode }code: 200, 群組建立P1
TC-API-VENDOR-003PATCH/admin/vendor-groups/:id{ name }code: 200, 群組更新P2
TC-API-VENDOR-004DELETE/admin/vendor-groups/:idcode: 200, 群組刪除P2
TC-API-VENDOR-005GET/admin/vendor-channels/list?groupId=1code: 200, 通道列表P1
TC-API-VENDOR-006POST/admin/vendor-channels{ name, type, groupId }code: 200, 通道建立P1
TC-API-VENDOR-007PATCH/admin/vendor-channels/:id{ enabled: false }code: 200, 通道更新P1
TC-API-VENDOR-008DELETE/admin/vendor-channels/:idcode: 200, 通道刪除P2

4.3 遊戲 API

Base: /api/game

4.3.1 前台遊戲端點

TC-ID方法端點請求內容預期回應優先級
TC-API-GAME-001GET/game/providers?gameType=SLOT + site-name headercode: 200, 該分類供應商列表P1
TC-API-GAME-002POST/game/launch{ providerCode, gameId } + Bearer Tokencode: 200, result.url 遊戲 iframe URLP1
TC-API-GAME-003POST/game/launch被風控封鎖的用戶code: 5010, 遊戲黑名單阻擋P1
TC-API-GAME-004POST/game/demo{ providerCode, gameId }code: 200, 試玩 URL(無需登入)P2
TC-API-GAME-005GET/game/recentBearer Tokencode: 200, 最近遊玩列表(最多 10)P3

4.3.2 遊戲 Admin API

TC-ID方法端點請求內容預期回應優先級
TC-API-GAME-006GET/game/admin/providers?gameType=SLOT + @AdminSiteCodecode: 200, 供應商列表(按站點)P1
TC-API-GAME-007POST/game/admin/providers{ providerCode, name, gameType, siteCode }code: 200, 供應商建立P1
TC-API-GAME-008PATCH/game/admin/providers/:id{ name }code: 200, 供應商更新P1
TC-API-GAME-009DELETE/game/admin/providers/:idcode: 200, 供應商刪除P2
TC-API-GAME-010GET/game/admin/type-configs@AdminSiteCodecode: 200, 分類列表P1
TC-API-GAME-011POST/game/admin/type-configs{ gameType, name, siteCode }code: 200, 分類建立P1
TC-API-GAME-012PATCH/game/admin/type-configs/:id{ name }code: 200, 分類更新P1
TC-API-GAME-013DELETE/game/admin/type-configs/:idcode: 200, 分類刪除P2
TC-API-GAME-014GET/game/admin/preview-templatecode: 200, 預設 providers + typeConfigsP1
TC-API-GAME-015POST/game/admin/load-template{ providers: [...], typeConfigs: [...] } + @AdminSiteCodecode: 200, 模板寫入指定站點P1
TC-API-GAME-016POST/game/admin/copy-site-data{ sourceSiteCode: "C9", targetSiteCode: "A1", type: "providers" }code: 200, 跨站複製(transaction 先刪後插)P1
TC-API-GAME-017POST/game/admin/copy-site-data{ sourceSiteCode: "C9", targetSiteCode: "A1", type: "typeConfigs" }code: 200, 分類跨站複製P1

4.3.3 S2S 回調

TC-ID方法端點請求內容預期回應優先級
TC-API-GAME-018POST/game/betsolutions/callbackBetSolutions S2S 格式 (bet/win/refund)供應商格式回應,bet-order + game-transaction 寫入P1
TC-API-GAME-019POST/game/rsg/callbackRSG S2S 格式(DES 加密)DES 解密 → 處理 → 加密回應P1
TC-API-GAME-020POST/game/betsolutions/callback重複交易 ID (idempotency)回傳之前的結果,不重複處理P1

4.4 VIP API

Base: /api/vip

4.4.1 前台 VIP 端點

TC-ID方法端點請求內容預期回應優先級
TC-API-VIP-001GET/vip/levelssite-name headercode: 200, 該站所有 VIP 等級列表P1
TC-API-VIP-002GET/vip/user-statusBearer Tokencode: 200, 用戶 VIP 狀態(等級、進度、保級)P1
TC-API-VIP-003GET/vip/my-rebatesBearer Token + ?page=1code: 200, 用戶反水紀錄P2
TC-API-VIP-004GET/vip/rebate-tablesite-name headercode: 200, 等級 x 遊戲類型反水比例表P2

4.4.2 VIP Admin API

TC-ID方法端點請求內容預期回應優先級
TC-API-VIP-005GET/vip/admin/levels@AdminSiteCodecode: 200, 等級列表(按站點)P1
TC-API-VIP-006POST/vip/admin/levels{ level, name, threshold, siteCode }code: 200, 等級建立P1
TC-API-VIP-007PATCH/vip/admin/levels/:id{ threshold }code: 200, 等級更新P1
TC-API-VIP-008DELETE/vip/admin/levels/:idcode: 200, 等級刪除P2
TC-API-VIP-009POST/vip/admin/rebates/bulk-upsert{ items: [{ siteCode, level, gameType, rate }] }code: 200, 批次更新反水P1
TC-API-VIP-010GET/vip/admin/rebates@AdminSiteCodecode: 200, 反水設定列表P1
TC-API-VIP-011POST/vip/admin/copy-site-data{ sourceSiteCode, targetSiteCode, type: "levels" }code: 200, VIP 等級跨站複製P1
TC-API-VIP-012POST/vip/admin/copy-site-data{ sourceSiteCode, targetSiteCode, type: "rebates" }code: 200, 返水跨站複製P1
TC-API-VIP-013GET/vip/admin/preview-templatecode: 200, VIP 模板預覽P1
TC-API-VIP-014POST/vip/admin/load-template{ levels: [...], rebates: [...] } + @AdminSiteCodecode: 200, 模板載入P1

4.5 代理 API

Base: /api/affiliate

4.5.1 前台代理端點

TC-ID方法端點請求內容預期回應優先級
TC-API-AFF-001POST/affiliate/track-click{ refCode: "ABC123" }code: 200, 點擊紀錄寫入P2
TC-API-AFF-002POST/affiliate/apply-agentBearer Tokencode: 200, 申請成為代理P1
TC-API-AFF-003GET/affiliate/dashboardBearer Tokencode: 200, 代理儀表板資料P1
TC-API-AFF-004GET/affiliate/downlinesBearer Token + ?page=1code: 200, 下線列表(帳號遮罩)P1
TC-API-AFF-005GET/affiliate/commissionsBearer Token + ?page=1code: 200, 佣金紀錄P1
TC-API-AFF-006GET/affiliate/settlementsBearer Token + ?page=1code: 200, 結算紀錄P1
TC-API-AFF-007POST/affiliate/withdraw{ amount, method } + Bearer Tokencode: 200, 代理提款申請P1
TC-API-AFF-008GET/affiliate/balanceBearer Tokencode: 200, 佣金餘額(含凍結)P1

4.5.2 聯盟公開端點

TC-ID方法端點請求內容預期回應優先級
TC-API-AFF-009GET/affiliate/alliance-infosite-name headercode: 200, 聯盟介紹資訊P2
TC-API-AFF-010GET/affiliate/tier-infosite-name headercode: 200, 代理等級資訊P2
TC-API-AFF-011GET/affiliate/vip-milestonessite-name headercode: 200, VIP 里程碑列表P2
TC-API-AFF-012GET/affiliate/referral-codesBearer Tokencode: 200, 推薦碼列表P1
TC-API-AFF-013POST/affiliate/referral-codes{ code: "MYCODE" } + Bearer Tokencode: 200, 推薦碼建立(max 10)P1
TC-API-AFF-014DELETE/affiliate/referral-codes/:idBearer Tokencode: 200, 推薦碼刪除P1

4.5.3 代理 Admin API

TC-ID方法端點請求內容預期回應優先級
TC-API-AFF-ADMIN-001GET/affiliate/admin/agents@AdminSiteCodecode: 200, 代理列表P1
TC-API-AFF-ADMIN-002POST/affiliate/admin/create-agent{ userId }code: 200, 手動建立代理P1
TC-API-AFF-ADMIN-003POST/affiliate/admin/bind{ parentId, childId }code: 200, 手動綁定上下線P1
TC-API-AFF-ADMIN-004GET/affiliate/admin/bind-logs?action&refCode&startDate&endDatecode: 200, 綁定紀錄P2
TC-API-AFF-ADMIN-005GET/affiliate/admin/settlements?status&startDate&endDatecode: 200, 結算列表P1
TC-API-AFF-ADMIN-006POST/affiliate/admin/settlements/:id/review{ action: "approve" }code: 200, 結算審核P1
TC-API-AFF-ADMIN-007GET/affiliate/admin/settlements/:id/risk-logscode: 200, 風控紀錄P2
TC-API-AFF-ADMIN-008GET/affiliate/admin/withdrawals?status&methodcode: 200, 代理提款列表P1
TC-API-AFF-ADMIN-009POST/affiliate/admin/withdrawals/:id/review{ action: "approve" }code: 200, 提款審核P1
TC-API-AFF-ADMIN-010POST/affiliate/admin/withdrawals/:id/completecode: 200, 提款完成P1
TC-API-AFF-ADMIN-011GET/affiliate/admin/commission-rates@AdminSiteCodecode: 200, 佣金費率列表P1
TC-API-AFF-ADMIN-012POST/affiliate/admin/commission-rates{ items: [...] }code: 200, 費率批次更新P1
TC-API-AFF-ADMIN-013GET/affiliate/admin/agent-tiers@AdminSiteCodecode: 200, 代理等級列表P1
TC-API-AFF-ADMIN-014POST/affiliate/admin/agent-tiers{ items: [...] }code: 200, 等級批次更新P1
TC-API-AFF-ADMIN-015GET/affiliate/admin/vip-milestones@AdminSiteCodecode: 200, VIP 里程碑列表P2
TC-API-AFF-ADMIN-016POST/affiliate/admin/vip-milestones{ items: [...] }code: 200, 里程碑批次更新P2
TC-API-AFF-ADMIN-017GET/affiliate/admin/preview-templatecode: 200, 代理模板預覽P1
TC-API-AFF-ADMIN-018POST/affiliate/admin/load-template@AdminSiteCodecode: 200, 模板載入(atomic)P1
TC-API-AFF-ADMIN-019POST/affiliate/admin/set-agent-tier{ agentId, tierId }code: 200, 手動設定等級P2
TC-API-AFF-ADMIN-020POST/affiliate/admin/trigger-settlementcode: 200, 手動觸發週結P2
TC-API-AFF-ADMIN-021POST/affiliate/admin/trigger-daily-settlementcode: 200, 手動觸發日結P2

4.6 金流 API

4.6.1 錢包端點

TC-ID方法端點請求內容預期回應優先級
TC-API-WALLET-001GET/wallet/bank-cardsBearer Tokencode: 200, 用戶銀行卡列表P1
TC-API-WALLET-002POST/wallet/bank-cards{ bankName, branch, accountNumber, holderName }code: 200, 銀行卡建立P1
TC-API-WALLET-003DELETE/wallet/bank-cards/:idBearer Tokencode: 200, 銀行卡刪除P2
TC-API-WALLET-004GET/wallet/credit-cardsBearer Tokencode: 200, 信用卡列表P1
TC-API-WALLET-005POST/wallet/credit-cards{ cardNumber, expiry, cvv, holderName }code: 200, 信用卡建立P1
TC-API-WALLET-006DELETE/wallet/credit-cards/:idBearer Tokencode: 200, 信用卡刪除P2
TC-API-WALLET-007GET/wallet/crypto-addressesBearer Tokencode: 200, 加密地址列表P1
TC-API-WALLET-008POST/wallet/crypto-addresses{ network: "TRC-20", address, currency: "USDT" }code: 200, 加密地址建立P1
TC-API-WALLET-009DELETE/wallet/crypto-addresses/:idBearer Tokencode: 200, 加密地址刪除P2

4.6.2 存款端點

TC-ID方法端點請求內容預期回應優先級
TC-API-DEP-001GET/deposit/listBearer Token + ?page=1code: 200, 存款訂單列表P1
TC-API-DEP-002POST/deposit{ channelId, amount } + Bearer Tokencode: 200, 建立存款訂單(後端路由至對應金流商)P1
TC-API-DEP-003GET/deposit/:idBearer Tokencode: 200, 訂單詳情P2
TC-API-DEP-004GET/deposit/exchange-rate?currency=TWDcode: 200, 台灣銀行即時匯率P1

4.6.3 提款端點

TC-ID方法端點請求內容預期回應優先級
TC-API-WD-001GET/withdrawal/listBearer Token + ?page=1code: 200, 提款訂單列表P1
TC-API-WD-002POST/withdrawal{ walletId, walletType, amount } + Bearer Tokencode: 200, 建立提款訂單P1
TC-API-WD-003POST/withdrawal金額超過餘額code != 200, 餘額不足P1
TC-API-WD-004GET/withdrawal/:idBearer Tokencode: 200, 訂單詳情P2

4.6.4 金流回調

TC-ID方法端點請求內容預期回應優先級
TC-API-VENDOR-CB-001POST/vendor/wantong/callback萬通金流回調格式回傳成功確認,訂單狀態更新P1
TC-API-VENDOR-CB-002POST/vendor/usdt/callbackUSDT 確認回調回傳成功確認,訂單狀態更新P1
TC-API-VENDOR-CB-003POST/vendor/wantong/callback重複回調 (idempotency)不重複處理,回傳成功P1

4.7 其他 API

4.7.1 站內信

TC-ID方法端點請求內容預期回應優先級
TC-API-INBOX-001GET/inbox/listBearer Token + ?page=1code: 200, 通知列表P1
TC-API-INBOX-002GET/inbox/:idBearer Tokencode: 200, 通知詳情 + 標記已讀P1
TC-API-INBOX-003GET/inbox/unread-countBearer Tokencode: 200, 未讀數量P1
TC-API-INBOX-004POST/inbox/read-allBearer Tokencode: 200, 全部標記已讀P2

4.7.2 任務系統

TC-ID方法端點請求內容預期回應優先級
TC-API-MISSION-001GET/mission/listBearer Tokencode: 200, 任務列表含進度P1
TC-API-MISSION-002POST/mission/:id/claimBearer Tokencode: 200, 領取獎勵(已完成任務)P1
TC-API-MISSION-003POST/mission/:id/claim未完成任務code != 200, 任務尚未完成P1

4.7.3 站點設定 Admin API

TC-ID方法端點請求內容預期回應優先級
TC-API-SITECONF-001GET/site-config/admin/listcode: 200, 所有站點列表(含主題)P1
TC-API-SITECONF-002POST/site-config/admin{ siteCode, name, ... }code: 200, 站點建立P1
TC-API-SITECONF-003PATCH/site-config/admin/:id{ name }code: 200, 站點更新P1
TC-API-SITECONF-004DELETE/site-config/admin/:id有效站點 IDcode: 200, 站點刪除(cascade 主題)P1
TC-API-SITECONF-005GET/site-config/admin/:siteConfigId/themes有效 siteConfigIdcode: 200, 主題列表P1
TC-API-SITECONF-006POST/site-config/admin/:siteConfigId/themes{ name, colors: { primary, accent, ... } }code: 200, 主題建立P2
TC-API-SITECONF-007PATCH/site-config/admin/themes/:id{ colors: { primary: "#xxx" } }code: 200, 主題更新P2
TC-API-SITECONF-008DELETE/site-config/admin/themes/:id有效主題 IDcode: 200, 主題刪除P2
TC-API-SITECONF-009POST/site-config/admin/:id/domain-assetFormData (logoSmall/logoBig/favicon)code: 200, 素材上傳至 R2P2
TC-API-SITECONF-010POST/site-config/admin/:id/customer-service-iconFormData (客服圖示)code: 200, 圖示上傳P3
TC-API-SITECONF-011PATCH/site-config/admin/:siteConfigId/mascots{ mascots: ["url1", "url2"] }code: 200, 吉祥物更新P3
TC-API-SITECONF-012GET/site-config/admin/:siteCode/customer-service有效 siteCodecode: 200, 客服設定(8 管道)P1

4.7.4 公用端點

TC-ID方法端點請求內容預期回應優先級
TC-API-COMMON-001GET/common/enumscode: 200, 完整 ERROR_CODES + 枚舉常數P1
TC-API-COMMON-002GET/ranking/listsite-name headercode: 200, 排行榜資料P3
TC-API-COMMON-003GET/bet-record/listBearer Token + ?page=1code: 200, 用戶投注紀錄P2
TC-API-COMMON-004GET/bet-record/:idBearer Tokencode: 200, 投注詳情P2
TC-API-COMMON-005GET/live-sports/matchessite-name headercode: 200, 即時賽事列表(30 分鐘快取)P3

4.7.5 前台站點設定

TC-ID方法端點請求內容預期回應優先級
TC-API-SITECONF-F-001GET/site-config/infosite-name headercode: 200, 站點資訊(名稱、Logo、features)P1
TC-API-SITECONF-F-002GET/site-config/themesite-name headercode: 200, 當前主題配色P1
TC-API-SITECONF-F-003GET/site-config/customer-servicesite-name headercode: 200, 客服管道列表P1

4.7.6 前台活動端點

TC-ID方法端點請求內容預期回應優先級
TC-API-PROMO-F-001GET/promo/listsite-name header + ?page=1code: 200, 活動列表(僅 enabled)P1
TC-API-PROMO-F-002GET/promo/:idsite-name headercode: 200, 活動詳情P1
TC-API-PROMO-F-003POST/promo/:id/claimBearer Tokencode: 200, 領取活動(檢查條件)P1
TC-API-PROMO-F-004POST/promo/:id/claim不符合條件code != 200, 條件未達標P1

第 5 章:業務流程端對端測試

本章描述跨系統的完整業務流程,驗證前台、後台、後端三個專案協同運作的正確性。 每個流程包含完整步驟、各階段預期狀態,以及需驗證的資料一致性。


5.1 完整存款流程

流程概述

前台提交存款 → 後端建立訂單 → 金流商回調確認 → 後台管理員審核 → 用戶餘額更新

詳細步驟

步驟 1:前台提交存款

操作驗證項目
1.1 用戶登入前台JWT Token 取得,用戶資訊正確
1.2 進入存款頁面金流通道列表載入(依金流群組篩選)
1.3 選擇存款通道(如 ATM)通道資訊顯示正確
1.4 輸入存款金額(如 30,000 TWD)匯率換算正確顯示(台灣銀行即時匯率)
1.5 確認提交API POST /deposit 呼叫成功

步驟 1 結束狀態

  • deposit-order 表新增一筆記錄
  • 訂單狀態:pending
  • 訂單金額:USD(截斷至 6 位小數)
  • 訂單匯率:使用 tw-exchange 取得的即時匯率
  • 用戶餘額:不變

步驟 2:金流商回調

操作驗證項目
2.1 用戶完成付款(ATM 轉帳/信用卡/USDT)金流商處理完成
2.2 金流商發送回調至 /vendor/wantong/callback/vendor/usdt/callback回調格式正確、簽名驗證
2.3 後端接收回調回調處理成功,回傳確認

步驟 2 結束狀態

  • 訂單狀態可能更新為 callback_received(視實作)
  • 回調紀錄寫入
  • Idempotency:重複回調不重複處理

步驟 3:後台管理員審核

操作驗證項目
3.1 管理員登入後台AdminJWT 取得
3.2 進入財務管理 > 存款審核訂單列表正確顯示
3.3 選擇站點 Tab + 篩選 pending 訂單siteCode 篩選正確
3.4 點擊「通過」並確認API POST /admin/finance/deposit-review/:id

步驟 3 結束狀態(審核通過)

  • 訂單狀態:approved
  • 用戶餘額:增加 USD 金額
  • 操作紀錄:寫入 admin-operation-log

步驟 3 結束狀態(審核拒絕)

  • 訂單狀態:rejected
  • 用戶餘額:不變
  • 拒絕原因:記錄在訂單中

步驟 4:驗證餘額

驗證項目預期結果
前台餘額顯示餘額增加 = 存款金額(TWD) / 匯率,截斷至 6 位
auth-userbalance 欄位數值正確
匯率精度decimal(18,10),使用即時匯率
金額精度decimal(18,6),無條件捨去

關鍵驗證公式

存款 USD = Math.floor(TWD_Amount / ExchangeRate * 1e6) / 1e6
用戶新餘額 = 原餘額 + 存款 USD

異常場景

場景預期行為
金流商回調失敗訂單保持 pending,可手動處理
審核後金流商又回調Idempotency 處理,不重複加款
同時審核同一訂單併發控制,只處理一次
匯率在審核前後變動使用建單時的匯率,非審核時匯率

5.2 完整提款流程

流程概述

前台提交提款 → 餘額凍結 → 後台審核 → 上傳憑證 → 標記完成 → 凍結餘額扣除

詳細步驟

步驟 1:前台提交提款

操作驗證項目
1.1 用戶登入,確認餘額充足餘額 >= 提款金額
1.2 進入提款頁面已審核通過的銀行卡/加密地址列表
1.3 選擇提款方式(如銀行卡)僅顯示 approved 的卡片
1.4 輸入提款金額驗證不超過可用餘額
1.5 確認提交API POST /withdrawal

步驟 1 結束狀態

欄位
withdrawal-order 狀態pending
用戶可用餘額原餘額 - 提款金額
用戶凍結餘額原凍結 + 提款金額
用戶總資產不變(可用 + 凍結 = 原總額)

步驟 2:後台審核

操作驗證項目
2.1 管理員進入提款管理訂單列表正確
2.2 檢查訂單資訊用戶、金額、提款方式正確
2.3 選擇「核准」或「拒絕」API 呼叫

審核通過後狀態

欄位
訂單狀態approved
用戶可用餘額不變(維持步驟 1)
用戶凍結餘額不變(維持步驟 1)

審核拒絕後狀態

欄位
訂單狀態rejected
用戶可用餘額原餘額(凍結退回)
用戶凍結餘額原凍結(扣回提款金額)

步驟 3:上傳轉帳憑證(可選)

操作驗證項目
3.1 管理員上傳轉帳截圖圖片上傳至 R2
3.2 憑證連結寫入訂單可在訂單詳情查看

步驟 4:標記完成

操作驗證項目
4.1 管理員點擊「完成」API POST /admin/finance/withdrawals/:id/complete

完成後狀態

欄位
訂單狀態completed
用戶可用餘額不變
用戶凍結餘額原凍結 - 提款金額(釋放)
用戶總資產原總額 - 提款金額

餘額變化摘要

假設用戶原始餘額 1000 USD,提款 200 USD:

階段可用餘額凍結餘額總資產提款訂單狀態
初始100001000-
提交後8002001000pending
審核通過8002001000approved
完成8000800completed
審核拒絕(替代)100001000rejected

5.3 遊戲投注連動流程

流程概述

啟動遊戲 → 遊戲內下注 → S2S 回調 → 更新投注訂單
    → VIP 等級重算
    → 活動打碼量更新
    → 任務進度更新

詳細步驟

步驟 1:啟動遊戲

操作驗證項目
1.1 用戶在前台點擊「進入遊戲」API POST /game/launch
1.2 風控黑名單檢查未被封鎖 → 通過;已封鎖 → 錯誤碼 5010
1.3 遊戲 iframe 載入遊戲供應商 URL 回傳成功
1.4 遊戲紀錄寫入game-play-log 新增紀錄

步驟 2:遊戲內下注(S2S 回調)

操作驗證項目
2.1 用戶在遊戲內下注 100 USD遊戲供應商發送 S2S bet 回調
2.2 後端接收 /game/betsolutions/callback/game/rsg/callback驗證簽名/DES 解密
2.3 扣除用戶餘額 100 USD轉帳錢包模式
2.4 寫入交易紀錄game-transaction 新增 debit 紀錄
2.5 寫入投注訂單bet-order + bet-detail 新增

步驟 2 結束狀態

  • 用戶餘額:減少 100 USD
  • bet-order 狀態:pending(等待結算)
  • game-transaction 類型:debit

步驟 3:派彩(S2S 回調)

操作驗證項目
3.1 遊戲結算,供應商發送 win 回調派彩 250 USD
3.2 後端增加用戶餘額 250 USD轉帳錢包模式
3.3 更新投注訂單bet-order 狀態 → settled
3.4 寫入交易紀錄game-transaction 新增 credit 紀錄

步驟 4:連動系統更新

投注結算後,後端自動觸發以下 4 個連動:

4a. VIP 等級重算

驗證項目預期結果
累計投注金額更新auth-user.totalBet 增加 100 USD
VIP 等級檢查若累計投注達到下一等級門檻 → 自動升級
VIP 等級只升不降只在升級時更新,不會降級
升級後反水比例更新新等級對應的返水比例生效

4b. 活動打碼量更新

驗證項目預期結果
活動打碼進度若用戶有參與需打碼的活動,打碼量增加
promo-claim 進度打碼量欄位更新
達標自動發放打碼量達標的活動可領取獎勵

4c. 任務進度更新

驗證項目預期結果
投注任務進度mission-progress 更新
進度百分比正確計算
任務完成達標後可領取 → mission-claim

4d. 代理佣金記錄

驗證項目預期結果
若用戶有上線代理affiliate-commission 寫入佣金紀錄
三層代理佣金各層代理按費率計算佣金
佣金金額精度decimal(18,6)

冪等性驗證

場景預期行為
相同交易 ID 重複發送 bet 回調不重複扣款,回傳原結果
相同交易 ID 重複發送 win 回調不重複派彩,回傳原結果
refund 回調退還已扣款金額,bet-order 狀態更新

5.4 代理佣金結算流程

流程概述

用戶透過推薦碼註冊 → 綁定代理上線 → 用戶投注 → 佣金產生
→ 每週一自動週結 → 風控檢測 → 管理員審核
→ 代理提款 → 三階段審核 → 完成

詳細步驟

步驟 1:代理綁定

操作驗證項目
1.1 代理建立推薦碼 AGENT01alliance-referral-code 表新增
1.2 新用戶透過 ?ref=AGENT01 連結進入推薦碼記錄到前端
1.3 用戶完成註冊自動綁定代理上線
1.4 綁定紀錄affiliate-bind-log 寫入 action=bind

步驟 1 結束狀態

  • 用戶的上線代理 = AGENT01 的擁有者
  • 代理下線人數 + 1
  • 三層代理結構:若 AGENT01 有上線,則建立最多 3 層關係

步驟 2:用戶投注產生佣金

操作驗證項目
2.1 下線用戶在前台投注 1000 USDS2S 回調處理
2.2 自動計算各層代理佣金依等級 x 遊戲類型的費率計算
2.3 佣金紀錄寫入affiliate-commission 表新增

佣金計算範例(假設 SLOT 遊戲):

代理層級代理等級費率佣金 (USD)
一級代理(直屬上線)gold0.5%5.00
二級代理silver0.2%2.00
三級代理bronze0.1%1.00

步驟 3:自動週結(Cron)

操作驗證項目
3.1 每週一 03:00 觸發 Cron Jobaffiliate-settlement.service.ts
3.2 彙總該週佣金按代理分組計算總額
3.3 風控檢測affiliate-risk.service.ts 檢查異常下線
3.4 建立結算紀錄affiliate-settlement 表新增

步驟 3 結束狀態

  • 結算紀錄狀態:pending(待審核)
  • 風控紀錄:affiliate-risk-log 寫入檢測結果
  • 可能觸發的風控項目:
    • 異常高額佣金
    • 短時間大量下線註冊
    • 下線投注模式異常

步驟 4:管理員審核

操作驗證項目
4.1 管理員進入代理中心 > 結算紀錄列表顯示 pending 結算
4.2 查看風控紀錄評估風險等級
4.3 審核通過/拒絕API 呼叫

審核通過後

  • 結算狀態:approved
  • 代理佣金餘額增加

審核拒絕後

  • 結算狀態:rejected
  • 佣金不入帳

步驟 5:代理提款

操作驗證項目
5.1 代理在前台提交提款申請affiliate-withdrawal 表新增
5.2 管理員審核提款pendingapproved
5.3 管理員標記完成approvedcompleted

三階段提款狀態

階段代理佣金餘額代理凍結餘額提款狀態
提交前5000-
提交後300200pending
審核通過300200approved
完成3000completed
審核拒絕(替代)5000rejected

5.5 VIP 保級/降級流程

流程概述

用戶升至 VIP 5+ → 每月保級檢查 → 投注未達門檻 → relegationMissCount++
→ 連續未達 → 降級 VIP 4 → 反水比例調整

詳細步驟

步驟 1:用戶達到 VIP 5

操作驗證項目
1.1 用戶累計投注達到 VIP 5 門檻自動升級至 VIP 5
1.2 VIP 等級更新auth-user.vipLevel = 5
1.3 保級機制啟動VIP 5+ 支援保級鎖定

步驟 2:第一個月保級檢查

操作驗證項目
2.1 每月 1 號 01:00 觸發 Cron JobVipService 保級排程
2.2 檢查上月投注金額對比 VIP 5 月度保級門檻
2.3 投注未達門檻relegationMissCount += 1

步驟 2 結束狀態(未達標):

  • VIP 等級:維持 VIP 5(首次未達不降級)
  • relegationMissCount:1
  • 用戶可在本月補足投注

步驟 3:第二個月保級檢查

操作驗證項目
3.1 再次觸發月度檢查Cron Job
3.2 上月投注仍未達門檻relegationMissCount += 1 (= 2)
3.3 觸發降級依保級規則降至 VIP 4

步驟 3 結束狀態(連續未達標):

  • VIP 等級:降至 VIP 4
  • relegationMissCount:重置為 0
  • 反水比例調整為 VIP 4 對應的費率

步驟 4:驗證連動影響

驗證項目預期結果
前台 VIP 狀態頁顯示 VIP 4
反水結算使用 VIP 4 的返水比例
VIP 福利調整為 VIP 4 對應福利
可重新升級累計投注達 VIP 5 門檻可再次升級

保級成功場景

操作結果
月度投注 >= 保級門檻relegationMissCount 重置為 0
VIP 等級維持不變
保級鎖定(VIP 5+)繼續保護

第 6 章:多站點隔離測試

測試目標:驗證各站點資料完全隔離,不同站點之間無法互相存取資料。 前置條件:Seed 資料含至少 2 個站點(如 C9 和 A1),各站點有獨立資料。


6.1 資料隔離測試

TC-ID測試說明測試步驟預期結果優先級
TC-ISO-001A 站資料不可見於 B 站1. 在 C9 站建立一筆活動 2. 切換至 A1 站 3. 查看活動列表1. C9 的活動不顯示在 A1 列表中 2. 各站點資料完全隔離 3. API 返回的資料僅含當前站點P1
TC-ISO-002siteCode 篩選覆蓋所有 Entity1. 對每個含 siteCode 的 Entity 進行測試 2. 使用不同站點查詢驗證以下 Entity 的 siteCode 篩選正確:auth-user, deposit-order, withdrawal-order, bank-card, credit-card, crypto-address, game-provider, game-type-config, game-transaction, bet-order, bet-detail, vip-level, vip-rebate, vip-rebate-log, promo, promo-claim, promo-tag, affiliate-commission, affiliate-settlement, affiliate-balance, affiliate-withdrawal, affiliate-click, affiliate-bind-log, alliance-commission-rate, alliance-agent-tier, alliance-vip-milestone, alliance-referral-code, notification, site-theme, risk-ip-rule, risk-game-blacklist, mission, mission-progress, mission-claim, vendor-group, vendor-channel, rank-list, r2-operation-logP1
TC-ISO-003管理員切站後資料刷新1. 在後台查看 C9 站玩家列表(記錄數量和帳號) 2. 切換至 A1 站 3. 查看玩家列表1. 玩家列表完全不同 2. 數量可能不同 3. AdminContentWrapper 重新掛載 4. 無殘留 C9 資料P1
TC-ISO-004同預設站點只影響目標站1. 記錄 C9 站遊戲供應商列表 2. 記錄 A1 站遊戲供應商列表 3. 記錄 B2 站遊戲供應商列表 4. 在 A1 站執行「同預設站點」 5. 檢查三個站點資料1. C9 站(預設站)資料不變 2. A1 站資料更新為 C9 的內容 3. B2 站資料不受影響 4. 只有目標站被修改P1
TC-ISO-005模板載入只影響當前站1. 在 A1 站載入 VIP 模板 2. 檢查 C9 站 VIP 等級 3. 檢查 B2 站 VIP 等級1. A1 站 VIP 等級更新為模板內容 2. C9 站不受影響 3. B2 站不受影響 4. @AdminSiteCode 正確限定範圍P1
TC-ISO-006全站共用 Entity 跨站可見1. 建立一個管理員帳號 2. 切換不同站點 3. 檢查管理員列表1. admin-user 不含 siteCode,全站共用 2. admin-group 全站共用 3. admin-operation-log 全站共用 4. 這些表格不受站點切換影響P1

6.2 多站點 API 隔離測試

TC-ID測試說明測試步驟預期結果優先級
TC-ISO-API-001x-site-code Header 篩選1. 發送 API 帶 x-site-code: C9 2. 發送相同 API 帶 x-site-code: A1 3. 比較回傳資料1. 兩次回傳的資料不同 2. C9 回傳僅含 siteCode=C9 的資料 3. A1 回傳僅含 siteCode=A1 的資料P1
TC-ISO-API-002siteCode query param 篩選1. 發送 API 帶 ?siteCode=C9 2. 發送相同 API 帶 ?siteCode=A11. 結果同上(@AdminSiteCode 先 header 後 query) 2. 查詢結果只含對應站點資料P1
TC-ISO-API-003不帶 siteCode1. 發送列表 API 不帶任何 siteCode 2. 檢查回傳資料1. @AdminSiteCode 返回 null 2. 回傳所有站點資料(全站模式) 3. 或依模組邏輯決定預設行為P2
TC-ISO-API-004跨站寫入阻擋1. 以 A1 站的 siteCode 查詢 C9 的資料 ID 2. 嘗試修改該筆資料1. 應被阻擋或拒絕 2. 不可跨站修改資料 3. siteCode 檢查在 Service 層P1
TC-ISO-API-005SiteCodeSubscriber 自動填入1. 建立新 Entity(不帶 siteCode) 2. 檢查資料庫中的 siteCode1. TypeORM Subscriber 自動填入 SITE_CODE 環境變數值 2. 不需手動指定 siteCodeP2
TC-ISO-API-006getSiteConfigs 回傳全站1. 呼叫 /site-config/admin/list 2. 不帶 siteCode1. 必須回傳所有站點資料 2. 此 API 跳過 siteCode 篩選 3. 前端用此填充 SiteSelectorP1

6.3 前台多站點隔離

TC-ID測試說明測試步驟預期結果優先級
TC-ISO-EC-001前台域名配置1. 檢查 useConfig.tsdomainConfig 2. 使用不同 hostname 存取1. 不同域名對應不同站點 2. site-name header 自動設定 3. 遊戲、活動、VIP 等資料對應該站點P1
TC-ISO-EC-002前台主題隔離1. A 站使用主題 1 2. B 站使用主題 2 3. 分別存取1. 各站點顯示對應主題色彩 2. CSS 變數不互相干擾 3. 主題來源:後端 site-themeP2
TC-ISO-EC-003前台遊戲列表隔離1. A 站有遊戲商 X 2. B 站沒有遊戲商 X 3. 分別查看遊戲大廳1. A 站顯示遊戲商 X 2. B 站不顯示遊戲商 X 3. 遊戲列表完全獨立P1
TC-ISO-EC-004前台活動隔離1. A 站有活動 Y 2. B 站沒有活動 Y1. 各站只顯示自己的活動 2. 不可跨站領取活動P1
TC-ISO-EC-005前台客服管道隔離1. A 站啟用 Line 客服 2. B 站未啟用 Line 客服1. A 站顯示 Line 客服入口 2. B 站不顯示 Line 客服 3. 各管道獨立配置P2

第 7 章:安全性測試

測試目標:驗證系統在認證、授權、資料保護、輸入驗證等方面的安全性,確保平台不受常見攻擊向量的威脅。 前置條件:系統已部署完成,具備有效的測試帳號(前台用戶、後台管理員各權限等級)。 涵蓋範圍:JWT 認證、RBAC 權限、2FA 雙因素驗證、輸入注入防護、密碼安全、資料存取控制、API 安全。


7.1 JWT 認證測試

測試範圍:前台用戶 JWT Bearer Token(7 天過期)與後台管理員 AdminJWT(獨立策略,payload 含 role: 'admin')。 相關元件JwtAuthGuardAdminJwtAuthGuardOptionalJwtAuthGuard

7.1.1 前台 JWT 認證

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-JWT-001有效 JWT 存取受保護端點1. 使用帳密登入取得 JWT Token 2. 在 Authorization header 帶入 Bearer {token} 3. 呼叫 GET /api/auth/profile1. HTTP 200 2. 回傳用戶個人資料 3. code: 200P1
TC-SEC-JWT-002過期 JWT 存取端點1. 取得有效 JWT Token 2. 模擬 Token 過期(修改 exp 時間戳或等待 7 天) 3. 使用過期 Token 呼叫 API1. HTTP 401 2. code: 401 3. message: "Unauthorized" 4. 前端收到 401 後觸發 token 重取流程P1
TC-SEC-JWT-003格式錯誤的 JWT1. 構造一個格式錯誤的 JWT(如 Bearer abc.def.ghi) 2. 使用該 Token 呼叫受保護端點1. HTTP 401 2. Token 解析失敗 3. 不回傳任何敏感錯誤訊息P1
TC-SEC-JWT-004缺少 Authorization Header1. 不帶任何 Authorization header 2. 呼叫 GET /api/auth/profile1. HTTP 401 2. message: "Unauthorized" 3. 明確指示需要認證P1
TC-SEC-JWT-005前台 Token 存取後台端點1. 使用前台用戶登入取得 JWT Token 2. 使用該 Token 呼叫 GET /api/admin/list1. HTTP 401 2. AdminJwtAuthGuard 拒絕前台 Token 3. 前後台認證策略完全隔離 4. payload 不含 role: 'admin'P1
TC-SEC-JWT-006後台 Token 存取前台端點1. 使用後台管理員登入取得 AdminJWT Token 2. 使用該 Token 呼叫 GET /api/auth/profile1. HTTP 401 2. JwtAuthGuard 拒絕 Admin Token 3. 兩套策略互不通用P1
TC-SEC-JWT-007tokenVersion 不匹配強制重認證1. 用戶登入取得 JWT(含 tokenVersion) 2. 後台管理員修改該用戶資料(觸發 tokenVersion 遞增) 3. 用戶使用原 Token 呼叫 API1. tokenVersion 檢查失敗 2. Redis 快取 cache:auth:tv:{userId} 中的版本不匹配 3. 強制用戶重新登入P1
TC-SEC-JWT-008修改密碼後舊 Token 失效1. 用戶登入取得 JWT Token 2. 用戶修改密碼 3. 使用修改前的 Token 呼叫 API1. 密碼修改觸發 tokenVersion 遞增 2. 舊 Token 失效 3. 需重新登入取得新 TokenP1
TC-SEC-JWT-009登出後 Token 失效1. 用戶登入取得 JWT Token 2. 呼叫登出 API 3. 使用登出前的 Token 呼叫受保護端點1. 登出操作使 Token 失效(tokenVersion 或黑名單) 2. 舊 Token 無法使用 3. 返回 401P1
TC-SEC-JWT-010相同帳號多裝置並發登入1. 在瀏覽器 A 登入帳號 X 2. 在瀏覽器 B 登入帳號 X 3. 兩邊同時呼叫 API1. 兩邊都能正常使用(系統允許多裝置登入) 2. 各自 Token 獨立有效 3. 裝置指紋記錄分別儲存P2

7.1.2 後台 AdminJWT 認證

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-ADMJWT-001管理員有效 Token 存取1. 後台管理員登入取得 AdminJWT 2. 呼叫 GET /api/admin/list1. HTTP 200 2. 回傳管理員列表 3. Token payload 含 role: 'admin'P1
TC-SEC-ADMJWT-002管理員 Token 過期1. 取得 AdminJWT Token 2. 模擬 Token 過期 3. 呼叫後台 API1. HTTP 401 2. 前端 NextAuth 觸發 session 刷新 3. 若刷新失敗導向登入頁P1
TC-SEC-ADMJWT-003管理員 tokenVersion 失效1. 管理員 A 登入取得 Token 2. Root 管理員修改管理員 A 的權限 3. 管理員 A 使用原 Token 呼叫 API1. tokenVersion 遞增 2. Redis cache:admin:tv:{adminId} 檢查失敗 3. 強制管理員 A 重新登入P1
TC-SEC-ADMJWT-004管理員帳號停用後 Token 失效1. 管理員正常登入 2. Root 停用該管理員帳號 3. 被停用的管理員呼叫 API1. Token 驗證時檢查帳號狀態 2. 已停用帳號拒絕存取 3. 返回 401P1
TC-SEC-ADMJWT-005NextAuth Session 與 JWT 同步1. 管理員登入(NextAuth 建立 session) 2. 檢查 apiClient 的 Authorization header 3. 呼叫後台 API1. NextAuth JWT 策略正確產生 session 2. apiClient 從 SessionSync 快取取得 token 3. Bearer token 正確傳遞P2
TC-SEC-ADMJWT-006401 自動重試機制1. 管理員 Token 因某原因失效 2. 前端呼叫 API 收到 401 3. 觀察 apiClient 的行為1. apiClient interceptor 捕獲 401 2. 清除舊 token → 重取 session → retry 3. 若 retry 仍失敗,導向登入頁 4. 不會無限重試P2

7.1.3 OptionalJwtAuthGuard 測試

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-OPTJWT-001帶 Token 的可選認證1. 使用有效 Token 呼叫支援可選認證的端點(如遊戲列表) 2. 檢查回應1. HTTP 200 2. 回傳含用戶相關資訊(如最近遊玩記錄) 3. 請求內可取得用戶身份P2
TC-SEC-OPTJWT-002不帶 Token 的可選認證1. 不帶 Authorization header 呼叫相同端點 2. 檢查回應1. HTTP 200(不返回 401) 2. 回傳公開資料(無用戶專屬內容) 3. 用戶身份為 nullP2
TC-SEC-OPTJWT-003帶無效 Token 的可選認證1. 使用無效 Token 呼叫可選認證端點1. HTTP 200(不返回 401) 2. 視為未登入 3. 回傳公開資料P3

7.2 權限(RBAC)測試

測試範圍:16 個權限模組 × 2 個操作(read/write)= 32 種權限。 權限模組:admin, admin-group, admin-log, user, deposit, withdrawal, promo, promo-tag, affiliate, vip, game, risk, report, vendor, finance, site-config。 群組類型:root(全權限)、super_admin(除 site-config)、general_admin(唯讀)、custom(自訂)。 相關元件PermissionsGuard@RequirePermissions()usePermissions hook。

7.2.1 群組類型權限測試

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-RBAC-001root 群組全權限存取1. 以 root 群組管理員登入 2. 逐一存取所有 32 種權限對應的 API 端點 3. 包含所有 16 模組的 read 和 write1. 全部 32 個權限檢查通過 2. 包含 site-config:readsite-config:write 3. isRoot() 返回 true 4. 所有 API 返回 200P1
TC-SEC-RBAC-002super_admin 權限範圍1. 以 super_admin 群組管理員登入 2. 存取 site-config 相關端點 3. 存取其他 15 個模組的 read/write 端點1. site-config 相關操作被拒絕(403) 2. 其他 15 個模組的 30 個權限全部通過 3. isRoot() 返回 false 4. can('site-config:read') 返回 falseP1
TC-SEC-RBAC-003general_admin 唯讀權限1. 以 general_admin 群組管理員登入 2. 嘗試讀取各模組資料 3. 嘗試寫入(新增/修改/刪除)操作1. 所有 read 操作通過 2. 所有 write 操作被拒絕(403) 3. canRead('*') 返回 true 4. canWrite('*') 返回 falseP1
TC-SEC-RBAC-004custom 群組自訂權限1. 建立 custom 群組,僅勾選 user:readdeposit:readdeposit:write 2. 以該群組管理員登入 3. 測試各操作1. user:read → 通過 2. user:write → 拒絕 3. deposit:read → 通過 4. deposit:write → 通過 5. 其他模組全部拒絕P1
TC-SEC-RBAC-005無 write 權限嘗試寫入1. 以只有 promo:read 權限的管理員登入 2. 嘗試 POST /api/admin/promos/create1. HTTP 403 Forbidden 2. PermissionsGuard 攔截 3. @RequirePermissions('promo:write') 檢查失敗P1
TC-SEC-RBAC-006無 read 權限嘗試讀取1. 以沒有 report:read 權限的管理員登入 2. 嘗試 GET /api/admin/reports/overview1. HTTP 403 Forbidden 2. 無法取得報表資料 3. 權限檢查在 Controller 層級觸發P1
TC-SEC-RBAC-007PermissionsGuard 元資料檢查1. 對一個需要 game:write 權限的端點 2. 分別用有/無該權限的帳號存取 3. 檢查 Guard 行為1. Guard 讀取 @RequirePermissions('game:write') metadata 2. 與管理員群組權限比對 3. 有權限 → 放行 4. 無權限 → 403P1
TC-SEC-RBAC-008群組權限快取失效測試1. 管理員 A 登入(群組權限被快取至 Redis,60s TTL) 2. Root 修改管理員 A 所屬群組的權限 3. 管理員 A 在快取有效期內呼叫 API 4. 等待 60 秒後再次呼叫1. 快取有效期內:使用舊權限(可能仍能存取) 2. 快取過期後:使用新權限 3. Redis key: cache:admin-group:perms:{groupId} 4. TTL 60 秒P2

7.2.2 前端權限控制測試

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-RBAC-009Sidebar 選單依權限隱藏1. 以 custom 群組管理員登入(僅有 user、deposit 權限) 2. 檢查側邊欄選單項目1. 僅顯示「玩家管理」和「財務管理 > 存款」相關項目 2. 遊戲管理、VIP、代理等選單隱藏 3. sidebar 檢查 Feature Flag + RBACP1
TC-SEC-RBAC-010直接 URL 存取無權限頁面1. 以無 game 權限的管理員登入 2. 在瀏覽器直接輸入 /game/providers URL1. 頁面顯示 AccessDenied 元件 2. 不顯示任何資料 3. 提示無存取權限P1
TC-SEC-RBAC-011usePermissions Hook 行為1. 在 React DevTools 檢查 usePermissions 返回值 2. 驗證各方法1. can('admin:read') 正確返回 boolean 2. canRead('admin') 等同 can('admin:read') 3. canWrite('admin') 等同 can('admin:write') 4. isRoot() 正確判斷 groupTypeP2

7.2.3 各模組權限逐一驗證

TC-ID模組read 端點write 端點預期行為
TC-SEC-PERM-001adminGET /admin/listPOST /admin/register管理員列表讀取 / 新增管理員
TC-SEC-PERM-002admin-groupGET /admin/groups/listPOST /admin/groups/create群組列表讀取 / 新增群組
TC-SEC-PERM-003admin-logGET /admin/logs/listN/A(僅 read)操作紀錄讀取
TC-SEC-PERM-004userGET /admin/finance/users/listPATCH /admin/finance/users/:id用戶列表讀取 / 編輯用戶
TC-SEC-PERM-005depositGET /admin/finance/deposit-review/listPOST /admin/finance/deposit-review/:id/review存款列表讀取 / 審核存款
TC-SEC-PERM-006withdrawalGET /admin/finance/withdrawals/listPOST /admin/finance/withdrawals/:id/review提款列表讀取 / 審核提款
TC-SEC-PERM-007promoGET /admin/promos/listPOST /admin/promos/create活動列表讀取 / 新增活動
TC-SEC-PERM-008promo-tagGET /admin/promo-tags/listPOST /admin/promo-tags/create活動標籤讀取 / 新增標籤
TC-SEC-PERM-009affiliateGET /affiliate/admin/agentsPOST /affiliate/admin/create-agent代理列表讀取 / 新增代理
TC-SEC-PERM-010vipGET /vip/admin/levelsPOST /vip/admin/levelsVIP 等級讀取 / 新增等級
TC-SEC-PERM-011gameGET /game/admin/providersPOST /game/admin/providers遊戲供應商讀取 / 新增供應商
TC-SEC-PERM-012riskGET /admin/risk/ip-rules/listPOST /admin/risk/ip-rules/createIP 規則讀取 / 新增規則
TC-SEC-PERM-013reportGET /admin/reports/overviewN/A(僅 read + export)報表讀取 / 匯出
TC-SEC-PERM-014vendorGET /admin/vendor-groups/listPOST /admin/vendor-groups/create金流群組讀取 / 新增群組
TC-SEC-PERM-015financeGET /admin/finance/bank-cards/listPOST /admin/finance/adjust-balance銀行卡讀取 / 手動調帳
TC-SEC-PERM-016site-configGET /site-config/admin/listPOST /site-config/admin站點列表讀取 / 新增站點

7.3 2FA(Google Authenticator)測試

測試範圍:後台管理員的 TOTP 雙因素認證(Google Authenticator)。 相關元件google-auth-dialog.tsx(狀態:idle → qr → verify)、後端 speakeasy 套件。 流程:啟用 → QR Code + Secret → 掃描 → 輸入 6 位驗證碼確認;停用 → 輸入當前 TOTP 驗證碼。

7.3.1 啟用 2FA 流程

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-2FA-001請求啟用 2FA 產生 QR Code1. 管理員登入後台 2. 進入個人資料頁 3. 點擊「啟用 Google Authenticator」 4. 檢查對話框狀態1. 對話框從 idle 進入 qr 狀態 2. 顯示 QR Code 圖片 3. 顯示 Secret Key(供手動輸入) 4. QR Code 可被 Google Authenticator App 掃描 5. Secret 為 base32 編碼P1
TC-SEC-2FA-002輸入正確 TOTP 碼啟用1. 掃描 QR Code 取得 TOTP 2. 在對話框輸入當前 6 位驗證碼 3. 點擊確認1. 對話框從 qr 進入 verify 狀態 2. 驗證通過 3. 2FA 啟用成功 4. 個人資料頁顯示 2FA 已啟用 5. 後端儲存加密後的 SecretP1
TC-SEC-2FA-003輸入錯誤 TOTP 碼1. 掃描 QR Code 2. 輸入錯誤的 6 位數字(如 000000) 3. 點擊確認1. 驗證失敗 2. 顯示錯誤提示 3. 2FA 未啟用 4. 可重新輸入 5. Secret 未被儲存P1
TC-SEC-2FA-004輸入非數字或位數不足1. 在驗證碼欄位輸入字母或 5 位數字 2. 嘗試提交1. 前端 Zod 驗證攔截 2. 顯示格式錯誤提示 3. 不發送 API 請求P2
TC-SEC-2FA-005已啟用 2FA 再次嘗試啟用1. 管理員已啟用 2FA 2. 再次點擊啟用按鈕1. 系統提示已啟用 2. 或不顯示啟用按鈕(改為停用按鈕)P3

7.3.2 使用 2FA 登入

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-2FA-006啟用 2FA 後登入需要驗證碼1. 管理員已啟用 2FA 2. 輸入帳號密碼點擊登入 3. 檢查登入流程1. 帳密驗證通過後 2. 顯示 TOTP 驗證碼輸入欄位 3. 不直接發放 JWT Token 4. 需完成兩步驟才能登入P1
TC-SEC-2FA-007輸入正確 TOTP 碼登入1. 帳密驗證通過進入 2FA 步驟 2. 從 Google Authenticator App 取得當前驗證碼 3. 輸入驗證碼提交1. TOTP 驗證通過 2. 發放 AdminJWT Token 3. 成功登入後台 4. 導向 Dashboard 頁面P1
TC-SEC-2FA-008輸入錯誤 TOTP 碼登入1. 帳密驗證通過進入 2FA 步驟 2. 輸入錯誤驗證碼1. 登入失敗 2. 顯示驗證碼錯誤 3. 不發放 Token 4. 可重試 5. 記錄登入失敗紀錄P1
TC-SEC-2FA-009時間窗口容差測試1. 使用剛過期的 TOTP 碼(前一個 30 秒週期) 2. 嘗試登入1. speakeasy 預設允許 ±1 個時間窗口(30 秒容差) 2. 剛過期的碼可能仍然有效 3. 超過容差範圍的碼無效P2
TC-SEC-2FA-010未啟用 2FA 的管理員登入1. 管理員未啟用 2FA 2. 輸入帳密登入1. 正常帳密驗證後直接發放 Token 2. 不顯示 TOTP 步驟 3. 直接導向 DashboardP1

7.3.3 停用 2FA

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-2FA-011輸入正確 TOTP 停用 2FA1. 管理員已啟用 2FA 2. 進入個人資料頁點擊「停用 2FA」 3. 輸入當前 TOTP 驗證碼 4. 確認停用1. 驗證碼正確 2. 2FA 成功停用 3. 後端清除 Secret 4. 後續登入不再要求 TOTPP1
TC-SEC-2FA-012輸入錯誤 TOTP 嘗試停用1. 管理員已啟用 2FA 2. 點擊停用 3. 輸入錯誤驗證碼1. 驗證失敗 2. 2FA 仍然啟用 3. 防止未授權停用P1
TC-SEC-2FA-013停用後重新啟用1. 管理員停用 2FA 2. 重新啟用 2FA 3. 掃描新 QR Code1. 產生全新的 Secret 2. 舊 QR Code/Secret 失效 3. 需重新在 App 中設定P2

7.4 輸入驗證與注入測試

測試範圍:SQL 注入、XSS 跨站腳本、路徑遍歷、命令注入、CSRF、檔案上傳安全、請求大小限制。 核心防護:TypeORM 參數化查詢、Zod 前端驗證、class-validator 後端驗證、Helmet 安全標頭。

7.4.1 SQL 注入防護

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-INJ-001搜尋欄位 SQL 注入1. 在玩家搜尋欄位輸入 ' OR 1=1 -- 2. 點擊搜尋 3. 檢查 API 請求和回應1. TypeORM 使用參數化查詢(:keyword) 2. 輸入被視為普通字串 3. 不回傳所有資料 4. 回傳空結果或僅匹配的資料P1
TC-SEC-INJ-002登入表單 SQL 注入1. 在登入帳號欄位輸入 admin' OR '1'='1 2. 密碼隨意輸入 3. 嘗試登入1. 登入失敗 2. TypeORM 參數化查詢防護 3. 不回傳 JWT Token 4. 記錄登入失敗紀錄P1
TC-SEC-INJ-003URL 參數 SQL 注入1. 在 URL 參數中注入 SQL(如 ?userId=1;DROP TABLE auth-user) 2. 發送 API 請求1. 參數經過 class-validator 驗證 2. 非法格式被拒絕 3. 資料庫不受影響 4. 返回 400 Bad RequestP1
TC-SEC-INJ-004JSON body SQL 注入1. 在 POST/PATCH 請求的 JSON body 中注入 SQL 語句 2. 如 { "username": "admin'; DROP TABLE--" }1. DTO class-validator 驗證字串格式 2. TypeORM 參數化查詢 3. 不執行注入的 SQLP1
TC-SEC-INJ-005排序欄位 SQL 注入1. 在排序參數中注入 SQL(如 ?sortBy=id;DELETE FROM users) 2. 發送列表 API 請求1. 排序欄位經過白名單驗證 2. 非允許的欄位被忽略或拒絕 3. 使用預設排序P2
TC-SEC-INJ-006LIKE 搜尋特殊字元1. 在搜尋欄位輸入 %_\ 等 SQL LIKE 特殊字元 2. 檢查搜尋結果1. 特殊字元被正確轉義 2. 搜尋 % 不會匹配所有記錄 3. 精確搜尋包含這些字元的資料P2

7.4.2 XSS 跨站腳本防護

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-XSS-001文字輸入欄位 XSS1. 在任何文字輸入欄位輸入 <script>alert('XSS')</script> 2. 提交表單 3. 在列表頁查看該資料1. 腳本不被執行 2. React/Vue 預設轉義 HTML 3. 顯示為純文字 <script>alert('XSS')</script> 4. 無彈窗出現P1
TC-SEC-XSS-002i18n 多語系欄位 XSS1. 在多語系 JSON 欄位中注入 {"zh-TW": "<img src=x onerror=alert(1)>"} 2. 儲存並在前台顯示1. resolveText() 解析後的文字經過轉義 2. 不執行 onerror 事件 3. 前端框架自動轉義 HTMLP1
TC-SEC-XSS-003富文本編輯器(Tiptap)XSS1. 在 Tiptap 編輯器中透過 HTML 模式輸入 <script>alert('XSS')</script> 2. 儲存活動內容 3. 在前台查看1. Tiptap 內建 sanitizer 過濾危險標籤 2. <script> 標籤被移除 3. 只保留允許的 HTML 標籤(p, h1-h6, strong, em, ul, ol, li, a, img 等) 4. 安全的 HTML 輸出P1
TC-SEC-XSS-004URL 參數 XSS(反射型)1. 在 URL 中注入 ?search=<script>alert(1)</script> 2. 頁面載入1. 搜尋參數不直接渲染為 HTML 2. 經過 React/Vue 轉義 3. 無腳本執行P1
TC-SEC-XSS-005站內信內容 XSS1. 管理員發送含惡意腳本的站內信 2. 前台用戶查看信件1. 信件內容經過 sanitize 2. 惡意腳本被移除或轉義 3. 安全顯示信件內容P1
TC-SEC-XSS-006HTTP Response Header 安全1. 檢查 API 回應的 HTTP Headers1. 包含 X-Content-Type-Options: nosniff 2. 包含 X-Frame-Options: DENYSAMEORIGIN 3. 包含 X-XSS-Protection: 1; mode=block(如適用) 4. Content-Type 正確設定P2

7.4.3 路徑遍歷與命令注入

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-PATH-001檔案上傳路徑遍歷1. 上傳檔案時修改 filename 為 ../../etc/passwd 2. 或使用 ..%2F..%2F 編碼形式 3. 發送上傳請求1. 檔案名稱經過清理(sanitize) 2. 路徑遍歷字元被移除 3. 檔案儲存至 R2 指定路徑 4. 不會存取伺服器本地檔案系統P1
TC-SEC-PATH-002R2 路徑操作遍歷1. 在 R2 create-folder API 中使用 ../../ 路徑 2. 在 R2 delete API 中使用遍歷路徑1. R2 模組驗證路徑合法性 2. 不允許遍歷到其他 bucket/prefix 3. 路徑限定在站點目錄下P1
TC-SEC-CMD-001搜尋參數命令注入1. 在搜尋欄位輸入 ; rm -rf / 或 `cat /etc/passwd` 2. 發送 API 請求1. 後端不執行 shell 命令 2. 所有查詢透過 ORM 3. 輸入被視為普通字串
TC-SEC-CMD-002檔案名稱命令注入1. 上傳檔案名稱含 $(whoami).jpg 2. 或 `whoami`.jpg1. 檔案名稱被清理 2. 特殊字元被移除或轉義 3. R2 上傳使用安全的 key 生成P2

7.4.4 CSRF 與請求安全

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-CSRF-001CSRF 防護驗證1. 從外部網站構造一個 POST 請求到後台 API 2. 不帶 JWT Token 3. 發送請求1. 請求被拒絕(缺少 Authorization) 2. JWT Token 機制本身防護 CSRF(Token 在 header 中,非 cookie 自動攜帶)P1
TC-SEC-CSRF-002Cookie 安全屬性1. 檢查 NextAuth session cookie 的屬性 2. 檢查 locale cookie 屬性1. Session cookie 設定 HttpOnly 2. Session cookie 設定 Secure(生產環境) 3. SameSite 設定為 Lax 或 StrictP2
TC-SEC-REQ-001超大請求 body 拒絕1. 構造一個超過限制大小的 JSON body(如 50MB) 2. 發送 POST 請求1. NestJS 的 body-parser 限制生效 2. 返回 413 Payload Too Large 3. 伺服器不因大請求而崩潰P1
TC-SEC-REQ-002上傳檔案大小限制1. 嘗試上傳超過限制的檔案(R2 上傳) 2. 檢查回應1. 檔案大小限制生效 2. 返回錯誤提示 3. 不佔用伺服器過多記憶體P1
TC-SEC-REQ-003Content-Type 驗證1. 發送 JSON API 但使用 Content-Type: text/plain 2. 檢查回應1. NestJS 驗證 Content-Type 2. 非預期格式被拒絕或正確處理P3

7.4.5 檔案上傳安全

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-FILE-001偽裝 Content-Type 上傳1. 將 .exe 檔案的 Content-Type 改為 image/png 2. 嘗試上傳1. 後端驗證實際檔案內容(magic bytes) 2. 或白名單驗證副檔名 3. 拒絕不合法的檔案類型P1
TC-SEC-FILE-002上傳含惡意 metadata 的圖片1. 製作含 XSS payload 的 EXIF 資料的圖片 2. 上傳至 R21. 圖片 metadata 不被解析為 HTML 2. 直接以 image/* MIME 回傳 3. 不會觸發腳本執行P2
TC-SEC-FILE-003空檔案上傳1. 上傳一個 0 bytes 的檔案1. 前端或後端驗證檔案非空 2. 返回驗證錯誤P3
TC-SEC-FILE-004超長檔案名稱1. 使用 300 字元以上的檔案名稱上傳1. 檔案名稱被截斷或拒絕 2. 不導致系統錯誤P3

7.5 密碼安全測試

測試範圍:密碼儲存方式、密碼強度要求、密碼變更流程、OAuth 用戶密碼設定。

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-PWD-001密碼以 bcrypt 雜湊儲存1. 建立一個測試帳號 2. 查詢資料庫中的密碼欄位 3. 檢查儲存格式1. 密碼不以明文儲存 2. 使用 bcrypt 雜湊($2b$ 開頭) 3. 包含 salt(bcrypt 內建) 4. 無法反推原始密碼P1
TC-SEC-PWD-002密碼最低強度要求1. 嘗試註冊密碼為 123 2. 嘗試密碼為 abcdef 3. 嘗試密碼為 Abc123!@#1. 過短密碼被拒絕 2. 不符合複雜度要求的密碼被拒絕 3. 符合要求的密碼通過 4. Zod schema 驗證生效P1
TC-SEC-PWD-003修改密碼需驗證當前密碼1. 登入帳號 2. 進入修改密碼頁面 3. 不輸入當前密碼直接設定新密碼 4. 輸入錯誤的當前密碼 5. 輸入正確的當前密碼1. 不輸入當前密碼 → 驗證失敗 2. 錯誤的當前密碼 → 拒絕修改 3. 正確的當前密碼 → 允許修改 4. 修改成功後舊 Token 失效P1
TC-SEC-PWD-004OAuth 用戶設定密碼1. 使用 Google OAuth 註冊的用戶 2. 進入設定密碼頁面 3. 直接設定新密碼(不需要當前密碼)1. OAuth 用戶首次設定密碼不需要舊密碼 2. 設定完成後可使用帳密登入 3. 仍可使用 OAuth 登入P2
TC-SEC-PWD-005登入失敗紀錄記錄1. 使用錯誤密碼嘗試登入 3 次 2. 查詢 auth-user-login-log1. 每次失敗都記錄一筆紀錄 2. 包含 IP 地址、時間戳、帳號 3. 後台可查詢登入失敗紀錄 4. 支援按日期和關鍵字篩選P1
TC-SEC-PWD-006密碼不在 API 回應中洩漏1. 呼叫用戶列表 API 2. 呼叫用戶詳情 API 3. 檢查所有回應欄位1. 任何 API 回應都不包含密碼欄位 2. 即使是 hash 過的密碼也不回傳 3. TypeORM select 排除 password 欄位P1
TC-SEC-PWD-007管理員密碼安全1. 建立管理員帳號 2. 查詢管理員資料 API 3. 檢查密碼欄位1. 管理員密碼同樣以 bcrypt 儲存 2. API 不回傳密碼 3. 管理員修改密碼需驗證舊密碼P1
TC-SEC-PWD-008密碼與帳號不可相同1. 嘗試設定密碼與帳號相同1. 驗證拒絕 2. 提示密碼不可與帳號相同(若有此規則)P3

7.6 資料存取控制測試

測試範圍:確保用戶只能存取自己的資料,代理只能看到自己的下線,前台和後台完全隔離。

7.6.1 前台用戶資料隔離

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-ACCESS-001用戶 A 無法存取用戶 B 的錢包1. 用戶 A 登入取得 JWT 2. 嘗試呼叫用戶 B 的銀行卡/加密地址 API 3. 或修改請求中的 userId1. 後端根據 JWT payload 的 userId 查詢 2. 無法取得他人資料 3. 返回空結果或 403P1
TC-SEC-ACCESS-002用戶 A 無法存取用戶 B 的交易紀錄1. 用戶 A 登入 2. 嘗試查看用戶 B 的存款/提款/投注紀錄1. API 根據 JWT userId 過濾 2. 僅返回用戶 A 自己的交易紀錄 3. 無法透過修改參數取得他人資料P1
TC-SEC-ACCESS-003用戶 A 無法修改用戶 B 的資料1. 用戶 A 登入 2. 嘗試修改用戶 B 的個人資料(修改請求中的 ID)1. 後端驗證操作者身份 2. 拒絕跨用戶修改 3. 返回 403 或忽略不屬於自己的 IDP1
TC-SEC-ACCESS-004用戶餘額只能自查1. 用戶 A 登入 2. 查詢餘額 API 3. 嘗試查詢用戶 B 的餘額1. 餘額 API 根據 JWT userId 返回 2. 無法查詢他人餘額 3. 不接受外部傳入 userId 參數P1

7.6.2 代理資料隔離

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-ACCESS-005代理 A 無法查看代理 B 的下線1. 代理 A 登入 2. 呼叫下線列表 API 3. 嘗試查詢代理 B 的下線1. API 根據代理身份過濾 2. 僅返回代理 A 的下線 3. 無法跨代理查詢P1
TC-SEC-ACCESS-006非代理用戶無法存取代理 API1. 一般用戶(未成為代理)登入 2. 呼叫代理相關 API(如 /affiliate/dashboard1. 代理身份檢查失敗 2. 返回錯誤(非代理用戶) 3. 無法存取代理功能P1
TC-SEC-ACCESS-007maskAccount 隱私保護1. 代理查看下線列表 2. 檢查下線帳號顯示1. 帳號透過 maskAccount() 處理 2. 中間字元被遮蔽(如 ab***fg) 3. 保護下線隱私P2
TC-SEC-ACCESS-008代理結算只能查看自己的1. 代理 A 登入 2. 查看佣金結算列表 3. 嘗試存取代理 B 的結算紀錄1. 結算紀錄依代理 ID 過濾 2. 僅顯示自己的結算 3. 無法跨代理查詢P1

7.6.3 前後台隔離

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-ACCESS-009前台用戶無法存取 /admin 端點1. 前台用戶登入取得 JWT 2. 呼叫 GET /api/admin/list 3. 呼叫 GET /api/admin/reports/overview1. 所有 /admin/* 端點拒絕前台 Token 2. AdminJwtAuthGuard 攔截 3. 返回 401P1
TC-SEC-ACCESS-010後台管理員無法使用前台功能1. 後台管理員取得 AdminJWT 2. 嘗試呼叫 POST /api/deposit(前台存款) 3. 嘗試呼叫 POST /api/game/launch(遊戲啟動)1. 前台端點要求 JwtAuthGuard 2. AdminJWT 不被接受 3. 返回 401P1
TC-SEC-ACCESS-011admin-user 與 auth-user 完全分離1. 確認資料庫中 admin-user 表和 auth-user 表 2. 驗證無 JOIN 或共用 ID 的情況1. 兩張表完全獨立 2. 帳號系統分離 3. 無法透過前台帳號登入後台 4. 無法透過後台帳號使用前台功能P1

7.7 API 安全測試

測試範圍:CORS 配置、速率限制、回應安全、敏感資訊洩漏防護。

7.7.1 CORS 跨域安全

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-API-001CORS 白名單驗證1. 從允許的來源(如 localhost:3010)發送請求 2. 從不允許的來源(如 evil.com)發送請求 3. 檢查 Access-Control-Allow-Origin1. 允許的來源 → 請求通過,CORS header 正確 2. 不允許的來源 → 被瀏覽器阻擋 3. 不使用 * 通配符(生產環境)P1
TC-SEC-API-002CORS preflight OPTIONS 請求1. 從跨域來源發送 OPTIONS 請求 2. 檢查回應 header1. 返回正確的 Access-Control-Allow-Methods 2. 返回正確的 Access-Control-Allow-Headers(含 Authorization, x-site-code, site-name, locales) 3. Access-Control-Max-Age 設定合理值P2
TC-SEC-API-003CORS 不允許攜帶 Cookie1. 檢查 Access-Control-Allow-Credentials1. 根據系統配置正確設定 2. 若使用 JWT header 認證,credentials 可設為 falseP3

7.7.2 速率限制

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-RATE-001登入端點速率限制1. 對 POST /api/auth/login 短時間內發送 100 次請求 2. 觀察回應變化1. 前 N 次正常回應 2. 超過限制後返回 429 Too Many Requests 3. 防止暴力破解P1
TC-SEC-RATE-002註冊端點速率限制1. 對 POST /api/auth/register 短時間內大量請求1. 速率限制生效 2. 超過後返回 429 3. 防止批量註冊P1
TC-SEC-RATE-003管理員登入速率限制1. 對 POST /api/admin/login 短時間內大量請求1. 速率限制生效 2. 記錄登入失敗 3. 防止管理員帳號暴力破解P1
TC-SEC-RATE-004一般 API 速率限制1. 對一般列表 API 短時間內發送大量請求(如 1000 次/秒)1. 速率限制或負載保護生效 2. 伺服器不因大量請求而崩潰 3. 返回適當的錯誤碼P2

7.7.3 回應安全與資訊洩漏防護

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-LEAK-001錯誤回應不洩漏內部資訊1. 觸發一個伺服器錯誤(如存取不存在的端點) 2. 檢查錯誤回應內容1. 不包含 stack trace 2. 不包含資料庫連線資訊 3. 不包含檔案路徑 4. 只回傳通用錯誤訊息P1
TC-SEC-LEAK-002404 回應不洩漏路由資訊1. 存取不存在的 API 路徑 2. 檢查回應1. 返回標準 404 格式 2. 不列出可用路由 3. 不暴露內部路由結構P2
TC-SEC-LEAK-003Server header 不洩漏版本1. 檢查 API 回應的 Server header1. 不包含 NestJS/Express 版本資訊 2. 或使用 Helmet 移除/覆蓋 Server headerP2
TC-SEC-LEAK-004Swagger UI 生產環境關閉1. 在生產環境存取 /api/docs1. Swagger UI 在生產環境不可用 2. 返回 404 3. 避免 API 結構洩漏P1
TC-SEC-LEAK-005敏感 Header 不暴露1. 檢查回應 headers 2. 確認不含敏感資訊1. 不包含 X-Powered-By(或已被 Helmet 移除) 2. 不包含內部 IP 3. 不包含 debug 資訊P2
TC-SEC-API-006裝置指紋安全傳輸1. 前台登入時附帶 FingerprintJS 產生的指紋 2. 檢查傳輸方式1. 指紋透過 HTTPS 加密傳輸 2. 指紋儲存在後端(非前端可讀) 3. 指紋用於風控反查,不回傳給其他用戶P2

7.7.4 API 端點安全總結

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-API-007所有寫入端點需認證1. 列出所有 POST/PATCH/DELETE 端點 2. 不帶 Token 逐一呼叫1. 所有寫入端點返回 401 2. 無任何未保護的寫入端點 3. 公開端點僅限 GET 查詢P1
TC-SEC-API-008管理員操作紀錄完整1. 管理員執行各種操作(新增/修改/刪除) 2. 查詢 admin-operation-log1. 所有管理員操作都有紀錄 2. 包含操作者、操作類型、時間、IP 3. 紀錄不可被刪除或修改P1
TC-SEC-API-009HTTP Method 限制1. 對 GET 端點發送 DELETE 請求 2. 對 POST 端點發送 GET 請求1. 方法不匹配返回 405 Method Not Allowed 2. 或返回 404 Not FoundP3
TC-SEC-API-010HTTPS 強制(生產環境)1. 在生產環境嘗試 HTTP 存取1. 自動重定向至 HTTPS 2. 或直接拒絕 HTTP 連線 3. HSTS header 設定P1

7.8 OAuth 安全測試

測試範圍:Google OAuth 與 Telegram OAuth 登入流程的安全性。

7.8.1 Google OAuth 安全

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-OAUTH-001Google OAuth 正常流程1. 點擊 Google 登入按鈕 2. 重定向至 Google 授權頁 3. 授權成功回調1. 正確重定向至 Google OAuth URL 2. callback URL 正確 3. 取得 Google profile 並建立/綁定帳號 4. 發放 JWT TokenP1
TC-SEC-OAUTH-002OAuth state 參數防 CSRF1. 檢查 OAuth URL 中的 state 參數 2. 偽造 state 回調1. OAuth URL 包含隨機 state 參數 2. 回調驗證 state 一致性 3. 偽造的 state 被拒絕P1
TC-SEC-OAUTH-003OAuth 回調偽造1. 不經過 Google 直接呼叫 callback URL 2. 帶上偽造的 code1. 偽造的 code 無法交換 token 2. 回調被拒絕 3. 不建立帳號P1
TC-SEC-OAUTH-004OAuth Token 不洩漏1. 檢查前端代碼和 URL 2. 驗證 Google access_token 不暴露1. Google access_token 僅在後端使用 2. 前端不儲存 Google token 3. 只使用系統自己的 JWTP2
TC-SEC-OAUTH-005Google 帳號已綁定其他用戶1. 用戶 A 已綁定 Google 帳號 X 2. 用戶 B 嘗試用 Google 帳號 X 登入1. 系統識別 Google 帳號已綁定 2. 自動登入用戶 A 3. 不建立重複帳號P1

7.8.2 Telegram OAuth 安全

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-OAUTH-006Telegram OAuth 正常流程1. 點擊 Telegram 登入 Widget 2. 授權成功1. Telegram 回傳用戶資訊 2. 後端驗證 hash 簽名 3. 建立/綁定帳號P1
TC-SEC-OAUTH-007Telegram hash 簽名驗證1. 偽造 Telegram 回調資料 2. 修改 hash 值1. 後端計算 HMAC-SHA256 驗證 hash 2. 偽造的 hash 被拒絕 3. 不建立帳號P1
TC-SEC-OAUTH-008Telegram 資料過期檢查1. 使用超過有效期的 Telegram 授權資料1. auth_date 時間戳檢查 2. 過期的授權被拒絕P2

7.9 裝置指紋安全測試

測試範圍:FingerprintJS v5 產生的裝置指紋在認證和風控中的安全應用。

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-FP-001指紋產生唯一性1. 在瀏覽器 A 產生指紋 2. 在瀏覽器 B 產生指紋 3. 比較兩個指紋1. 不同瀏覽器/裝置產生不同指紋 2. 相同瀏覽器多次產生相同指紋 3. 指紋不可預測P2
TC-SEC-FP-002指紋隨登入記錄1. 用戶登入時帶 fingerprint 2. 查詢 auth-user-login-log1. 登入紀錄包含指紋 2. 可用於風控反查 3. 指紋欄位不為空P1
TC-SEC-FP-003指紋用於風控反查1. 查詢某指紋的所有關聯帳號 2. 在後台 IP/FP 檢查頁面搜尋1. 回傳使用相同指紋的所有帳號 2. 可識別同一裝置多帳號 3. 支援多站點篩選P1
TC-SEC-FP-004指紋不回傳給前端用戶1. 檢查所有前台 API 回應 2. 確認無指紋欄位1. 用戶 API 不回傳其他用戶的指紋 2. 指紋僅用於後台管理和風控P2
TC-SEC-FP-005指紋 HTTPS 加密傳輸1. 監聽登入請求 2. 確認指紋傳輸方式1. 指紋透過 HTTPS POST body 傳送 2. 不在 URL 參數中暴露 3. 不在 Cookie 中明文儲存P2

7.10 S2S 遊戲回調安全測試

測試範圍:遊戲商 Server-to-Server 回調端點的安全性。

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-S2S-001BetSolutions 回調驗證1. 使用正確的簽名呼叫 BetSolutions 回調 2. 使用錯誤簽名呼叫1. 正確簽名 → 處理成功 2. 錯誤簽名 → 拒絕處理 3. 驗證機制保護回調端點P1
TC-SEC-S2S-002RSG 回調 DES 加解密1. 使用正確 DES 密鑰加密回調資料 2. 使用錯誤密鑰加密1. 正確密鑰 → 成功解密並處理 2. 錯誤密鑰 → 解密失敗,拒絕處理P1
TC-SEC-S2S-003回調冪等性1. 相同的遊戲交易回調發送兩次 2. 檢查用戶餘額和紀錄1. 第二次回調不重複處理 2. 餘額不重複增減 3. game_transaction 紀錄唯一P1
TC-SEC-S2S-004回調端點 IP 白名單1. 從允許的 IP 呼叫回調 2. 從不允許的 IP 呼叫回調1. 允許的 IP → 正常處理 2. 不允許的 IP → 拒絕(若有 IP 白名單)P2
TC-SEC-S2S-005回調資料完整性1. 發送缺少必要欄位的回調 2. 發送包含額外欄位的回調1. 缺少必要欄位 → 驗證失敗 2. 額外欄位 → 忽略或拒絕 3. 不因不完整資料而崩潰P1
TC-SEC-S2S-006回調金額驗證1. 發送負數金額的回調 2. 發送超大金額的回調1. 負數金額 → 拒絕或適當處理 2. 超大金額 → 驗證範圍限制 3. 不因異常金額導致餘額錯誤P1

7.11 金流安全測試

測試範圍:存款、提款、調帳等金流操作的安全性和一致性。

7.11.1 存款安全

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-FIN-001存款回調簽名驗證1. 使用正確簽名的金流商回調 2. 使用偽造簽名的回調1. 正確簽名 → 更新訂單狀態 + 增加餘額 2. 偽造簽名 → 拒絕處理 3. 不因偽造回調增加餘額P1
TC-SEC-FIN-002存款訂單不可重複確認1. 對同一存款訂單發送兩次成功回調1. 第一次回調正常處理 2. 第二次回調因狀態已變更而忽略 3. 餘額只增加一次P1
TC-SEC-FIN-003存款金額篡改防護1. 提交存款申請(金額 1000 TWD) 2. 在回調中嘗試修改金額為 10000 TWD1. 後端驗證回調金額與訂單金額一致 2. 不一致時拒絕或標記異常 3. 不因金額篡改入帳錯誤P1
TC-SEC-FIN-004匯率時間鎖定1. 用戶發起存款(匯率 A) 2. 匯率變動為 B 3. 金流商回調成功1. 使用發起時的匯率 A 計算 USD 2. 不因回調時匯率 B 變動而改變金額 3. 訂單記錄使用的匯率值P1

7.11.2 提款安全

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-FIN-005提款餘額即時扣減1. 用戶餘額 1000 USD 2. 申請提款 800 USD 3. 立即再申請提款 300 USD1. 第一筆提款申請成功,餘額凍結 800 2. 第二筆提款檢查可用餘額(200 USD) 3. 第二筆因餘額不足被拒絕 4. 無超額提款P1
TC-SEC-FIN-006提款審核權限1. 非 withdrawal:write 權限的管理員嘗試審核 2. 有權限的管理員審核1. 無權限 → 403 2. 有權限 → 正常審核 3. 審核紀錄記入 admin-operation-logP1
TC-SEC-FIN-007提款至錯誤地址防護1. 提款至非用戶本人的銀行卡/加密地址1. 後端驗證提款目標屬於該用戶 2. 非本人地址 → 拒絕 3. 防止資金轉移至他人帳戶P1

7.11.3 調帳安全

TC-ID測試說明測試步驟預期結果優先級
TC-SEC-FIN-008手動調帳需 finance:write 權限1. 無 finance:write 的管理員嘗試調帳 2. 有權限的管理員調帳1. 無權限 → 403 2. 有權限 → 調帳成功 3. 調帳紀錄完整P1
TC-SEC-FIN-009調帳操作紀錄不可刪改1. 管理員執行手動調帳 2. 查詢操作紀錄 3. 嘗試修改紀錄1. 調帳操作自動記錄 2. 含操作者、金額、原因、時間 3. 紀錄不可被修改或刪除P1
TC-SEC-FIN-010調帳金額限制1. 嘗試調帳超大金額(如 999999999) 2. 嘗試調帳為負數餘額1. 有金額上限限制 2. 不可將餘額調為負數 3. decimal(18,6) 範圍內P2

7.12 安全性測試總結矩陣

說明:以下矩陣總結所有安全性測試的涵蓋範圍和狀態。

7.12.1 OWASP Top 10 對應

OWASP 風險對應測試覆蓋狀態
A01:2021 - Broken Access ControlTC-SEC-RBAC-, TC-SEC-ACCESS-完整覆蓋
A02:2021 - Cryptographic FailuresTC-SEC-PWD-001, TC-SEC-FIN-001部分覆蓋
A03:2021 - InjectionTC-SEC-INJ-, TC-SEC-XSS-完整覆蓋
A04:2021 - Insecure DesignTC-SEC-FIN-, TC-SEC-S2S-部分覆蓋
A05:2021 - Security MisconfigurationTC-SEC-API-, TC-SEC-LEAK-完整覆蓋
A06:2021 - Vulnerable Components需定期依賴掃描建議加入 CI
A07:2021 - Auth FailuresTC-SEC-JWT-, TC-SEC-2FA-, TC-SEC-OAUTH-*完整覆蓋
A08:2021 - Software/Data IntegrityTC-SEC-S2S-003, TC-SEC-FIN-002部分覆蓋
A09:2021 - Logging FailuresTC-SEC-API-008, TC-SEC-FIN-009部分覆蓋
A10:2021 - SSRFTC-SEC-PATH-, TC-SEC-CMD-基本覆蓋

7.12.2 安全測試案例統計

章節測試案例數P1P2P3
7.1 JWT 認證161240
7.2 RBAC 權限271863
7.3 2FA 測試13832
7.4 輸入驗證201352
7.5 密碼安全8521
7.6 資料存取11920
7.7 API 安全14752
7.8 OAuth 安全8530
7.9 裝置指紋5230
7.10 S2S 回調6510
7.11 金流安全10820
合計138923610

第 8 章:效能測試建議

測試目標:建立系統效能基準線,識別潛在瓶頸,確保在正常和高負載情境下系統表現穩定。 適用工具:Apache JMeter、k6、Artillery、Lighthouse(前端)、MySQL EXPLAIN ANALYZE。 注意事項:效能測試應在獨立環境執行,避免影響開發或生產環境。


8.1 API 回應時間基準

量測方式:每個端點至少測試 100 次,取 95th percentile(P95)作為基準。 前置條件:資料庫含 Seed 資料(5 站點 × 30 用戶 + 相關資料)。

8.1.1 回應時間目標

分類目標(P95)量測方式說明
列表查詢(分頁)< 200ms含 SQL 查詢 + 序列化/admin/finance/users/list?page=1&pageSize=20
單筆記錄查詢< 100ms含 SQL 查詢 + 序列化GET /admin/finance/users/:id
新增/修改操作< 300ms含驗證 + SQL 寫入POST /admin/promos/create
報表產生< 1000ms含聚合查詢 + 計算GET /admin/reports/overview
檔案上傳(R2)< 2000ms含檔案傳輸 + R2 寫入POST /admin/r2/upload
遊戲啟動< 500ms含用戶驗證 + 遊戲商 APIPOST /game/launch
登入/認證< 200ms含密碼驗證 + JWT 產生POST /auth/login
批次操作< 500ms含批次 SQL 寫入如 VIP rebate bulk upsert
CSV 匯出< 3000ms含查詢 + CSV 生成GET /admin/reports/export?type=players
站點設定載入< 150ms含 Redis 快取查詢GET /site-config/list

8.1.2 各模組端點效能基準

模組端點範例目標(P95)資料量假設
認證POST /auth/login< 200msbcrypt 比對
認證POST /auth/register< 300ms含 bcrypt hash + DB insert
用戶GET /admin/finance/users/list< 200ms10,000 用戶
存款POST /deposit< 300ms含金流商 API 呼叫
存款GET /admin/finance/deposit-review/list< 200ms50,000 訂單
提款GET /admin/finance/withdrawals/list< 200ms30,000 訂單
遊戲GET /game/providers< 100ms20 供應商
遊戲POST /game/launch< 500ms含遊戲商 API
VIPGET /vip/admin/levels< 100ms15 等級
VIPPOST /vip/admin/rebates/bulk< 500ms15 等級 × 8 類型 = 120 筆
報表GET /admin/reports/overview< 1000ms含 SUM/COUNT 聚合
報表GET /admin/reports/profit-loss< 1000ms含分組聚合
報表GET /admin/reports/bet-records< 200ms100,000 投注
代理GET /affiliate/admin/agents< 200ms5,000 代理
代理POST /affiliate/admin/trigger-settlement< 5000ms含大量計算
風控GET /admin/risk/ip-rules/list< 100ms1,000 規則
站內信GET /inbox/list< 150ms10,000 信件
R2POST /admin/r2/upload< 2000ms5MB 檔案
R2GET /admin/r2/list< 500ms含 R2 API 呼叫

8.2 大量資料分頁效能

測試目標:驗證在不同資料量下分頁查詢的效能表現,特別是深度分頁的效能降級。

8.2.1 分頁效能測試情境

TC-ID測試說明測試步驟預期結果優先級
TC-PERF-PAGE-0011,000 筆資料分頁1. 確保表格有 1,000 筆資料 2. 查詢 page=1, pageSize=20 3. 查詢 page=25, pageSize=20 4. 查詢 page=50, pageSize=201. 所有頁碼回應時間 < 200ms 2. total 正確為 1,000 3. 最後一頁資料正確 4. 分頁元件正確顯示P1
TC-PERF-PAGE-00210,000 筆資料含篩選1. 確保表格有 10,000 筆資料 2. 加入日期範圍篩選 3. 加入狀態篩選 4. 分頁查詢1. 篩選後回應時間 < 300ms 2. total 反映篩選後數量 3. 篩選條件有使用索引 4. 組合篩選效能可接受P1
TC-PERF-PAGE-003100,000 筆資料深度分頁1. 確保表格有 100,000 筆資料 2. 查詢 page=5000, pageSize=20(OFFSET 99,980) 3. 量測回應時間1. 深度分頁可能效能降級(OFFSET 大時 MySQL 效能下降) 2. 回應時間 < 1000ms(可接受) 3. 若超過,考慮 cursor-based pagination 4. 記錄效能數據供優化參考P2
TC-PERF-PAGE-004大量資料排序效能1. 100,000 筆資料 2. 依 createdAt DESC 排序 3. 依非索引欄位排序1. 有索引欄位排序 < 200ms 2. 無索引欄位排序可能較慢 3. 記錄差異供索引優化P2
TC-PERF-PAGE-005空結果快速回應1. 使用篩選條件使結果為空 2. 量測回應時間1. 空結果回應時間 < 100ms 2. 正確回傳 { items: [], total: 0 } 3. 不因計算 total 而延遲P3

8.2.2 分頁工具函式效能

項目說明預期行為
parsePagination(query)解析分頁參數1. 預設 page=1, pageSize=20 2. 最大 pageSize 限制(防止一次查全部) 3. 無效參數使用預設值
applyDateRange(qb, col, start, end)日期範圍篩選1. 使用 BETWEEN 查詢 2. 有使用 createdAt 索引 3. 時區轉換正確(UTC+8)
QueryBuilder .skip().take()TypeORM 分頁1. 轉換為 LIMIT ? OFFSET ? 2. OFFSET 大時效能紀錄

8.3 Redis 快取效能

測試目標:驗證 Redis 快取的命中率、失效機制、以及快取與資料庫間的一致性。

8.3.1 快取 Key 與 TTL 規格

Key Pattern用途TTL命中率目標失效觸發
cache:auth:tv:{userId}前台用戶 tokenVersion60s> 95%用戶修改密碼、管理員修改用戶、登出
cache:admin:tv:{adminId}後台管理員 tokenVersion60s> 95%管理員修改密碼、Root 修改管理員、停用帳號
cache:admin-group:perms:{groupId}群組權限60s> 90%Root 修改群組權限
cache:vip:levels:{siteCode}VIP 等級列表3600s> 95%管理員修改 VIP 等級
cache:vip:rebates:{siteCode}VIP 返水規則3600s> 95%管理員修改返水規則
cache:common:enums:{locale}系統枚舉(錯誤碼等)persistent> 99%系統重啟
cache:live-sports即時賽事1800s> 90%Cron 每 30 分鐘更新
cache:exchange-rate匯率3600s> 95%匯率更新

8.3.2 快取效能測試

TC-ID測試說明測試步驟預期結果優先級
TC-PERF-CACHE-001快取命中 vs 未命中時間差1. 清除 Redis 快取 2. 第一次呼叫 API(cache miss) 3. 第二次呼叫相同 API(cache hit) 4. 比較回應時間1. Cache miss: 含 DB 查詢時間 2. Cache hit: 顯著快於 miss(通常 < 10ms) 3. 時間差至少 2-5 倍P1
TC-PERF-CACHE-002快取失效正確性1. 查詢 VIP 等級(建立快取) 2. 管理員修改 VIP 等級 3. 再次查詢 VIP 等級1. 修改操作後快取被清除 2. 第三步查詢取得最新資料 3. 不會回傳過期的快取資料P1
TC-PERF-CACHE-003tokenVersion 快取一致性1. 用戶登入(tokenVersion 寫入 Redis) 2. 用戶修改密碼(tokenVersion +1) 3. 使用舊 Token 呼叫 API1. Redis 中的 tokenVersion 已更新 2. 舊 Token 的版本不匹配 3. 強制重新認證P1
TC-PERF-CACHE-004群組權限快取 60 秒 TTL1. 管理員 A 登入,觸發群組權限快取 2. Root 修改群組權限 3. 管理員 A 立即呼叫 API 4. 等 60 秒後再呼叫1. 立即呼叫:可能使用舊權限(快取未過期) 2. 60 秒後:使用新權限 3. TTL 機制正確運作P2
TC-PERF-CACHE-005Redis 連線中斷容錯1. 模擬 Redis 連線中斷 2. 呼叫需要快取的 API1. 系統不崩潰 2. 降級為直接查詢 DB 3. 效能降低但功能正常 4. Redis 恢復後自動重連P2
TC-PERF-CACHE-006快取 key 命名空間隔離1. 檢查不同站點的快取 key 2. C9 站和 A1 站的 VIP 快取1. cache:vip:levels:C9cache:vip:levels:A1 分開 2. 修改 C9 站不影響 A1 站的快取 3. 站點間快取完全隔離P1

8.4 並發測試

測試目標:驗證系統在並發存取下的穩定性和資料一致性。

8.4.1 並發情境測試

TC-ID測試說明測試步驟預期結果優先級
TC-PERF-CONC-00110 並發登入1. 準備 10 個不同帳號 2. 同時發送登入請求 3. 驗證所有回應1. 全部 10 個登入成功 2. 各自取得獨立的 JWT Token 3. 無 Token 混淆 4. 伺服器回應穩定P1
TC-PERF-CONC-002100 並發列表查詢1. 100 個已認證的連線 2. 同時發送列表查詢(不同頁碼) 3. 驗證所有回應1. 全部 100 個查詢成功 2. 各自回傳正確的頁碼資料 3. 無資料錯亂 4. 回應時間 P95 < 500msP1
TC-PERF-CONC-00310 並發存款訂單1. 10 個不同用戶同時發起存款 2. 各自不同金額 3. 驗證所有訂單和餘額1. 全部 10 個訂單建立成功 2. 無 race condition 3. 無重複入帳(double-credit) 4. 各用戶餘額正確 5. 訂單號唯一P1
TC-PERF-CONC-00450 並發報表查詢1. 50 個管理員同時查詢報表 2. 包含不同報表類型 3. 監控伺服器資源1. 全部查詢成功 2. 伺服器 CPU 使用率不超過 80% 3. 記憶體使用穩定 4. 無 OOM 崩潰P2
TC-PERF-CONC-005並發結算與提款1. 觸發代理佣金結算 2. 同時有代理發起提款請求 3. 驗證資料一致性1. 結算和提款不衝突 2. 佣金餘額正確 3. 不超額提款 4. 使用資料庫交易(transaction)保護P1
TC-PERF-CONC-006並發遊戲回調1. 模擬 10 個遊戲回調同時到達(下注/派彩) 2. 針對同一用戶1. 餘額計算正確 2. 無重複處理回調 3. game_transaction 紀錄完整 4. 使用樂觀鎖或交易保護P1
TC-PERF-CONC-007並發活動領取1. 50 個用戶同時領取同一活動 2. 活動有領取上限1. 領取數量不超過上限 2. 無超額領取 3. 各用戶只能領取一次 4. 使用 unique constraint 或交易P1
TC-PERF-CONC-008並發 VIP 反水結算1. 每日 00:05 觸發反水結算 2. 同時有大量投注回調 3. 驗證反水計算1. 結算使用截止時間(如 00:00) 2. 00:00 後的投注計入下一日 3. 反水金額正確 4. 無遺漏或重複P2

8.4.2 並發負載測試建議

場景並發數持續時間成功率目標回應時間目標(P95)
正常負載50 users5 min> 99.9%< 200ms
高峰負載200 users10 min> 99.5%< 500ms
壓力測試500 users15 min> 99.0%< 1000ms
極限測試1000 users5 min> 95.0%< 2000ms
持久測試100 users1 hour> 99.9%無記憶體洩漏

8.5 資料庫查詢效能

測試目標:確保關鍵查詢有使用索引,避免全表掃描,優化慢查詢。

8.5.1 關鍵索引驗證

資料表欄位索引類型用途驗證方式
auth-usersiteCodeINDEX多站點篩選EXPLAIN SELECT * FROM auth_user WHERE siteCode = 'C9'
auth-useraccountUNIQUE帳號查詢/登入登入查詢必須使用此索引
auth-useremailINDEXEmail 查詢OAuth 登入使用
deposit-ordersiteCode, statusCOMPOSITE INDEX存款審核列表篩選站點 + 狀態
deposit-orderuserIdINDEX用戶存款記錄用戶查詢自己的訂單
deposit-ordercreatedAtINDEX日期範圍篩選報表查詢
bet-ordersiteCode, createdAtCOMPOSITE INDEX投注報表按站點 + 日期查詢
bet-orderuserIdINDEX用戶投注記錄用戶查詢/VIP 計算
vip-levelsiteCodeINDEX各站 VIP 配置站點篩選
vip-rebatesiteCode, level, gameTypeUNIQUE返水規則唯一鍵Bulk upsert
game-providersiteCodeINDEX各站遊戲商站點篩選
risk-ip-rulesiteCode, typeINDEX風控規則類型 + 站點篩選
affiliate-settlementagentId, statusCOMPOSITE INDEX代理結算代理查詢自己的結算
notificationuserId, isReadCOMPOSITE INDEX站內信列表用戶查詢未讀信件
admin-operation-logcreatedAtINDEX操作紀錄日期範圍查詢
r2-operation-logsiteCode, createdAtCOMPOSITE INDEXR2 日誌站點 + 日期查詢

8.5.2 慢查詢偵測

TC-ID測試說明測試步驟預期結果優先級
TC-PERF-DB-001開啟 MySQL 慢查詢日誌1. 設定 slow_query_log = 1 2. 設定 long_query_time = 0.5(500ms) 3. 執行完整功能測試 4. 檢查慢查詢日誌1. 記錄所有超過 500ms 的查詢 2. 分析慢查詢的 EXPLAIN 3. 優化缺少索引的查詢P1
TC-PERF-DB-002報表聚合查詢 EXPLAIN1. 對 overview 報表的聚合查詢執行 EXPLAIN ANALYZE 2. 檢查是否使用索引1. SUM/COUNT 查詢使用適當索引 2. 無全表掃描(除非資料量小) 3. 執行計劃合理P1
TC-PERF-DB-003多表 JOIN 查詢1. 對含 JOIN 的查詢執行 EXPLAIN 2. 如用戶列表含 VIP 等級1. JOIN 使用索引 2. 驅動表選擇正確 3. 無 Using temporary / Using filesort(或在可接受範圍)P2
TC-PERF-DB-004JSON 欄位搜尋效能1. 對 JSON 欄位使用 CAST(column AS CHAR) LIKE :keyword 2. 檢查效能1. 效能可能較差(無法使用索引) 2. 在可接受範圍內 3. 若太慢,考慮增加搜尋專用欄位P3

8.6 前端效能

測試目標:確保前台和後台的載入速度和互動效能符合標準。 量測工具:Lighthouse、Chrome DevTools Performance、Web Vitals。

8.6.1 Core Web Vitals 目標

指標說明前台 (c9-ec) 目標後台 (c9-ims) 目標
FCP (First Contentful Paint)首次內容繪製< 1.5s< 2.0s
LCP (Largest Contentful Paint)最大內容繪製< 2.5s< 3.0s
FID (First Input Delay)首次輸入延遲< 100ms< 100ms
CLS (Cumulative Layout Shift)累積版面位移< 0.1< 0.1
TTI (Time to Interactive)可互動時間< 3.0s< 4.0s
TTFB (Time to First Byte)首位元組時間< 500ms< 500ms

8.6.2 前端效能測試項目

TC-ID測試說明測試步驟預期結果優先級
TC-PERF-FE-001前台首頁載入效能1. 使用 Lighthouse 測試前台首頁 2. 量測 FCP / LCP / CLS1. Performance 分數 > 80 2. FCP < 1.5s 3. LCP < 2.5s 4. CLS < 0.1P1
TC-PERF-FE-002後台 Dashboard 載入效能1. 使用 Lighthouse 測試後台 Dashboard 2. 量測各指標1. Performance 分數 > 70(後台功能較複雜) 2. LCP < 3.0s 3. 所有 API 並行載入P1
TC-PERF-FE-003Bundle 大小監控1. 執行 yarn build 2. 檢查產出的 bundle 大小 3. 分析最大的 chunk1. 主 bundle < 500KB (gzipped) 2. 無不必要的大型依賴 3. 動態 import 正確分割P2
TC-PERF-FE-004圖片延遲載入1. 打開含大量圖片的頁面(如遊戲大廳) 2. 觀察網路請求 3. 捲動頁面1. 可視區域外的圖片不預載 2. 捲動時才載入 3. 使用 lazy loading 或 Intersection ObserverP2
TC-PERF-FE-005TanStack Query 快取效能1. 載入列表頁 2. 切換到其他頁面 3. 返回列表頁 4. 觀察是否重新載入1. staleTime(5 min)內不重新請求 2. 直接使用快取資料 3. 頁面瞬間顯示 4. 背景 refetch 不阻塞 UIP2
TC-PERF-FE-006大量資料表格渲染1. 載入含 100 筆資料的表格 2. 量測渲染時間 3. 測試排序和篩選1. 表格渲染 < 100ms 2. 排序操作流暢 3. 無 UI 卡頓 4. 分頁切換順暢P2
TC-PERF-FE-007SiteSelector 切換效能1. 在 Header 切換站點 2. 量測頁面刷新時間 3. 驗證 AdminContentWrapper remount1. 切換觸發 TanStack Query cache 清除 2. AdminContentWrapper key 變更導致 remount 3. 新站點資料載入 < 500ms 4. 無殘留舊資料P1
TC-PERF-FE-008路由切換效能1. 在後台不同頁面間快速切換 2. 量測切換時間1. 頁面切換 < 300ms(含 API 載入) 2. 無白屏閃爍 3. loading 狀態正確顯示 4. scrollToTop 正確觸發P2
TC-PERF-FE-009多語系切換效能1. 切換語系(如 zh-TW → en-US) 2. 量測頁面更新時間1. 語系切換 < 200ms 2. 所有文字正確更新 3. 無需重新載入頁面 4. Cookie 正確設定P3
TC-PERF-FE-010記憶體洩漏檢查1. 長時間使用後台(30 分鐘) 2. 反覆切換頁面/站點 3. 使用 Chrome DevTools Memory 監控1. 記憶體使用量穩定 2. 無持續增長趨勢 3. 切換頁面後舊元件正確釋放 4. 無 detached DOM 累積P2

8.7 Cron 排程效能

測試目標:驗證排程任務在資料量增長時的執行效能和穩定性。

8.7.1 反水結算效能

資料量用戶數投注紀錄數預期執行時間備註
小型站1001,000< 5s基本場景
中型站1,00050,000< 30s一般營運
大型站10,000500,000< 3min高峰營運
超大站50,0005,000,000< 15min壓力測試

測試步驟

  1. 使用對應資料量的 Seed 資料
  2. 手動觸發反水結算 Cron
  3. 量測從開始到結束的執行時間
  4. 監控 MySQL CPU、記憶體使用
  5. 確認所有用戶反水金額正確

8.7.2 代理週結效能

資料量代理數下線總數投注紀錄數預期執行時間
小型505005,000< 10s
中型5005,000100,000< 1min
大型2,00030,0001,000,000< 5min

重點關注

  • 三層代理結構的遞迴計算效能
  • 風控檢測查詢效能
  • 結算記錄批次寫入效能

8.7.3 月度保級效能

用戶數VIP 等級分佈預期執行時間備註
1,000均勻分佈< 10s基本場景
10,00080% 低級< 1min一般營運
50,000混合分佈< 5min壓力測試

8.8 效能監控指標

測試目標:定義系統效能監控的關鍵指標和告警門檻。

8.8.1 後端監控指標

指標正常範圍告警門檻嚴重門檻量測方式
API 平均回應時間< 100ms> 300ms> 1000msPrometheus + Grafana
API P99 回應時間< 500ms> 1000ms> 3000msPrometheus
請求成功率> 99.9%< 99.5%< 99.0%HTTP status code
每秒請求數 (RPS)50-500> 1000> 2000負載監控
MySQL 查詢時間< 50ms> 200ms> 1000msSlow query log
MySQL 連線數< 50> 80> 100max_connections
Redis 記憶體使用< 50%> 70%> 90%Redis INFO
Redis 命中率> 95%< 90%< 80%Redis INFO
Node.js 記憶體< 512MB> 768MB> 1024MBprocess.memoryUsage()
Node.js CPU< 50%> 70%> 90%OS monitoring

8.8.2 前端監控指標

指標正常範圍告警門檻量測方式
FCP< 1.5s> 2.5sWeb Vitals
LCP< 2.5s> 4.0sWeb Vitals
CLS< 0.1> 0.25Web Vitals
JS Bundle 大小 (gzip)< 500KB> 800KBBuild output
API 呼叫數/頁面< 10> 20Network tab
DOM Node 數量< 1500> 3000DevTools
JS Heap Size< 100MB> 200MBDevTools Memory

8.9 效能測試報告模板

markdown
# 效能測試報告

## 測試環境
- **硬體**: [CPU / RAM / Disk]
- **軟體**: [Node.js / MySQL / Redis version]
- **資料量**: [Seed 資料規模]
- **測試工具**: [k6 / JMeter / Artillery]

## API 回應時間

| 端點 | 方法 | P50 | P95 | P99 | Max | 目標 | 結果 |
|------|------|-----|-----|-----|-----|------|------|
| /auth/login | POST | Xms | Xms | Xms | Xms | <200ms | Pass/Fail |
| /admin/finance/users/list | GET | Xms | Xms | Xms | Xms | <200ms | Pass/Fail |
| ... | ... | ... | ... | ... | ... | ... | ... |

## 並發測試

| 場景 | VUs | 持續 | 成功率 | P95 | 結果 |
|------|-----|------|--------|-----|------|
| 正常負載 | 50 | 5min | X% | Xms | Pass/Fail |
| 高峰負載 | 200 | 10min | X% | Xms | Pass/Fail |
| ... | ... | ... | ... | ... | ... |

## 資料庫查詢

| 查詢 | 資料量 | 執行時間 | 使用索引 | 結果 |
|------|--------|---------|---------|------|
| 用戶列表 | 10K | Xms | Yes/No | Pass/Fail |
| 報表聚合 | 100K | Xms | Yes/No | Pass/Fail |
| ... | ... | ... | ... | ... |

## Cron 排程

| 排程 | 資料量 | 執行時間 | 目標 | 結果 |
|------|--------|---------|------|------|
| 反水結算 | 10K users | Xs | <30s | Pass/Fail |
| 佣金週結 | 500 agents | Xs | <60s | Pass/Fail |
| ... | ... | ... | ... | ... |

## 前端效能

| 頁面 | FCP | LCP | CLS | TTI | Lighthouse Score |
|------|-----|-----|-----|-----|-----------------|
| 前台首頁 | Xs | Xs | X | Xs | X |
| 後台 Dashboard | Xs | Xs | X | Xs | X |
| ... | ... | ... | ... | ... | ... |

## 發現問題

| 問題 | 影響 | 建議 |
|------|------|------|
| ... | ... | ... |

## 結論
[效能是否達標,是否建議發布]

8.10 效能優化建議追蹤

優化項目當前狀態預期改善優先級備註
深度分頁改用 cursor-based未實施深度分頁效能提升 10xP2page > 1000 時明顯
報表聚合結果快取未實施重複查詢命中率 > 90%P2TTL 5 min
列表查詢 COUNT 優化未實施COUNT 查詢時間減少 50%P3使用估算或分離計數
JSON 欄位搜尋索引未實施模糊搜尋效能提升 5xP3新增搜尋專用欄位
前端圖片 WebP 轉換未實施圖片大小減少 30%P3Nuxt Image 模組
API 回應 gzip 壓縮已實施回應大小減少 60%-NestJS 內建
TanStack Query staleTime已實施重複請求減少 80%-5 min staleTime
Redis 快取策略已實施DB 查詢減少 70%-分層 TTL

第 9 章:回歸測試清單

使用方式:每次版本發布前,逐項勾選確認。未通過的項目需建立 Bug 報告。 優先級說明:P1 為每次必測,P2 為重大版本必測,P3 為季度測試。 格式- [ ] TC-ID: 說明 — 未測試;- [x] TC-ID: 說明 — 已通過。


9.1 認證模組回歸

9.1.1 前台用戶註冊

  • [ ] TC-REG-AUTH-001: 帳號密碼註冊 → 成功建立帳號並取得 JWT
  • [ ] TC-REG-AUTH-002: 帳號已存在 → 顯示錯誤訊息(ERROR_CODES 查表)
  • [ ] TC-REG-AUTH-003: 密碼不符合強度要求 → Zod 驗證攔截
  • [ ] TC-REG-AUTH-004: Email 格式驗證 → 不合法 Email 被拒絕
  • [ ] TC-REG-AUTH-005: 註冊時裝置指紋記錄 → FingerprintJS v5 正確產生並傳送

9.1.2 前台用戶登入

  • [ ] TC-REG-AUTH-006: 帳號密碼登入 → 成功取得 JWT Token(7 天過期)
  • [ ] TC-REG-AUTH-007: 錯誤密碼登入 → 顯示錯誤訊息,記錄登入失敗
  • [ ] TC-REG-AUTH-008: Google OAuth 登入 → 成功建立/綁定帳號
  • [ ] TC-REG-AUTH-009: Telegram OAuth 登入 → 成功建立/綁定帳號
  • [ ] TC-REG-AUTH-010: 登入時裝置指紋記錄 → 新增 auth-user-login-log 紀錄
  • [ ] TC-REG-AUTH-011: 不存在的帳號登入 → 統一錯誤訊息(不洩漏帳號存在與否)

9.1.3 Token 與 Session 管理

  • [ ] TC-REG-AUTH-012: JWT Token 7 天內有效 → API 正常存取
  • [ ] TC-REG-AUTH-013: JWT Token 過期 → 返回 401,前端觸發重新登入
  • [ ] TC-REG-AUTH-014: 登出 → Token 失效,清除 session
  • [ ] TC-REG-AUTH-015: tokenVersion 變更 → 舊 Token 失效
  • [ ] TC-REG-AUTH-016: 多裝置同時登入 → 各自 Token 獨立

9.1.4 密碼管理

  • [ ] TC-REG-AUTH-017: 修改密碼(需驗證舊密碼) → 成功後舊 Token 失效
  • [ ] TC-REG-AUTH-018: OAuth 用戶首次設定密碼(不需舊密碼) → 成功
  • [ ] TC-REG-AUTH-019: 密碼以 bcrypt 儲存 → 資料庫無明文

9.1.5 後台管理員認證

  • [ ] TC-REG-AUTH-020: 管理員帳密登入 → 取得 AdminJWT
  • [ ] TC-REG-AUTH-021: 管理員 2FA 登入流程 → 帳密 + TOTP 雙步驟
  • [ ] TC-REG-AUTH-022: NextAuth 5 Session 管理 → JWT 策略正確
  • [ ] TC-REG-AUTH-023: 管理員登出 → 清除 session + Token
  • [ ] TC-REG-AUTH-024: 管理員 Token 過期 → 401 重試機制

9.1.6 2FA 管理

  • [ ] TC-REG-AUTH-025: 啟用 Google Authenticator → QR Code + Secret
  • [ ] TC-REG-AUTH-026: 正確 TOTP 碼驗證 → 啟用成功
  • [ ] TC-REG-AUTH-027: 錯誤 TOTP 碼 → 啟用失敗
  • [ ] TC-REG-AUTH-028: 停用 2FA(需當前 TOTP) → 成功停用
  • [ ] TC-REG-AUTH-029: 停用後重新啟用 → 新 Secret 產生

9.1.7 頭像管理

  • [ ] TC-REG-AUTH-030: 上傳頭像 → R2 儲存成功
  • [ ] TC-REG-AUTH-031: 更換頭像 → 舊頭像清除
  • [ ] TC-REG-AUTH-032: 頭像顯示 → 正確載入

9.2 遊戲模組回歸

9.2.1 遊戲大廳(前台)

  • [ ] TC-REG-GAME-001: 遊戲大廳載入 → 顯示所有已啟用的遊戲類型 Tab
  • [ ] TC-REG-GAME-002: 體育 (SPORTS) 分類 → 正確顯示體育遊戲
  • [ ] TC-REG-GAME-003: 老虎機 (SLOT) 分類 → 正確顯示老虎機遊戲
  • [ ] TC-REG-GAME-004: 真人 (LIVE) 分類 → 正確顯示真人遊戲
  • [ ] TC-REG-GAME-005: 彩票 (LOTTERY) 分類 → 正確顯示彩票遊戲
  • [ ] TC-REG-GAME-006: 棋牌 (CHESS) 分類 → 正確顯示棋牌遊戲
  • [ ] TC-REG-GAME-007: 電競 (ESPORTS) 分類 → 正確顯示電競遊戲
  • [ ] TC-REG-GAME-008: 加密貨幣 (CRYPTO) 分類 → 正確顯示加密遊戲
  • [ ] TC-REG-GAME-009: 捕魚 (FISH) 分類 → 正確顯示捕魚遊戲

9.2.2 遊戲功能

  • [ ] TC-REG-GAME-010: 遊戲搜尋 → 關鍵字模糊搜尋正確
  • [ ] TC-REG-GAME-011: 遊戲啟動(已登入) → 正確跳轉遊戲頁面
  • [ ] TC-REG-GAME-012: 遊戲試玩(免登入) → 試玩模式正確
  • [ ] TC-REG-GAME-013: 風控黑名單攔截 → 被封鎖用戶無法啟動遊戲(錯誤碼 5010)
  • [ ] TC-REG-GAME-014: 最近遊玩記錄 → 顯示用戶最近玩過的遊戲
  • [ ] TC-REG-GAME-015: 遊戲下注回調 → 餘額正確扣減
  • [ ] TC-REG-GAME-016: 遊戲派彩回調 → 餘額正確增加
  • [ ] TC-REG-GAME-017: 投注後連動 → VIP 等級重算 + 活動打碼量 + 任務進度

9.2.3 遊戲管理(後台)

  • [ ] TC-REG-GAME-018: 遊戲供應商列表 → 按站點顯示(SiteTabs)
  • [ ] TC-REG-GAME-019: 新增遊戲供應商 → 成功建立(含 siteCode)
  • [ ] TC-REG-GAME-020: 編輯遊戲供應商 → 更新成功
  • [ ] TC-REG-GAME-021: 刪除遊戲供應商 → 刪除成功
  • [ ] TC-REG-GAME-022: 遊戲分類列表 → 按站點顯示(SiteTabs)
  • [ ] TC-REG-GAME-023: 新增遊戲分類 → 成功建立(含 siteCode)
  • [ ] TC-REG-GAME-024: 遊戲模板載入 → 預覽後確認寫入(按站點)
  • [ ] TC-REG-GAME-025: 同預設站點複製 → transaction 內先刪後插
  • [ ] TC-REG-GAME-026: 跨站複製遊戲資料 → sourceSiteCode → targetSiteCode

9.3 金流模組回歸

9.3.1 存款功能(前台)

  • [ ] TC-REG-FIN-001: 存款入口 → POST /deposit 統一入口
  • [ ] TC-REG-FIN-002: ATM 存款(萬通金流) → 訂單建立 + 導向金流頁面
  • [ ] TC-REG-FIN-003: 信用卡存款(萬通金流) → 訂單建立 + 信用卡表單
  • [ ] TC-REG-FIN-004: USDT 加密貨幣存款 → 訂單建立 + 顯示收款地址
  • [ ] TC-REG-FIN-005: 存款金額 → TWD 轉 USD(台銀即時匯率)
  • [ ] TC-REG-FIN-006: USD 截斷規則 → Math.floor(value * 1e6) / 1e6
  • [ ] TC-REG-FIN-007: 金流群組依語系分配 → 正確路由至對應通道
  • [ ] TC-REG-FIN-008: 存款回調 → 金流商回調更新訂單狀態
  • [ ] TC-REG-FIN-009: 存款成功後連動 → 餘額增加 + 任務進度更新

9.3.2 提款功能(前台)

  • [ ] TC-REG-FIN-010: 提款申請 → 建立提款訂單
  • [ ] TC-REG-FIN-011: 提款餘額檢查 → 餘額不足時拒絕
  • [ ] TC-REG-FIN-012: 提款至銀行卡 → 資料正確
  • [ ] TC-REG-FIN-013: 提款至加密地址 → 資料正確
  • [ ] TC-REG-FIN-014: 提款手續費計算 → 正確扣除

9.3.3 金流管理(後台)

  • [ ] TC-REG-FIN-015: 存款審核列表 → 多站點 SiteTabs + 篩選
  • [ ] TC-REG-FIN-016: 存款審核(通過) → 狀態更新 + 餘額增加
  • [ ] TC-REG-FIN-017: 存款審核(拒絕) → 狀態更新 + 餘額不變
  • [ ] TC-REG-FIN-018: 提款審核列表 → 多站點 SiteTabs + 篩選
  • [ ] TC-REG-FIN-019: 提款審核(通過) → 狀態更新
  • [ ] TC-REG-FIN-020: 提款審核(拒絕) → 狀態更新 + 餘額返還
  • [ ] TC-REG-FIN-021: 提款上傳憑證 → R2 儲存 + 關聯訂單
  • [ ] TC-REG-FIN-022: 提款標記完成 → 最終狀態更新
  • [ ] TC-REG-FIN-023: 手動調帳 → 餘額正確增減 + 紀錄

9.3.4 金流商管理(後台)

  • [ ] TC-REG-FIN-024: 金流群組列表 → 多站點顯示
  • [ ] TC-REG-FIN-025: 金流群組 CRUD → 新增/編輯/刪除
  • [ ] TC-REG-FIN-026: 金流通道列表 → 多站點顯示
  • [ ] TC-REG-FIN-027: 金流通道 CRUD → 新增/編輯/刪除
  • [ ] TC-REG-FIN-028: 用戶金流群組分配 → 正確設定

9.3.5 匯率

  • [ ] TC-REG-FIN-029: 即時匯率取得 → 台灣銀行匯率 API
  • [ ] TC-REG-FIN-030: 匯率精度 → decimal(18,10) 小數 10 位

9.4 錢包模組回歸

9.4.1 銀行卡

  • [ ] TC-REG-WALLET-001: 新增銀行卡 → 前台用戶新增成功
  • [ ] TC-REG-WALLET-002: 銀行卡列表 → 顯示用戶所有銀行卡
  • [ ] TC-REG-WALLET-003: 刪除銀行卡 → 成功刪除
  • [ ] TC-REG-WALLET-004: 後台銀行卡審核列表 → 多站點 SiteTabs + 篩選
  • [ ] TC-REG-WALLET-005: 後台銀行卡審核(通過/拒絕) → 狀態正確更新

9.4.2 信用卡

  • [ ] TC-REG-WALLET-006: 新增信用卡 → 前台用戶新增成功
  • [ ] TC-REG-WALLET-007: 信用卡列表 → 顯示用戶所有信用卡
  • [ ] TC-REG-WALLET-008: 刪除信用卡 → 成功刪除
  • [ ] TC-REG-WALLET-009: 後台信用卡審核列表 → 多站點 SiteTabs + 篩選
  • [ ] TC-REG-WALLET-010: 後台信用卡審核(通過/拒絕) → 狀態正確更新

9.4.3 加密錢包地址

  • [ ] TC-REG-WALLET-011: 新增加密地址 → 前台用戶新增成功
  • [ ] TC-REG-WALLET-012: 加密地址列表 → 顯示用戶所有地址
  • [ ] TC-REG-WALLET-013: 刪除加密地址 → 成功刪除
  • [ ] TC-REG-WALLET-014: 後台加密地址審核列表 → 多站點 SiteTabs + 篩選
  • [ ] TC-REG-WALLET-015: 後台加密地址審核(通過/拒絕) → 狀態正確更新

9.5 VIP 模組回歸

9.5.1 VIP 等級(前台)

  • [ ] TC-REG-VIP-001: VIP 等級頁面 → 顯示該站點所有 VIP 等級
  • [ ] TC-REG-VIP-002: 當前 VIP 等級 → 正確顯示用戶 VIP 等級
  • [ ] TC-REG-VIP-003: 升級進度 → 累積投注金額和升級門檻
  • [ ] TC-REG-VIP-004: VIP 等級只升不降 → 投注累積自動升級

9.5.2 VIP 反水

  • [ ] TC-REG-VIP-005: 反水規則頁面 → 顯示各等級各遊戲類型反水率
  • [ ] TC-REG-VIP-006: 每日反水結算(00:05 Cron) → 正確計算並發放
  • [ ] TC-REG-VIP-007: 反水含 8 種遊戲類型 → sports/slot/live/lottery/chess/esports/crypto/fish
  • [ ] TC-REG-VIP-008: 反水精度 → decimal(18,6) 無條件捨去

9.5.3 VIP 保級

  • [ ] TC-REG-VIP-009: 月度保級檢查(每月 1 號 01:00 Cron) → 正確執行
  • [ ] TC-REG-VIP-010: VIP 5+ 保級鎖定 → 高等級不因保級失敗而降級

9.5.4 VIP 管理(後台)

  • [ ] TC-REG-VIP-011: VIP 等級列表 → 多站點 SiteTabs
  • [ ] TC-REG-VIP-012: VIP 等級 CRUD → 新增/編輯/刪除
  • [ ] TC-REG-VIP-013: VIP 等級數量可自由擴充 → 不限 15 級
  • [ ] TC-REG-VIP-014: 返水設定列表 → 多站點 SiteTabs
  • [ ] TC-REG-VIP-015: 返水設定 CRUD → bulk upsert(unique key: siteCode + level + gameType)
  • [ ] TC-REG-VIP-016: VIP 等級帶入模板 → 只影響當前站點
  • [ ] TC-REG-VIP-017: VIP 等級同預設站點 → 複製預設站配置到目標站
  • [ ] TC-REG-VIP-018: 返水設定帶入模板 → 只影響當前站點
  • [ ] TC-REG-VIP-019: 返水設定同預設站點 → 複製預設站配置到目標站
  • [ ] TC-REG-VIP-020: VIP 玩家列表 → 多站點 SiteTabs + 篩選
  • [ ] TC-REG-VIP-021: 其他頁面 VIP 下拉選項 → 動態取得(不硬編碼)

9.6 代理模組回歸

9.6.1 代理申請與綁定

  • [ ] TC-REG-AFF-001: 申請成為代理 → 成功設定為代理身份
  • [ ] TC-REG-AFF-002: 推廣碼上限(每人最多 10 個) → 超過時拒絕
  • [ ] TC-REG-AFF-003: 推廣碼雙重查找 → 聯盟碼 → 主代理碼
  • [ ] TC-REG-AFF-004: 三層代理結構 → 最多 3 層上下線關係
  • [ ] TC-REG-AFF-005: 手動綁定上下線 → 後台管理員操作

9.6.2 佣金與結算

  • [ ] TC-REG-AFF-006: 下線投注產生佣金 → 按佣金費率計算
  • [ ] TC-REG-AFF-007: 佣金費率 → 按代理等級 × 遊戲類型配置
  • [ ] TC-REG-AFF-008: 佣金週結(每週一 03:00 Cron) → 正確結算
  • [ ] TC-REG-AFF-009: 佣金日結(每日 03:30 Cron) → 正確結算
  • [ ] TC-REG-AFF-010: 結算風控檢測 → 異常下線自動標記

9.6.3 代理提款

  • [ ] TC-REG-AFF-011: 代理提款申請 → 佣金餘額充足時建立
  • [ ] TC-REG-AFF-012: 代理提款三階段 → 待審核 → 已核准 → 已完成
  • [ ] TC-REG-AFF-013: 代理提款審核(後台) → 通過/拒絕

9.6.4 聯盟系統

  • [ ] TC-REG-AFF-014: 代理等級 → bronze/silver/gold/platinum
  • [ ] TC-REG-AFF-015: VIP 里程碑 → 下線 VIP 等級達標自動發放獎勵
  • [ ] TC-REG-AFF-016: 佣金費率模板 → 4 等級 × 3 級別 × 8 遊戲類型 = 96 筆
  • [ ] TC-REG-AFF-017: 聯盟公開端點 → alliance-info / tier-info / vip-milestones / referral-codes

9.6.5 代理管理(後台)

  • [ ] TC-REG-AFF-018: 代理列表 → 多站點 SiteTabs + 篩選
  • [ ] TC-REG-AFF-019: 新增代理 → 手動綁定用戶為代理
  • [ ] TC-REG-AFF-020: 佣金結算列表 → 篩選 status + 日期
  • [ ] TC-REG-AFF-021: 結算審核 → approve / reject
  • [ ] TC-REG-AFF-022: 結算風控紀錄 → 查看風控檢測結果
  • [ ] TC-REG-AFF-023: 代理提款列表 → 篩選 status + method
  • [ ] TC-REG-AFF-024: 代理提款審核 → approve / reject / complete
  • [ ] TC-REG-AFF-025: 綁定紀錄 → 篩選 action + refCode + 日期
  • [ ] TC-REG-AFF-026: 佣金費率 CRUD → 按代理等級 × 遊戲類型
  • [ ] TC-REG-AFF-027: VIP 里程碑 CRUD → 下線 VIP 等級獎勵
  • [ ] TC-REG-AFF-028: 代理等級 CRUD → bronze/silver/gold/platinum
  • [ ] TC-REG-AFF-029: 帶入模板 → 預覽後確認寫入
  • [ ] TC-REG-AFF-030: 設定代理等級 → 手動調整
  • [ ] TC-REG-AFF-031: 觸發結算 → 手動觸發週結/日結
  • [ ] TC-REG-AFF-032: 帳號遮罩 → maskAccount() 正確隱藏

9.7 活動模組回歸

9.7.1 活動功能(前台)

  • [ ] TC-REG-PROMO-001: 活動列表 → 顯示該站點所有進行中活動
  • [ ] TC-REG-PROMO-002: 活動詳情 → 正確顯示多語系內容(resolveText)
  • [ ] TC-REG-PROMO-003: 活動領取 → 符合條件時成功領取
  • [ ] TC-REG-PROMO-004: 活動條件檢查 → 不符合條件時顯示原因
  • [ ] TC-REG-PROMO-005: 打碼量追蹤 → 投注後正確累計打碼進度
  • [ ] TC-REG-PROMO-006: 重複領取防護 → 已領取的活動不可再領

9.7.2 活動管理(後台)

  • [ ] TC-REG-PROMO-007: 活動列表 → 多站點 SiteTabs + 篩選
  • [ ] TC-REG-PROMO-008: 新增活動 → 含多語系內容 + 條件設定
  • [ ] TC-REG-PROMO-009: 編輯活動 → 更新成功
  • [ ] TC-REG-PROMO-010: 刪除活動 → 刪除成功
  • [ ] TC-REG-PROMO-011: 活動上下架 → 狀態切換正確

9.7.3 活動標籤(後台)

  • [ ] TC-REG-PROMO-012: 活動標籤列表 → 多站點 SiteTabs
  • [ ] TC-REG-PROMO-013: 標籤 CRUD → 新增/編輯/刪除
  • [ ] TC-REG-PROMO-014: 活動關聯標籤 → 篩選功能正確
  • [ ] TC-REG-PROMO-015: 標籤多語系名稱 → 5 個語系正確顯示

9.8 任務模組回歸

9.8.1 任務功能

  • [ ] TC-REG-MISSION-001: 任務列表 → 顯示每日/週/月任務
  • [ ] TC-REG-MISSION-002: 存款任務進度 → 存款確認後自動更新
  • [ ] TC-REG-MISSION-003: 投注任務進度 → 投注結算後自動更新
  • [ ] TC-REG-MISSION-004: 任務完成領取獎勵 → 成功領取
  • [ ] TC-REG-MISSION-005: 每日任務重置 → 每日 00:00 重置進度
  • [ ] TC-REG-MISSION-006: 每週任務重置 → 每週一重置進度
  • [ ] TC-REG-MISSION-007: 每月任務重置 → 每月 1 號重置進度
  • [ ] TC-REG-MISSION-008: 任務獎勵精度 → decimal(18,6) 無條件捨去
  • [ ] TC-REG-MISSION-009: 重複領取防護 → 已領取的任務不可再領
  • [ ] TC-REG-MISSION-010: 任務進度不因重複投注而超額 → 進度上限為目標值

9.9 站內信模組回歸

9.9.1 站內信功能(前台)

  • [ ] TC-REG-INBOX-001: 站內信列表 → 顯示用戶收件匣
  • [ ] TC-REG-INBOX-002: 未讀信件計數 → 正確顯示未讀數量
  • [ ] TC-REG-INBOX-003: 閱讀信件 → 標記為已讀
  • [ ] TC-REG-INBOX-004: 刪除信件 → 成功刪除
  • [ ] TC-REG-INBOX-005: 信件分頁 → 大量信件正確分頁

9.9.2 站內信管理(後台)

  • [ ] TC-REG-INBOX-006: 站內信列表 → 多站點 SiteTabs
  • [ ] TC-REG-INBOX-007: 發送站內信 → 指定用戶或全站廣播
  • [ ] TC-REG-INBOX-008: 信件多語系內容 → 5 個語系正確
  • [ ] TC-REG-INBOX-009: 信件設定 → 模式 B 設定頁(各站獨立)
  • [ ] TC-REG-INBOX-010: 信件內容 XSS 防護 → 安全顯示

9.10 風控模組回歸

9.10.1 IP 黑白名單

  • [ ] TC-REG-RISK-001: IP 規則列表 → 多站點 SiteTabs + 篩選(類型/IP/日期)
  • [ ] TC-REG-RISK-002: 新增 IP 黑名單 → 成功建立
  • [ ] TC-REG-RISK-003: 新增 IP 白名單 → 成功建立
  • [ ] TC-REG-RISK-004: 編輯 IP 規則 → 更新成功
  • [ ] TC-REG-RISK-005: 刪除 IP 規則 → 刪除成功
  • [ ] TC-REG-RISK-006: 黑名單 IP 阻擋 → 該 IP 用戶被限制

9.10.2 遊戲黑名單

  • [ ] TC-REG-RISK-007: 遊戲黑名單列表 → 多站點 SiteTabs + 篩選(用戶/遊戲類型/日期)
  • [ ] TC-REG-RISK-008: 新增遊戲黑名單 → 全封鎖/類型封鎖/特定遊戲封鎖
  • [ ] TC-REG-RISK-009: 遊戲黑名單生效 → 被封鎖用戶無法啟動遊戲(錯誤碼 5010)
  • [ ] TC-REG-RISK-010: 刪除遊戲黑名單 → 用戶恢復遊戲權限

9.10.3 IP/裝置指紋查詢

  • [ ] TC-REG-RISK-011: IP 查詢 → 多站點 SiteTabs + 關鍵字搜尋
  • [ ] TC-REG-RISK-012: 裝置指紋查詢 → 反查使用該指紋的用戶
  • [ ] TC-REG-RISK-013: 帳號/姓名/Email/手機查詢 → 反查 IP 和指紋
  • [ ] TC-REG-RISK-014: 登入失敗紀錄 → 多站點 + 關鍵字 + 日期篩選
  • [ ] TC-REG-RISK-015: 登入失敗紀錄含 IP 和時間 → 風控分析依據

9.11 報表模組回歸

9.11.1 各報表功能

  • [ ] TC-REG-REPORT-001: 玩家報表 → 多站點 SiteTabs + 關鍵字/VIP 等級/日期篩選
  • [ ] TC-REG-REPORT-002: 投注紀錄 → 多站點 SiteTabs + 關鍵字/遊戲類型/平台/狀態/日期篩選
  • [ ] TC-REG-REPORT-003: 總覽報表 → 多站點 SiteTabs + 日期篩選 + 統計卡片
  • [ ] TC-REG-REPORT-004: 損益報表 → 多站點 SiteTabs + 分組(日/週/月)/遊戲類型/日期篩選
  • [ ] TC-REG-REPORT-005: 遊戲報表 → 多站點 SiteTabs + 遊戲類型/平台/日期篩選
  • [ ] TC-REG-REPORT-006: 玩家摘要 → 多站點 SiteTabs + 關鍵字/VIP/排序/日期篩選
  • [ ] TC-REG-REPORT-007: 活動報表 → 日期篩選(待加入多站點)

9.11.2 報表通用功能

  • [ ] TC-REG-REPORT-008: 分頁功能 → 所有報表分頁正確
  • [ ] TC-REG-REPORT-009: 排序功能 → 點擊欄位標頭排序
  • [ ] TC-REG-REPORT-010: CSV 匯出 → ExportButton 匯出正確
  • [ ] TC-REG-REPORT-011: 空資料顯示 → tc("noData") 提示
  • [ ] TC-REG-REPORT-012: 日期範圍篩選 → 正確篩選 createdAt
  • [ ] TC-REG-REPORT-013: 重置篩選 → 清除所有篩選條件

9.11.3 報表數據正確性

  • [ ] TC-REG-REPORT-014: 總覽報表數據 → 存款/提款/投注總額正確
  • [ ] TC-REG-REPORT-015: 損益報表計算 → 收入 - 支出 = 損益
  • [ ] TC-REG-REPORT-016: 遊戲報表統計 → 各遊戲類型數據正確
  • [ ] TC-REG-REPORT-017: 玩家報表含 VIP 資訊 → 等級正確顯示
  • [ ] TC-REG-REPORT-018: 投注紀錄完整 → 每筆投注都有紀錄
  • [ ] TC-REG-REPORT-019: 報表金額精度 → decimal(18,6) 正確顯示
  • [ ] TC-REG-REPORT-020: 報表時區 → UTC+8 正確顯示

9.12 系統管理模組回歸

9.12.1 管理員管理

  • [ ] TC-REG-SYS-001: 管理員列表 → 全站共用(不區分站點)
  • [ ] TC-REG-SYS-002: 新增管理員 → 帳號/密碼/群組設定
  • [ ] TC-REG-SYS-003: 編輯管理員 → 修改資料/群組
  • [ ] TC-REG-SYS-004: 停用管理員 → 帳號停用後無法登入
  • [ ] TC-REG-SYS-005: 管理員密碼重設 → 管理員可修改自己密碼

9.12.2 群組管理

  • [ ] TC-REG-SYS-006: 群組列表 → 全站共用
  • [ ] TC-REG-SYS-007: 新增群組 → 設定群組類型和權限
  • [ ] TC-REG-SYS-008: 編輯群組權限 → 16 模組 × 2 操作
  • [ ] TC-REG-SYS-009: 刪除群組 → 無管理員使用才可刪除
  • [ ] TC-REG-SYS-010: 四種群組類型 → root/super_admin/general_admin/custom

9.12.3 操作紀錄

  • [ ] TC-REG-SYS-011: 操作紀錄列表 → 全站共用 + 日期篩選
  • [ ] TC-REG-SYS-012: 操作紀錄內容 → 操作者/類型/時間/IP
  • [ ] TC-REG-SYS-013: 紀錄不可刪改 → 稽核安全

9.12.4 站點設定

  • [ ] TC-REG-SYS-014: 站點列表 → 所有站點(含主題)
  • [ ] TC-REG-SYS-015: 新增站點 → 建立新站點配置
  • [ ] TC-REG-SYS-016: 編輯站點 → 更新站點設定
  • [ ] TC-REG-SYS-017: 刪除站點 → cascade 刪除主題

9.12.5 客服配置

  • [ ] TC-REG-SYS-018: 客服配置 → 8 種管道(line/telegram/wechat/facebook/instagram/twitter/discord/custom)
  • [ ] TC-REG-SYS-019: 客服管道設定 → 多語系 label + icon + link + sortOrder + enabled
  • [ ] TC-REG-SYS-020: LiveChat 嵌入腳本 → 獨立開關
  • [ ] TC-REG-SYS-021: 客服配置各站獨立 → 同預設站點複製

9.12.6 域名設置

  • [ ] TC-REG-SYS-022: 域名設置 → 模式 B(各站獨立)
  • [ ] TC-REG-SYS-023: 域名素材上傳 → logoSmall / logoBig / favicon

9.12.7 雲端儲存

  • [ ] TC-REG-SYS-024: R2 檔案列表 → 多站點 SiteTabs
  • [ ] TC-REG-SYS-025: R2 檔案上傳 → 上傳至正確路徑
  • [ ] TC-REG-SYS-026: R2 檔案刪除 → 刪除成功
  • [ ] TC-REG-SYS-027: R2 資料夾管理 → 建立/刪除資料夾
  • [ ] TC-REG-SYS-028: R2 操作紀錄 → 雲端儲存日誌正確記錄

9.12.8 其他系統設定

  • [ ] TC-REG-SYS-029: 三方登入配置 → 各站獨立(模式 B)
  • [ ] TC-REG-SYS-030: 遊戲商配置 → 各站獨立(模式 B)
  • [ ] TC-REG-SYS-031: 服務商配置 → 各站獨立(模式 B)

9.12.9 詳細測試步驟:認證模組

以下為認證模組回歸測試的詳細步驟,適用於首次執行或新人上手。

TC-REG-AUTH-001 詳細步驟:帳號密碼註冊

步驟操作驗證點
1開啟前台首頁 http://localhost:3010頁面正確載入
2點擊右上角「註冊」按鈕跳轉至註冊頁面
3輸入帳號:test_new_user_001帳號欄位接受輸入
4輸入密碼:NewUser123!@#密碼強度指示器顯示
5輸入確認密碼:NewUser123!@#兩次密碼一致
6輸入 Email:test@example.comEmail 格式驗證通過
7點擊「註冊」按鈕發送 POST /api/auth/register
8檢查 API 回應code: 200, 包含 tokenuser
9檢查頁面跳轉自動登入並跳轉至首頁
10檢查 Header 用戶名稱顯示 test_new_user_001
11查詢資料庫auth-user 表新增一筆記錄,siteCode 正確
12查詢密碼儲存密碼以 $2b$ 開頭的 bcrypt hash 儲存

TC-REG-AUTH-006 詳細步驟:帳號密碼登入

步驟操作驗證點
1開啟前台登入頁面登入表單正確顯示
2輸入帳號:test_user_C9_001帳號欄位接受輸入
3輸入密碼:Test123!@#密碼欄位接受輸入
4確認 FingerprintJS 已載入瀏覽器指紋已產生
5點擊「登入」按鈕發送 POST /api/auth/login(含 fingerprint)
6檢查 API 回應code: 200, result.token 為有效 JWT
7解碼 JWT payload包含 userId, account, siteCode, exp(7天後)
8檢查頁面狀態跳轉至首頁,Header 顯示用戶資訊
9檢查 Cookielocale cookie 已設定
10查詢 auth-user-login-log新增一筆登入記錄,含 IP、指紋、時間

TC-REG-AUTH-020 詳細步驟:後台管理員登入

步驟操作驗證點
1開啟後台登入頁面 http://localhost:3011登入表單正確顯示
2輸入帳號:root_admin帳號欄位接受輸入
3輸入密碼:Root123!@#密碼欄位接受輸入
4點擊「登入」按鈕發送 POST /api/admin/login
5檢查 API 回應code: 200, result.tokenrole: 'admin'
6檢查 NextAuth sessionSession 正確建立,JWT 策略
7檢查頁面跳轉導向 Dashboard 頁面
8檢查 Sidebar顯示完整選單(root 權限)
9檢查 SiteSelectorHeader 顯示站點選擇下拉選單
10檢查 SiteFilterInitializer站點列表已載入(呼叫 /site-config/admin/list)

9.12.10 詳細測試步驟:金流模組

TC-REG-FIN-001 詳細步驟:前台存款流程

步驟操作驗證點
1前台用戶已登入Header 顯示用戶名稱和餘額
2記錄當前餘額(如 100.000000 USD)存款前基準值
3進入存款頁面顯示可用的存款方式
4選擇 ATM 存款ATM 存款表單顯示
5輸入金額 1000 TWD金額驗證通過
6確認匯率顯示顯示當前台銀匯率和折算 USD
7計算預期 USDMath.floor(1000 / rate * 1e6) / 1e6
8點擊「確認存款」發送 POST /api/deposit
9檢查回應訂單建立成功,含訂單號和金流頁 URL
10模擬金流商回調成功發送回調至 /api/vendor/callback
11檢查訂單狀態deposit-order 狀態更新為 completed
12檢查用戶餘額餘額增加 = 步驟 7 的 USD 金額
13檢查任務進度存款任務進度更新
14確認精度USD 金額 decimal(18,6) 無條件捨去

TC-REG-FIN-015 詳細步驟:後台存款審核

步驟操作驗證點
1後台管理員登入(需 deposit:read + deposit:write 權限)成功登入
2進入「財務管理 > 存款審核」頁面載入
3觀察 SiteTabs顯示站點 Tab(全站模式下顯示所有站)
4選擇 C9 站 Tab列表僅顯示 C9 站資料
5使用篩選條件按訂單 ID / 用戶 ID / 狀態 / 日期 篩選
6找到待審核的訂單狀態顯示「待審核」標籤
7點擊「審核」按鈕審核對話框彈出
8選擇「通過」並確認發送 POST /api/admin/finance/deposit-review/:id/review
9檢查訂單狀態更新狀態變為「已通過」
10檢查用戶餘額餘額已增加對應金額
11檢查操作紀錄admin-operation-log 記錄審核操作

9.12.11 詳細測試步驟:VIP 模組

TC-REG-VIP-006 詳細步驟:每日反水結算

步驟操作驗證點
1確認用戶 VIP 等級(如 VIP 5)資料庫確認
2確認反水規則(C9 站 VIP 5 各遊戲類型)查詢 vip-rebate 表
3確認用戶前一日有投注紀錄查詢 bet-order 表
4記錄各遊戲類型的投注金額分 8 類統計
5手動觸發反水結算(或等待 00:05 Cron)Cron job 執行
6計算預期反水各類型投注 × 對應反水率
7加總所有遊戲類型反水使用 truncateUsd() 截斷
8檢查 vip-rebate-log新增反水發放紀錄
9檢查用戶餘額餘額增加 = 步驟 7 的反水總額
10確認多站點隔離C9 站反水不影響 A1 站用戶

TC-REG-VIP-016 詳細步驟:VIP 帶入模板

步驟操作驗證點
1後台進入「VIP > 等級管理」頁面載入
2選擇 A1 站 Tab顯示 A1 站 VIP 等級
3記錄 A1 站當前 VIP 等級數量和設定記錄基準值
4記錄 C9 站(預設站)VIP 等級設定記錄來源值
5點擊「帶入模板」按鈕預覽對話框彈出
6確認模板內容顯示預設 VIP 等級設定
7可編輯模板內容修改部分設定
8點擊確認發送 POST /vip/admin/load-template(含 siteCode=A1)
9檢查 A1 站 VIP 等級更新為模板內容
10檢查 C9 站 VIP 等級不受影響(仍為原始設定)
11檢查 B2 站 VIP 等級不受影響

9.12.12 詳細測試步驟:代理模組

TC-REG-AFF-008 詳細步驟:佣金週結

步驟操作驗證點
1確認代理 A 有下線用戶查詢代理關係
2確認下線用戶上週有投注查詢 bet-order
3確認代理 A 的佣金費率按等級 × 遊戲類型查詢 commission-rates
4手動觸發週結(POST /affiliate/admin/trigger-settlement)或等待每週一 03:00 Cron
5檢查結算風控affiliate-risk-log 記錄
6檢查結算記錄affiliate-settlement 新增記錄
7計算預期佣金各遊戲類型投注 × 對應佣金費率
8驗證佣金金額結算金額 = 步驟 7 的計算結果
9檢查代理佣金餘額affiliate-balance 增加
10檢查結算狀態依風控結果決定:pending / approved

9.12.13 詳細測試步驟:報表模組

TC-REG-REPORT-003 詳細步驟:總覽報表

步驟操作驗證點
1後台管理員登入(需 report:read 權限)成功登入
2進入「報表 > 總覽」頁面載入
3觀察 SiteTabs顯示站點 Tab
4選擇 C9 站 Tab資料篩選為 C9 站
5設定日期範圍(近 7 天)篩選條件更新
6檢查統計卡片顯示:總存款、總提款、總投注、總派彩、淨利
7驗證總存款= SUM(deposit-order.amount WHERE status=completed AND siteCode=C9 AND dateRange)
8驗證總提款= SUM(withdrawal-order.amount WHERE status=completed AND siteCode=C9 AND dateRange)
9驗證總投注= SUM(bet-order.betAmount WHERE siteCode=C9 AND dateRange)
10驗證總派彩= SUM(bet-order.payoutAmount WHERE siteCode=C9 AND dateRange)
11驗證淨利= 總存款 - 總提款 - 總派彩 + 總投注(或定義的公式)
12檢查每日摘要表格按日分群,各日數據正確
13切換 A1 站 Tab資料切換為 A1 站,數值不同

9.12.14 詳細測試步驟:風控模組

TC-REG-RISK-008 詳細步驟:遊戲黑名單

步驟操作驗證點
1後台管理員進入「風控 > 遊戲黑名單」頁面載入
2選擇 C9 站 Tab列表篩選為 C9 站
3點擊「新增黑名單」新增對話框彈出
4選擇用戶(如 test_user_C9_001)用戶搜尋功能
5選擇封鎖類型:「全封鎖」全部遊戲類型封鎖
6點擊確認發送 POST API,建立黑名單
7確認列表更新新增一筆黑名單記錄
8前台切換至 test_user_C9_001登入該帳號
9嘗試啟動任意遊戲發送 POST /api/game/launch
10檢查回應錯誤碼 5010(遊戲黑名單)
11確認無法進入遊戲前台顯示被封鎖提示
12回到後台刪除黑名單刪除成功
13前台再次啟動遊戲成功進入遊戲

9.12.15 Cron 排程回歸測試

測試方式:手動觸發排程或修改 Cron 時間,驗證排程邏輯正確性。

每日排程

  • [ ] TC-REG-CRON-001: 每日反水結算(00:05) → 計算前一日投注的反水並發放
  • [ ] TC-REG-CRON-002: 反水結算只計算前一日資料 → 不包含當日投注
  • [ ] TC-REG-CRON-003: 反水結算多站點隔離 → 各站獨立計算
  • [ ] TC-REG-CRON-004: 反水結算含 8 種遊戲類型 → 每種類型獨立計算
  • [ ] TC-REG-CRON-005: 反水結算用戶無投注 → 不產生反水紀錄
  • [ ] TC-REG-CRON-006: 代理佣金日結(03:30) → 計算前一日的佣金
  • [ ] TC-REG-CRON-007: 日結含風控檢測 → 異常下線標記
  • [ ] TC-REG-CRON-008: 即時賽事更新(每 30 分鐘) → API-Football 資料快取更新

每週排程

  • [ ] TC-REG-CRON-009: 代理佣金週結(每週一 03:00) → 計算上週佣金
  • [ ] TC-REG-CRON-010: 週結含風控檢測 → 結算風控紀錄完整
  • [ ] TC-REG-CRON-011: 週結結果 → 產生 affiliate-settlement 記錄

每月排程

  • [ ] TC-REG-CRON-012: VIP 月度保級(每月 1 號 01:00) → 檢查上月投注
  • [ ] TC-REG-CRON-013: 保級失敗 → VIP 4 以下可能降級
  • [ ] TC-REG-CRON-014: VIP 5+ 保級鎖定 → 不因保級失敗而降級
  • [ ] TC-REG-CRON-015: 保級多站點隔離 → 各站獨立保級規則

排程錯誤處理

  • [ ] TC-REG-CRON-016: 排程執行中伺服器重啟 → 不產生重複結算
  • [ ] TC-REG-CRON-017: 排程執行失敗 → 錯誤日誌記錄
  • [ ] TC-REG-CRON-018: 排程重複觸發防護 → 使用鎖機制防止並發

9.12.16 統一回應格式回歸

  • [ ] TC-REG-RESP-001: 成功回應格式 → { code: 200, message: "ok", result, timestamp, path }
  • [ ] TC-REG-RESP-002: 業務錯誤格式 → HTTP 200, code != 200, message 為當前語系錯誤訊息
  • [ ] TC-REG-RESP-003: 未授權格式 → HTTP 401, { code: 401, message: "Unauthorized" }
  • [ ] TC-REG-RESP-004: timestamp 格式 → ISO 8601 格式
  • [ ] TC-REG-RESP-005: path 欄位 → 正確反映請求路徑
  • [ ] TC-REG-RESP-006: 錯誤碼查表 → ERROR_CODES[path][code] 在前端正確映射
  • [ ] TC-REG-RESP-007: GET /common/enums → 回傳完整 ERROR_CODES
  • [ ] TC-REG-RESP-008: 各語系錯誤訊息 → 切換語系後錯誤訊息對應變化
  • [ ] TC-REG-RESP-009: 前端不硬寫錯誤文字 → 所有錯誤來自 ERROR_CODES 查表
  • [ ] TC-REG-RESP-010: 分頁回應格式 → { items: [], pagination: { total, page, pageSize, totalPages } }

9.12.17 元件庫回歸

共用元件驗證

  • [ ] TC-REG-COMP-001: SiteTabs — 多站 Tab 切換正確、activeSiteId 追蹤
  • [ ] TC-REG-COMP-002: SiteTabs — defaultLabel 顯示「預設站點」文字
  • [ ] TC-REG-COMP-003: SiteTabs — copyLabel 顯示「同預設站點」按鈕
  • [ ] TC-REG-COMP-004: SiteTabs — onCopyFromDefault 回調觸發
  • [ ] TC-REG-COMP-005: FilterBar — text 類型欄位正確篩選
  • [ ] TC-REG-COMP-006: FilterBar — date 類型欄位日期選擇器
  • [ ] TC-REG-COMP-007: FilterBar — select 類型欄位下拉選單
  • [ ] TC-REG-COMP-008: FilterBar — onSearch 搜尋回調
  • [ ] TC-REG-COMP-009: FilterBar — onReset 重置所有篩選
  • [ ] TC-REG-COMP-010: SimpleTable — 資料列表渲染
  • [ ] TC-REG-COMP-011: SimpleTable — loading 狀態顯示 Spinner
  • [ ] TC-REG-COMP-012: SimpleTable — emptyText 空資料提示
  • [ ] TC-REG-COMP-013: SimpleTable — rowKey 唯一識別
  • [ ] TC-REG-COMP-014: SimpleTable — pagination 分頁整合
  • [ ] TC-REG-COMP-015: Pagination — 頁碼顯示正確
  • [ ] TC-REG-COMP-016: Pagination — onPageChange 回調
  • [ ] TC-REG-COMP-017: Pagination — 首頁/末頁/上一頁/下一頁
  • [ ] TC-REG-COMP-018: StatusBadge — 各狀態對應正確顏色(colorMap)
  • [ ] TC-REG-COMP-019: ConfirmDialog — 標題/描述/變體(destructive)
  • [ ] TC-REG-COMP-020: ConfirmDialog — 確認返回 true、取消返回 false
  • [ ] TC-REG-COMP-021: HtmlEditor — Tiptap 富文本編輯
  • [ ] TC-REG-COMP-022: HtmlEditor — 安全 HTML 輸出(XSS 防護)
  • [ ] TC-REG-COMP-023: ExportButton — CSV 匯出觸發
  • [ ] TC-REG-COMP-024: ExportButton — 檔案下載成功
  • [ ] TC-REG-COMP-025: LoadingSpinner — 載入動畫顯示
  • [ ] TC-REG-COMP-026: AccessDenied — 無權限提示頁面
  • [ ] TC-REG-COMP-027: TemplatePreviewDialog — 模板預覽顯示
  • [ ] TC-REG-COMP-028: TemplatePreviewDialog — 可編輯 + 確認
  • [ ] TC-REG-COMP-029: GoogleAuthDialog — idle → qr → verify 狀態流轉
  • [ ] TC-REG-COMP-030: ThemeInjector — CSS 變數正確注入

Hook 驗證

  • [ ] TC-REG-HOOK-001: useApi — Facade 合併所有 domain hook
  • [ ] TC-REG-HOOK-002: useApiQuery — 通用查詢(自動提取 result)
  • [ ] TC-REG-HOOK-003: useApiListQuery — 列表查詢(自動正規化分頁)
  • [ ] TC-REG-HOOK-004: useApiMutation — 變更操作(invalidateKeys)
  • [ ] TC-REG-HOOK-005: useMultiSiteTabs — visibleSites / activeSiteId / activeSiteCode
  • [ ] TC-REG-HOOK-006: useMultiSiteTabs — onSiteChange 回調(重置分頁)
  • [ ] TC-REG-HOOK-007: useInitEnums — 啟動時拉取 /common/enums
  • [ ] TC-REG-HOOK-008: useNotify — success / error / warning / info Toast
  • [ ] TC-REG-HOOK-009: usePermissions — can / canRead / canWrite / isRoot
  • [ ] TC-REG-HOOK-010: useDomainConfig — 域名解析 siteCode / baseURL
  • [ ] TC-REG-HOOK-011: useR2Url — R2 儲存 URL 產生
  • [ ] TC-REG-HOOK-012: useConfirm — 確認對話框 hook

Store 驗證

  • [ ] TC-REG-STORE-001: siteFilterStore — selectedSiteCode 正確更新
  • [ ] TC-REG-STORE-002: siteFilterStore — sites 列表正確填充
  • [ ] TC-REG-STORE-003: siteFilterStore — sessionStorage 持久化
  • [ ] TC-REG-STORE-004: enumStore — 錯誤碼枚舉快取
  • [ ] TC-REG-STORE-005: enumStore — ERROR_CODES[path][code] 查表
  • [ ] TC-REG-STORE-006: uiStore — sidebar 展開/收合狀態

9.12.18 API Client 回歸

apiClient 攔截器驗證

  • [ ] TC-REG-API-001: 動態 baseURL → 依域名解析 domainConfig
  • [ ] TC-REG-API-002: site-name Header → 白牌路由自動注入
  • [ ] TC-REG-API-003: locales Header → 從 NEXT_LOCALE cookie 讀取
  • [ ] TC-REG-API-004: x-site-code Header → 從 siteFilterStore 注入
  • [ ] TC-REG-API-005: Authorization Header → Bearer JWT 從 SessionSync
  • [ ] TC-REG-API-006: 401 重試機制 → 清 token → 重取 session → retry
  • [ ] TC-REG-API-007: 401 重試失敗 → 導向登入頁
  • [ ] TC-REG-API-008: 401 不無限重試 → 最多重試 1 次
  • [ ] TC-REG-API-009: getSiteConfigs 跳過 x-site-code → 必須回傳全站資料

httpRequest 三層錯誤處理驗證

  • [ ] TC-REG-API-010: 第一層:enumStore 查表 → errorCodes[path][code]
  • [ ] TC-REG-API-011: 第一層::id 萬用路徑匹配 → /admin/finance/users/:id
  • [ ] TC-REG-API-012: 第二層:呼叫端 errorMessage → string 覆寫
  • [ ] TC-REG-API-013: 第二層:呼叫端 errorMessage → Record<code, msg> 覆寫
  • [ ] TC-REG-API-014: 第三層:自動 Toast → toast.error(message)
  • [ ] TC-REG-API-015: errorToast: false → 停用自動 Toast

9.12.19 前台 (c9-ec) 核心功能回歸

Composable 驗證

  • [ ] TC-REG-EC-001: useConfig — domainConfig[hostname] 域名設定
  • [ ] TC-REG-EC-002: useConfig — site-name header 自動注入
  • [ ] TC-REG-EC-003: Pinia 狀態管理 — 用戶狀態正確
  • [ ] TC-REG-EC-004: Nuxt UI v4 — 元件正確渲染
  • [ ] TC-REG-EC-005: FingerprintJS v5 — 指紋正確產生
  • [ ] TC-REG-EC-006: Zod v4 前端驗證 — 表單驗證正確

前台多語系驗證

  • [ ] TC-REG-EC-007: @nuxtjs/i18n — no_prefix 策略(cookie)
  • [ ] TC-REG-EC-008: 語系切換 → Cookie 更新
  • [ ] TC-REG-EC-009: 5 個語系檔案同步 → 無裸 key
  • [ ] TC-REG-EC-010: ICU 格式轉義 → 大括號顯示正確

前台佈局驗證

  • [ ] TC-REG-EC-011: A1 佈局 — components/A1/ 元件正確
  • [ ] TC-REG-EC-012: 響應式斷點 — mobile / tablet / desktop
  • [ ] TC-REG-EC-013: CSS 變數主題注入 — 6 組預設主題
  • [ ] TC-REG-EC-014: 底部導航列 — 行動版 Tab

前台 API 整合

  • [ ] TC-REG-EC-015: API 統一回應格式 → code / message / result
  • [ ] TC-REG-EC-016: ERROR_CODES 查表 → 不硬寫錯誤文字
  • [ ] TC-REG-EC-017: JWT 過期處理 → 自動重新登入
  • [ ] TC-REG-EC-018: site-name header → 白牌路由正確

9.12.20 後端 (c9-be) 核心功能回歸

框架驗證

  • [ ] TC-REG-BE-001: NestJS v11 啟動正常
  • [ ] TC-REG-BE-002: TypeORM 0.3.28 連線正常
  • [ ] TC-REG-BE-003: MySQL utf8mb4 字元集
  • [ ] TC-REG-BE-004: MySQL TZ +08:00
  • [ ] TC-REG-BE-005: Redis (@keyv/redis) 連線正常
  • [ ] TC-REG-BE-006: Swagger UI 開發環境可用

Guard 與 Decorator 驗證

  • [ ] TC-REG-BE-007: JwtAuthGuard — 前台用戶 JWT 認證
  • [ ] TC-REG-BE-008: OptionalJwtAuthGuard — 可選認證(未認證返回 null)
  • [ ] TC-REG-BE-009: AdminJwtAuthGuard — 後台管理員 JWT 認證
  • [ ] TC-REG-BE-010: PermissionsGuard — RBAC 權限檢查
  • [ ] TC-REG-BE-011: @AdminSiteCode() — header 優先於 query param
  • [ ] TC-REG-BE-012: @SiteName() — 讀取 site-name header
  • [ ] TC-REG-BE-013: @RequirePermissions() — 權限元資料
  • [ ] TC-REG-BE-014: SiteCodeSubscriber — Entity insert 自動填入 siteCode

工具函式驗證

  • [ ] TC-REG-BE-015: parsePagination(query) — 預設 page=1, pageSize=20
  • [ ] TC-REG-BE-016: applyDateRange(qb, col, start, end) — BETWEEN 查詢
  • [ ] TC-REG-BE-017: truncateUsd(value) — Math.floor(value * 1e6) / 1e6
  • [ ] TC-REG-BE-018: resolveText(record, locale) — 多語系文字解析
  • [ ] TC-REG-BE-019: maskAccount(account) — 帳號遮罩

Cron 排程驗證

  • [ ] TC-REG-BE-020: @nestjs/schedule — Cron 裝飾器正確觸發
  • [ ] TC-REG-BE-021: 每日反水結算 — 00:05 觸發
  • [ ] TC-REG-BE-022: 月度保級 — 每月 1 號 01:00 觸發
  • [ ] TC-REG-BE-023: 代理週結 — 每週一 03:00 觸發
  • [ ] TC-REG-BE-024: 代理日結 — 每日 03:30 觸發
  • [ ] TC-REG-BE-025: 賽事更新 — 每 30 分鐘觸發

9.13 多站點回歸

9.13.1 站點切換

  • [ ] TC-REG-SITE-001: SiteSelector 下拉選單 → 顯示「全部站點」和各站點
  • [ ] TC-REG-SITE-002: 切換至全部站點 → SiteTabs 顯示所有站 Tab
  • [ ] TC-REG-SITE-003: 切換至單站點 → SiteTabs 僅顯示該站 Tab
  • [ ] TC-REG-SITE-004: 站點切換清除快取 → TanStack Query cache 清除
  • [ ] TC-REG-SITE-005: AdminContentWrapper remount → key={selectedSiteCode} 觸發重掛載

9.13.2 資料隔離

  • [ ] TC-REG-SITE-006: 各站點資料獨立 → 不同站點列表資料不同
  • [ ] TC-REG-SITE-007: x-site-code Header → apiClient 自動注入
  • [ ] TC-REG-SITE-008: siteCode query param → 全站模式手動傳入
  • [ ] TC-REG-SITE-009: SiteCodeSubscriber → Entity insert 自動填入 siteCode

9.13.3 複製與模板

  • [ ] TC-REG-SITE-010: 同預設站點(前端拷貝) → 5 個設定頁面正確拷貝
  • [ ] TC-REG-SITE-011: 同預設站點(後端 API) → 遊戲/VIP 正確複製
  • [ ] TC-REG-SITE-012: 帶入模板 → 只影響當前站點
  • [ ] TC-REG-SITE-013: 複製不影響其他站 → B2 站資料不受 A1 複製影響

9.13.4 特殊頁面

  • [ ] TC-REG-SITE-014: 管理員/群組/紀錄 → SiteSelector 自動隱藏
  • [ ] TC-REG-SITE-015: getSiteConfigs → 必須回傳全站資料(跳過 siteCode 篩選)

9.14 多語系回歸

9.14.1 語系切換

  • [ ] TC-REG-I18N-001: 繁體中文 (zh-TW) → 所有文字正確顯示
  • [ ] TC-REG-I18N-002: 英文 (en-US) → 所有文字正確顯示
  • [ ] TC-REG-I18N-003: 簡體中文 (zh-CN) → 所有文字正確顯示
  • [ ] TC-REG-I18N-004: 泰文 (th-TH) → 所有文字正確顯示
  • [ ] TC-REG-I18N-005: 越南文 (vi-VN) → 所有文字正確顯示

9.14.2 語系功能

  • [ ] TC-REG-I18N-006: Cookie 儲存語系偏好 → 重新載入後保留
  • [ ] TC-REG-I18N-007: 後端錯誤訊息多語系 → 根據 locales header 回傳
  • [ ] TC-REG-I18N-008: 日期格式多語系 → 各語系日期格式正確
  • [ ] TC-REG-I18N-009: ICU 格式大括號轉義 → '{'xxx'}' 正確顯示
  • [ ] TC-REG-I18N-010: 5 個語系檔案同步 → 所有 key 都存在於所有檔案
  • [ ] TC-REG-I18N-011: ERROR_CODES 查表 → 前端不硬寫錯誤文字

9.15 主題回歸

9.15.1 主題功能

  • [ ] TC-REG-THEME-001: 前台 6 組主題預設 → 各主題正確套用
  • [ ] TC-REG-THEME-002: 自訂主題 → 後台設定完整色號體系(primary/accent/surface/text/border)
  • [ ] TC-REG-THEME-003: CSS 變數注入 → 前台 CSS variables 正確
  • [ ] TC-REG-THEME-004: OKLCH 色彩(後台) → 30+ CSS custom properties 正確
  • [ ] TC-REG-THEME-005: Light/Dark 模式(後台) → 切換正確
  • [ ] TC-REG-THEME-006: 主題持久化 → 重新載入後保留主題設定
  • [ ] TC-REG-THEME-007: 各站獨立主題 → site-theme 表按站點區分

9.16 前台佈局回歸

9.16.1 響應式設計

  • [ ] TC-REG-LAYOUT-001: 桌面版(>= 1024px) → 完整 sidebar + 主內容區
  • [ ] TC-REG-LAYOUT-002: 平板版(768px - 1023px) → 收合 sidebar
  • [ ] TC-REG-LAYOUT-003: 手機版(< 768px) → 底部導航列 + 漢堡選單
  • [ ] TC-REG-LAYOUT-004: 前台 A1 佈局 → 元件在 components/A1/

9.16.2 佈局元件

  • [ ] TC-REG-LAYOUT-005: 底部導航列 → 行動版 Tab 項目正確(後台可配置)
  • [ ] TC-REG-LAYOUT-006: 頁尾 → 連結和版權資訊正確(後台可配置)
  • [ ] TC-REG-LAYOUT-007: 「了解更多」區塊 → 內容正確(後台可配置)
  • [ ] TC-REG-LAYOUT-008: 吉祥物 → R2 圖片正確載入(後台可配置)

9.16.3 後台佈局

  • [ ] TC-REG-LAYOUT-009: (admin) Route Group → 登入後含 sidebar + header
  • [ ] TC-REG-LAYOUT-010: (auth) Route Group → 登入頁面獨立佈局
  • [ ] TC-REG-LAYOUT-011: Sidebar → 14+ 群組、50+ 項目、Feature Flag + RBAC
  • [ ] TC-REG-LAYOUT-012: Header → SiteSelector + 個人資料 + 語系切換
  • [ ] TC-REG-LAYOUT-013: scrollToTop → 路由變更自動捲至頂部
  • [ ] TC-REG-LAYOUT-014: localeGuard → 不支援的語系自動導向

第 10 章:Bug 報告模板

使用說明:所有測試中發現的缺陷,統一使用以下模板建立 Bug 報告,確保資訊完整、可追蹤。


10.1 Bug 報告標準模板

markdown
### Bug 報告

**Bug-ID**: BUG-[模組]-[序號]
**標題**: [簡短描述問題,不超過 80 字元]

---

#### 基本資訊

| 欄位 | 內容 |
|------|------|
| **嚴重程度** | Critical / Major / Minor / Trivial |
| **優先級** | P1 / P2 / P3 / P4 |
| **發現日期** | YYYY-MM-DD |
| **報告人** | [姓名] |
| **指派給** | [開發人員] |
| **狀態** | New / Open / In Progress / Fixed / Verified / Closed |
| **模組** | [所屬模組,如:auth / game / finance / vip / affiliate / risk / report / system] |
| **相關測試案例** | [TC-ID,如:TC-SEC-JWT-002] |

#### 環境資訊

| 項目 | 詳情 |
|------|------|
| **瀏覽器** | Chrome 120 / Safari 17 / Firefox 121 / Edge 120 |
| **作業系統** | macOS 14 / Windows 11 / iOS 17 / Android 14 |
| **螢幕解析度** | 1920x1080 / 1440x900 / 375x812 / 390x844 |
| **語系** | zh-TW / en-US / zh-CN / th-TH / vi-VN |
| **站點** | C9 / A1 / [siteCode] |
| **專案** | c9-ec / c9-ims / c9-be |
| **環境** | localhost / staging / production |
| **分支** | master / [branch-name] |
| **Commit** | [commit hash] |

#### 前置條件

> 描述重現 Bug 前系統需要處於什麼狀態。

1. [條件 1,如:用戶已登入且 VIP 等級為 5]
2. [條件 2,如:站點設定已包含遊戲供應商 BetSolutions]
3. [條件 3,如:Redis 快取已清空]

#### 重現步驟

1. [步驟 1,如:登入後台管理系統]
2. [步驟 2,如:進入「財務管理 > 存款審核」頁面]
3. [步驟 3,如:切換站點至 A1]
4. [步驟 4,如:點擊「搜尋」按鈕]
5. [步驟 5,如:觀察列表顯示]

**重現率**: 100% / 80% / 偶發

#### 預期結果

> 描述系統應該呈現的正確行為。

- [預期結果 1]
- [預期結果 2]

#### 實際結果

> 描述系統實際呈現的錯誤行為。

- [實際結果 1]
- [實際結果 2]

#### 附件

- **截圖**: [附加截圖或標註]
- **影片**: [螢幕錄影 URL]
- **Console 錯誤**:

[複製瀏覽器 Console 的錯誤訊息]

- **API 請求/回應**:
```json
// Request
{
  "method": "GET",
  "url": "/api/admin/finance/deposit-review/list",
  "headers": { "x-site-code": "A1" }
}

// Response
{
  "code": 500,
  "message": "Internal Server Error",
  "result": null
}
  • 後端日誌:
[相關的後端日誌片段]

備註

  • [任何補充資訊]
  • [可能的根因推測]
  • [暫時解決方案]

---

## 10.2 嚴重程度定義

| 等級 | 名稱 | 定義 | 範例 |
|------|------|------|------|
| **S1** | Critical(嚴重) | 系統崩潰、資料遺失、安全漏洞、核心功能完全無法使用 | 登入功能完全失效、用戶餘額計算錯誤、SQL 注入漏洞、資料庫連線中斷、JWT Token 可被偽造 |
| **S2** | Major(重大) | 核心功能異常,無替代方案 | 存款流程失敗、遊戲無法啟動、VIP 等級計算錯誤、代理佣金結算異常、報表數據不正確、提款審核無法操作 |
| **S3** | Minor(一般) | 功能異常但有替代方案,或非核心功能異常 | 篩選條件無效(可手動翻頁)、分頁計算偏差、排序不正確、匯出 CSV 少欄位、SiteTabs 切換後未重置分頁 |
| **S4** | Trivial(輕微) | 外觀問題、錯字、微小 UI 不一致 | 圖示顯示不正確、文字對齊偏差、翻譯缺失或錯誤、按鈕 hover 效果不一致、空白頁面缺少 loading 動畫 |

### 嚴重程度判定流程

系統可以正常使用嗎? ├── 否 → 系統崩潰/無法啟動? │ ├── 是 → S1 Critical │ └── 否 → 核心功能(認證/金流/遊戲)受影響? │ ├── 是 → S2 Major │ └── 否 → S3 Minor └── 是 → 功能有問題嗎? ├── 是 → 有替代方案嗎? │ ├── 是 → S3 Minor │ └── 否 → S2 Major └── 否 → 僅外觀/文字問題 → S4 Trivial


---

## 10.3 優先級定義

| 等級 | 名稱 | SLA(修復期限) | 說明 | 適用場景 |
|------|------|----------------|------|----------|
| **P1** | 緊急 | 4 小時內修復 | 生產環境阻斷性問題,影響所有用戶 | 登入/存款/提款完全失效、安全漏洞、資料庫崩潰 |
| **P2** | 高 | 24 小時內修復 | 核心功能嚴重異常 | 遊戲無法啟動、VIP 計算錯誤、報表數據錯誤、代理結算異常 |
| **P3** | 中 | 1 週內修復 | 一般功能問題 | 篩選不正確、分頁問題、非核心頁面異常 |
| **P4** | 低 | 下次發布時修復 | 外觀/改善需求 | UI 微調、翻譯修正、非關鍵增強功能 |

### 嚴重程度與優先級的對應關係

| | P1(緊急) | P2(高) | P3(中) | P4(低) |
|---|---|---|---|---|
| **S1(Critical)** | 常見 | 罕見 | - | - |
| **S2(Major)** | 可能 | 常見 | 可能 | - |
| **S3(Minor)** | - | 可能 | 常見 | 可能 |
| **S4(Trivial)** | - | - | 罕見 | 常見 |

> **說明**:嚴重程度和優先級是兩個獨立維度。S2 的 Bug 可能因為只影響少數用戶而被標記為 P3;S3 的 Bug 可能因為影響重要客戶而被提升為 P2。

---

## 10.4 Bug 生命週期

### 狀態流轉圖

┌─────────────────────────────────────────────────────────┐ │ │ │ ┌─────┐ ┌──────┐ ┌─────────────┐ │ │ │ New │────▶│ Open │────▶│ In Progress │ │ │ └─────┘ └──────┘ └──────┬──────┘ │ │ │ │ │ │ │ ▼ │ │ │ ┌───────────┐ │ │ │ │ Fixed │ │ │ │ └─────┬─────┘ │ │ │ │ │ │ │ ▼ │ │ │ ┌──────────┐ ┌────────┐ │ │ │ │ Verified │───▶│ Closed │ │ │ │ └────┬─────┘ └────────┘ │ │ │ │ │ │ │ │ 驗證失敗 │ │ │ ▼ │ │ │ ┌──────────┐ │ │ │ │ Reopened │ │ │ │ └──────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────────────────────────┐ │ │ │ Won't Fix / Duplicate / │ │ │ │ Cannot Reproduce / By Design │ │ │ └────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘


### 各狀態說明

| 狀態 | 說明 | 負責人 | 動作 |
|------|------|--------|------|
| **New** | 新建立的 Bug 報告,尚未審查 | QA | 填寫完整 Bug 報告 |
| **Open** | 已審查確認為有效 Bug,等待指派 | 測試經理 | 確認嚴重程度/優先級,指派開發人員 |
| **In Progress** | 開發人員正在修復中 | 開發人員 | 分析根因,撰寫修復程式碼 |
| **Fixed** | 已完成修復,等待 QA 驗證 | 開發人員 | 提交 commit,標註修復的 Bug-ID |
| **Verified** | QA 驗證修復成功 | QA | 重新執行相關測試案例 |
| **Closed** | Bug 完全解決,流程結束 | QA | 更新測試報告 |
| **Reopened** | 驗證時發現修復不完整 | QA | 說明仍然存在的問題 |
| **Won't Fix** | 決定不修復(風險可接受) | 測試經理/PM | 記錄決策原因 |
| **Duplicate** | 與已知 Bug 重複 | QA | 關聯原始 Bug-ID |
| **Cannot Reproduce** | 無法重現 | QA/開發人員 | 要求提供更多資訊或環境 |
| **By Design** | 屬於設計行為,非 Bug | PM | 確認需求文件 |

---

## 10.5 測試報告模板

### 10.5.1 測試週期報告

```markdown
# 測試報告

## 基本資訊

| 項目 | 內容 |
|------|------|
| **測試週期** | YYYY-MM-DD ~ YYYY-MM-DD |
| **測試範圍** | [列出此次測試涵蓋的模組] |
| **測試環境** | localhost / staging / production |
| **後端版本** | c9-be commit: [hash] |
| **前台版本** | c9-ec commit: [hash] |
| **後台版本** | c9-ims commit: [hash] |
| **資料庫** | MySQL 8.0, Seed 資料版本: [date] |
| **測試人員** | [姓名列表] |

---

## 測試結果統計

### 整體統計

| 狀態 | 數量 | 百分比 |
|------|------|--------|
| 通過 (Passed) | XX | XX% |
| 失敗 (Failed) | XX | XX% |
| 阻塞 (Blocked) | XX | XX% |
| 未執行 (Not Run) | XX | XX% |
| **合計** | **XX** | **100%** |

### 各模組通過率

| 模組 | 測試案例數 | 通過 | 失敗 | 阻塞 | 通過率 |
|------|-----------|------|------|------|--------|
| 認證模組 | XX | XX | XX | XX | XX% |
| 遊戲模組 | XX | XX | XX | XX | XX% |
| 金流模組 | XX | XX | XX | XX | XX% |
| 錢包模組 | XX | XX | XX | XX | XX% |
| VIP 模組 | XX | XX | XX | XX | XX% |
| 代理模組 | XX | XX | XX | XX | XX% |
| 活動模組 | XX | XX | XX | XX | XX% |
| 任務模組 | XX | XX | XX | XX | XX% |
| 站內信模組 | XX | XX | XX | XX | XX% |
| 風控模組 | XX | XX | XX | XX | XX% |
| 報表模組 | XX | XX | XX | XX | XX% |
| 系統管理 | XX | XX | XX | XX | XX% |
| 多站點 | XX | XX | XX | XX | XX% |
| 多語系 | XX | XX | XX | XX | XX% |
| 安全性 | XX | XX | XX | XX | XX% |
| **總計** | **XX** | **XX** | **XX** | **XX** | **XX%** |

---

## 新發現缺陷

### 缺陷統計

| 嚴重程度 | 新增 | 修復 | 未關閉 |
|----------|------|------|--------|
| S1 Critical | XX | XX | XX |
| S2 Major | XX | XX | XX |
| S3 Minor | XX | XX | XX |
| S4 Trivial | XX | XX | XX |
| **合計** | **XX** | **XX** | **XX** |

### 缺陷清單

| Bug-ID | 標題 | 嚴重程度 | 優先級 | 模組 | 狀態 | 指派 |
|--------|------|----------|--------|------|------|------|
| BUG-AUTH-001 | [標題] | S2 | P2 | 認證 | Open | [人員] |
| BUG-FIN-001 | [標題] | S1 | P1 | 金流 | In Progress | [人員] |
| ... | ... | ... | ... | ... | ... | ... |

---

## 風險評估

### 高風險項目

| 風險 | 影響 | 緩解措施 |
|------|------|----------|
| [描述風險 1] | [影響範圍] | [建議處理方式] |
| [描述風險 2] | [影響範圍] | [建議處理方式] |

### 未測試項目

| 項目 | 原因 | 計劃 |
|------|------|------|
| [未測項目 1] | [阻塞原因] | [後續計劃] |
| [未測項目 2] | [阻塞原因] | [後續計劃] |

---

## 結論與建議

### 測試結論

- [ ] 建議發布:所有 P1/P2 缺陷已修復並驗證
- [ ] 有條件發布:存在未關閉的 P2 缺陷,但有暫時解決方案
- [ ] 不建議發布:存在未關閉的 P1 缺陷

### 改善建議

1. [建議 1]
2. [建議 2]
3. [建議 3]

---

## 附錄

### 測試案例執行明細

| TC-ID | 測試說明 | 結果 | 備註 |
|-------|----------|------|------|
| TC-XXX-001 | ... | Pass/Fail/Block | [備註] |
| ... | ... | ... | ... |

10.5.2 每日測試摘要模板

markdown
# 每日測試摘要 — YYYY-MM-DD

## 今日進度

| 項目 | 數量 |
|------|------|
| 執行測試案例 | XX |
| 通過 | XX |
| 失敗 | XX |
| 新建 Bug | XX |
| 驗證通過 Bug | XX |

## 新發現缺陷

| Bug-ID | 標題 | 嚴重程度 | 模組 |
|--------|------|----------|------|
| ... | ... | ... | ... |

## 阻塞項目

| 項目 | 阻塞原因 | 需要支援 |
|------|----------|----------|
| ... | ... | ... |

## 明日計劃

- [ ] [計劃 1]
- [ ] [計劃 2]

附錄 A:測試資料準備指南

目標:提供完整的測試資料建立流程,確保測試環境一致性和可重複性。


A.1 Seed 腳本

A.1.1 執行 Seed

C9 平台提供一鍵 Seed 腳本,可建立 5 個站點 × 30 個用戶及所有相關資料。

bash
# 確保後端已安裝相依套件
cd c9-be && yarn install

# 執行 Seed 腳本(建立所有測試資料)
npx ts-node scripts/seed-all.ts

A.1.2 Seed 資料涵蓋範圍

資料表數量說明
site-config5站點配置(C9, A1, B2, D3, E4)
site-theme5+各站點主題
auth-user1505 站 × 30 用戶
admin-user5+各權限等級管理員
admin-group4root / super_admin / general_admin / custom
game-provider10+各站遊戲供應商
game-type-config40+8 遊戲類型 × 5 站
vip-level75+15 等級 × 5 站
vip-rebate600+15 等級 × 8 遊戲類型 × 5 站
deposit-order300+各種狀態的存款訂單
withdrawal-order200+各種狀態的提款訂單
bet-order500+各遊戲類型的投注紀錄
promo30+各站活動
promo-tag20+活動標籤
notification100+站內信
bank-card50+銀行卡資料
credit-card30+信用卡資料
crypto-address30+加密地址
vendor-group10+金流群組
vendor-channel20+金流通道
risk-ip-rule20+IP 黑白名單
risk-game-blacklist10+遊戲黑名單
affiliate-*50+代理相關資料
alliance-*100+聯盟佣金費率/等級/里程碑
mission15+任務資料

A.1.3 Seed 後驗證

bash
# 確認資料正確建立(進入 MySQL)
mysql -u root -p

# 檢查各表資料量
SELECT 'site-config' AS tbl, COUNT(*) AS cnt FROM `site-config`
UNION ALL SELECT 'auth-user', COUNT(*) FROM `auth-user`
UNION ALL SELECT 'admin-user', COUNT(*) FROM `admin-user`
UNION ALL SELECT 'game-provider', COUNT(*) FROM `game-provider`
UNION ALL SELECT 'vip-level', COUNT(*) FROM `vip-level`
UNION ALL SELECT 'deposit-order', COUNT(*) FROM `deposit-order`;

A.2 測試管理員帳號

A.2.1 建立測試管理員

bash
# 方式 1:透過 Seed 腳本(自動建立)
npx ts-node scripts/seed-all.ts

# 方式 2:透過 API(手動建立)
curl -X POST http://localhost:8080/api/admin/register \
  -H "Content-Type: application/json" \
  -d '{
    "account": "test_root",
    "password": "Test123!@#",
    "name": "測試管理員",
    "groupId": 1
  }'

A.2.2 預設管理員帳號

帳號密碼群組用途
root_adminRoot123!@#root最高權限,可存取所有功能
super_adminSuper123!@#super_admin進階管理員(無 site-config 權限)
general_adminGeneral123!@#general_admin一般管理員(僅讀取權限)
custom_adminCustom123!@#custom自訂權限(測試 RBAC)
2fa_adminTwofa123!@#root已啟用 2FA 的管理員

A.2.3 各群組權限對照

模組rootsuper_admingeneral_admincustom(範例)
adminR/WR/WRR
admin-groupR/WR/WR-
admin-logRRR-
userR/WR/WRR/W
depositR/WR/WRR/W
withdrawalR/WR/WRR
promoR/WR/WR-
promo-tagR/WR/WR-
affiliateR/WR/WR-
vipR/WR/WRR
gameR/WR/WR-
riskR/WR/WRR
reportRRRR
vendorR/WR/WR-
financeR/WR/WRR/W
site-configR/W---

R = Read, W = Write, - = 無權限


A.3 測試前台用戶帳號

A.3.1 Seed 用戶帳號格式

Seed 腳本建立的用戶帳號格式為:

帳號格式: test_user_{siteCode}_{number}
密碼統一: Test123!@#
帳號範例站點VIP 等級代理身份說明
test_user_C9_001C90普通新用戶
test_user_C9_002C95VIP 5 用戶
test_user_C9_003C910VIP 10 + 代理
test_user_C9_004C915最高 VIP 等級
test_user_A1_001A10A1 站普通用戶
test_user_A1_002A13A1 站代理
oauth_user_C9_001C90Google OAuth 用戶

A.3.2 特殊測試帳號

帳號用途特殊設定
test_blacklist_001遊戲黑名單測試已被加入遊戲全封鎖黑名單
test_blacklist_002遊戲類型封鎖測試已被封鎖 SLOT 類型遊戲
test_agent_top頂層代理無上線代理
test_agent_mid中層代理上線為 test_agent_top
test_agent_bot底層代理上線為 test_agent_mid(第 3 層)
test_rich_user高餘額用戶USD 餘額 100,000.000000
test_poor_user低餘額用戶USD 餘額 0.000000

A.4 測試遊戲資料

A.4.1 遊戲供應商

providerCode名稱支援遊戲類型S2S 回調
betsolutionsBetSolutionsSLOT, LIVE, CHESS/game/betsolutions/callback
rsgRSGSLOT, FISH/game/rsg/callback(DES 加解密)

A.4.2 遊戲類型 ID 對照

gameTypeID中文名稱
SPORTS1體育
SLOT2老虎機
LIVE3真人
LOTTERY4彩票
CHESS5棋牌
ESPORTS8電競
CRYPTO9加密貨幣
FISH10捕魚

A.5 測試金流資料

A.5.1 金流測試環境

金流商測試環境測試帳號
萬通金流(ATM)沙盒模式詳見萬通金流沙盒文件
萬通金流(信用卡)沙盒模式測試信用卡號: 4111-1111-1111-1111
USDT(加密貨幣)測試網使用 Testnet 地址

A.5.2 銀行卡測試資料

銀行代碼銀行名稱測試帳號持卡人
004台灣銀行0041234567890測試用戶一
005土地銀行0051234567890測試用戶二
012台北富邦0121234567890測試用戶三

A.5.3 加密地址測試資料

網路幣種測試地址說明
TRC20USDTTTestAddress123456789Tron 測試網地址
ERC20USDT0xTestAddress123456789Ethereum 測試網地址
BEP20USDT0xBscTestAddress12345BSC 測試網地址

A.6 測試資料清理

A.6.1 清理腳本

bash
# 清除所有測試資料(危險操作!僅限開發環境)
mysql -u root -p -e "
  SET FOREIGN_KEY_CHECKS = 0;
  TRUNCATE TABLE \`deposit-order\`;
  TRUNCATE TABLE \`withdrawal-order\`;
  TRUNCATE TABLE \`bet-order\`;
  TRUNCATE TABLE \`bet-detail\`;
  TRUNCATE TABLE \`game-transaction\`;
  TRUNCATE TABLE \`game-play-log\`;
  TRUNCATE TABLE \`vip-rebate-log\`;
  TRUNCATE TABLE \`promo-claim\`;
  TRUNCATE TABLE \`mission-progress\`;
  TRUNCATE TABLE \`mission-claim\`;
  TRUNCATE TABLE \`notification\`;
  TRUNCATE TABLE \`notification-read\`;
  TRUNCATE TABLE \`admin-operation-log\`;
  TRUNCATE TABLE \`r2-operation-log\`;
  TRUNCATE TABLE \`auth-user-login-log\`;
  SET FOREIGN_KEY_CHECKS = 1;
" c9_db

A.6.2 Redis 快取清理

bash
# 清除所有 Redis 快取
redis-cli FLUSHALL

# 清除特定前綴的快取
redis-cli KEYS "cache:vip:*" | xargs redis-cli DEL
redis-cli KEYS "cache:auth:*" | xargs redis-cli DEL
redis-cli KEYS "cache:admin:*" | xargs redis-cli DEL

附錄 B:API 測試工具使用指南

目標:提供使用各種工具進行 API 測試的操作指南。


B.1 Swagger UI

B.1.1 存取方式

URL: http://localhost:8080/api/docs

Swagger UI 在開發環境自動啟用,提供互動式 API 文件和測試功能。

B.1.2 認證步驟

  1. 取得 Token

    • 在 Swagger 中找到 POST /api/auth/login(前台用戶)或 POST /api/admin/login(後台管理員)
    • 填入帳號密碼,執行請求
    • 從回應中複製 result.token
  2. 設定認證

    • 點擊頁面右上方的「Authorize」按鈕
    • 在 Bearer Token 欄位輸入:Bearer {token}
    • 點擊「Authorize」確認
  3. 測試 API

    • 選擇要測試的端點
    • 填入必要參數
    • 點擊「Try it out」→「Execute」
    • 查看 Response

B.1.3 注意事項

  • Swagger UI 僅在開發環境可用,生產環境應關閉
  • 部分端點需要設定 x-site-code header(在 Parameters 中填入)
  • 檔案上傳端點需使用 multipart/form-data 格式

B.2 cURL 測試範例

B.2.1 前台認證

bash
# 登入取得 Token
curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -H "site-name: C9" \
  -d '{
    "account": "test_user_C9_001",
    "password": "Test123!@#",
    "fingerprint": "test-fingerprint-001"
  }'

# 回應範例
# {
#   "code": 200,
#   "message": "ok",
#   "result": {
#     "token": "eyJhbGciOiJIUzI1NiIs...",
#     "user": { "id": 1, "account": "test_user_C9_001", ... }
#   }
# }

B.2.2 帶認證的 API 呼叫

bash
# 設定 Token 變數
TOKEN="eyJhbGciOiJIUzI1NiIs..."

# 查詢個人資料
curl -X GET http://localhost:8080/api/auth/profile \
  -H "Authorization: Bearer $TOKEN" \
  -H "site-name: C9" \
  -H "locales: zh-TW"

# 查詢遊戲供應商列表
curl -X GET "http://localhost:8080/api/game/providers?gameType=2" \
  -H "Authorization: Bearer $TOKEN" \
  -H "site-name: C9"

# 查詢站內信
curl -X GET "http://localhost:8080/api/inbox/list?page=1&pageSize=20" \
  -H "Authorization: Bearer $TOKEN" \
  -H "site-name: C9"

B.2.3 後台 Admin API

bash
# 管理員登入
curl -X POST http://localhost:8080/api/admin/login \
  -H "Content-Type: application/json" \
  -d '{
    "account": "root_admin",
    "password": "Root123!@#"
  }'

# 設定 Admin Token
ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIs..."

# 查詢用戶列表(指定站點)
curl -X GET "http://localhost:8080/api/admin/finance/users/list?page=1&pageSize=20" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "x-site-code: C9"

# 查詢用戶列表(全站)
curl -X GET "http://localhost:8080/api/admin/finance/users/list?page=1&pageSize=20" \
  -H "Authorization: Bearer $ADMIN_TOKEN"

# 查詢站點列表
curl -X GET http://localhost:8080/api/site-config/admin/list \
  -H "Authorization: Bearer $ADMIN_TOKEN"

# 查詢報表(帶篩選)
curl -X GET "http://localhost:8080/api/admin/reports/overview?startDate=2026-01-01&endDate=2026-03-01" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "x-site-code: C9"

# 查詢 VIP 等級
curl -X GET "http://localhost:8080/api/vip/admin/levels" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "x-site-code: C9"

B.2.4 多站點測試

bash
# 使用 x-site-code header 切換站點
# C9 站
curl -X GET "http://localhost:8080/api/admin/finance/deposit-review/list?page=1" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "x-site-code: C9"

# A1 站(相同端點,不同站點)
curl -X GET "http://localhost:8080/api/admin/finance/deposit-review/list?page=1" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "x-site-code: A1"

# 使用 siteCode query param(備選方式)
curl -X GET "http://localhost:8080/api/admin/finance/deposit-review/list?page=1&siteCode=C9" \
  -H "Authorization: Bearer $ADMIN_TOKEN"

B.2.5 檔案上傳測試

bash
# R2 檔案上傳
curl -X POST http://localhost:8080/api/admin/r2/upload \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "site-name: C9" \
  -F "file=@/path/to/test-image.png" \
  -F "folder=test"

# 域名素材上傳(logo)
curl -X POST http://localhost:8080/api/site-config/admin/1/domain-asset \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -F "logoSmall=@/path/to/logo-small.png"

B.3 Postman 設定指南

B.3.1 環境變數設定

變數名初始值說明
base_urlhttp://localhost:8080/apiAPI 基礎 URL
user_token(空)前台用戶 JWT Token
admin_token(空)後台管理員 AdminJWT Token
site_codeC9當前測試站點
site_nameC9前台 site-name header
localezh-TW當前測試語系

B.3.2 Pre-request Script(自動認證)

javascript
// 自動登入並設定 Token
const baseUrl = pm.environment.get("base_url");

// 前台用戶自動登入
pm.sendRequest({
    url: baseUrl + "/auth/login",
    method: "POST",
    header: {
        "Content-Type": "application/json",
        "site-name": pm.environment.get("site_name")
    },
    body: {
        mode: "raw",
        raw: JSON.stringify({
            account: "test_user_C9_001",
            password: "Test123!@#",
            fingerprint: "postman-test"
        })
    }
}, function (err, response) {
    if (!err) {
        const result = response.json();
        if (result.code === 200) {
            pm.environment.set("user_token", result.result.token);
        }
    }
});

B.3.3 Collection 結構建議

C9 Platform API Tests/
├── Auth/
│   ├── [POST] Register
│   ├── [POST] Login
│   ├── [GET] Profile
│   └── [POST] Logout
├── Admin Auth/
│   ├── [POST] Admin Login
│   └── [GET] Admin Profile
├── Game/
│   ├── [GET] Providers
│   ├── [POST] Launch
│   └── [GET] Type Configs
├── Finance/
│   ├── [POST] Deposit
│   ├── [GET] Deposit List (Admin)
│   ├── [POST] Deposit Review (Admin)
│   ├── [GET] Withdrawal List (Admin)
│   └── [POST] Withdrawal Review (Admin)
├── VIP/
│   ├── [GET] Levels
│   ├── [GET] Rebates
│   └── [GET] Admin Levels
├── Reports/
│   ├── [GET] Overview
│   ├── [GET] Profit Loss
│   ├── [GET] Bet Records
│   └── [GET] Player Summary
├── Site Config/
│   ├── [GET] Site List
│   ├── [GET] Themes
│   └── [PATCH] Update Site
└── Risk Control/
    ├── [GET] IP Rules
    ├── [POST] Create IP Rule
    └── [GET] Game Blacklist

B.3.4 共用 Header 設定

在 Collection 層級設定共用 Header:

HeaderValue說明
AuthorizationBearer Bearer 依測試對象選擇
Content-Typeapplication/jsonJSON 格式
x-site-code多站點篩選(Admin API)
site-name前台站點名稱
locales多語系

B.4 自動化 API 測試腳本

B.4.1 使用 k6 進行負載測試

javascript
// k6-load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  vus: 50,           // 50 虛擬用戶
  duration: '5m',    // 持續 5 分鐘
  thresholds: {
    http_req_duration: ['p(95)<500'],  // P95 < 500ms
    http_req_failed: ['rate<0.01'],     // 失敗率 < 1%
  },
};

const BASE_URL = 'http://localhost:8080/api';

export function setup() {
  // 登入取得 Token
  const loginRes = http.post(`${BASE_URL}/admin/login`, JSON.stringify({
    account: 'root_admin',
    password: 'Root123!@#',
  }), { headers: { 'Content-Type': 'application/json' } });

  return { token: loginRes.json().result.token };
}

export default function (data) {
  const headers = {
    'Authorization': `Bearer ${data.token}`,
    'x-site-code': 'C9',
  };

  // 測試列表查詢
  const listRes = http.get(
    `${BASE_URL}/admin/finance/users/list?page=1&pageSize=20`,
    { headers }
  );
  check(listRes, {
    'status is 200': (r) => r.status === 200,
    'has items': (r) => r.json().result !== null,
  });

  sleep(1);
}
bash
# 執行 k6 負載測試
k6 run k6-load-test.js

B.5 完整 API 端點測試矩陣

以下矩陣列出所有 205+ 端點的測試狀態追蹤表。QA 可用此表逐一確認每個端點的測試覆蓋。

B.5.1 認證模組 API(17 個端點)

#Method端點認證測試狀態備註
1POST/auth/register[ ]帳號密碼註冊
2POST/auth/login[ ]帳密登入(含指紋)
3POST/auth/google[ ]Google OAuth 登入
4POST/auth/telegram[ ]Telegram OAuth 登入
5GET/auth/profileJWT[ ]取得個人資料
6PATCH/auth/profileJWT[ ]更新個人資料
7POST/auth/change-passwordJWT[ ]修改密碼
8POST/auth/set-passwordJWT[ ]OAuth 用戶設定密碼
9POST/auth/logoutJWT[ ]登出
10POST/auth/upload-avatarJWT[ ]上傳頭像
11POST/auth/enable-2faJWT[ ]啟用 2FA
12POST/auth/verify-2faJWT[ ]驗證 2FA
13POST/auth/disable-2faJWT[ ]停用 2FA
14GET/auth/2fa-statusJWT[ ]查詢 2FA 狀態
15POST/auth/refresh-tokenJWT[ ]刷新 Token
16GET/auth/check-account[ ]檢查帳號是否存在
17GET/auth/check-email[ ]檢查 Email 是否存在

B.5.2 遊戲模組 API(17 個端點)

#Method端點認證測試狀態備註
1GET/game/providersOptional JWT[ ]遊戲供應商列表
2GET/game/providers/:idOptional JWT[ ]供應商詳情
3GET/game/type-configsOptional JWT[ ]遊戲類型配置
4POST/game/launchJWT[ ]啟動遊戲
5POST/game/demo[ ]遊戲試玩
6GET/game/recentJWT[ ]最近遊玩
7POST/game/betsolutions/callbackS2S[ ]BetSolutions 回調
8POST/game/rsg/callbackS2S[ ]RSG 回調
9GET/game/admin/providersAdminJWT[ ]管理供應商列表
10POST/game/admin/providersAdminJWT[ ]新增供應商
11PATCH/game/admin/providers/:idAdminJWT[ ]更新供應商
12DELETE/game/admin/providers/:idAdminJWT[ ]刪除供應商
13GET/game/admin/type-configsAdminJWT[ ]管理類型配置
14POST/game/admin/type-configsAdminJWT[ ]新增類型配置
15PATCH/game/admin/type-configs/:idAdminJWT[ ]更新類型配置
16DELETE/game/admin/type-configs/:idAdminJWT[ ]刪除類型配置
17POST/game/admin/copy-site-dataAdminJWT[ ]跨站複製

B.5.3 金流模組 API(26 個端點)

#Method端點認證測試狀態備註
1POST/depositJWT[ ]存款
2GET/deposit/ordersJWT[ ]存款訂單列表
3GET/deposit/exchange-rateJWT[ ]即時匯率
4POST/vendor/callback/:codeS2S[ ]金流回調
5GET/wallet/bank-cardsJWT[ ]銀行卡列表
6POST/wallet/bank-cardsJWT[ ]新增銀行卡
7DELETE/wallet/bank-cards/:idJWT[ ]刪除銀行卡
8GET/wallet/credit-cardsJWT[ ]信用卡列表
9POST/wallet/credit-cardsJWT[ ]新增信用卡
10DELETE/wallet/credit-cards/:idJWT[ ]刪除信用卡
11GET/wallet/crypto-addressesJWT[ ]加密地址列表
12POST/wallet/crypto-addressesJWT[ ]新增加密地址
13DELETE/wallet/crypto-addresses/:idJWT[ ]刪除加密地址
14POST/withdrawalJWT[ ]提款
15GET/withdrawal/ordersJWT[ ]提款訂單列表
16GET/admin/finance/deposit-review/listAdminJWT[ ]存款審核列表
17POST/admin/finance/deposit-review/:id/reviewAdminJWT[ ]審核存款
18GET/admin/finance/withdrawals/listAdminJWT[ ]提款列表
19POST/admin/finance/withdrawals/:id/reviewAdminJWT[ ]審核提款
20POST/admin/finance/withdrawals/:id/uploadAdminJWT[ ]上傳憑證
21POST/admin/finance/withdrawals/:id/completeAdminJWT[ ]完成提款
22POST/admin/finance/adjust-balanceAdminJWT[ ]手動調帳
23GET/admin/vendor-groups/listAdminJWT[ ]金流群組列表
24POST/admin/vendor-groups/createAdminJWT[ ]新增金流群組
25GET/admin/vendor-channels/listAdminJWT[ ]金流通道列表
26POST/admin/vendor-channels/createAdminJWT[ ]新增金流通道

B.5.4 VIP 模組 API(13 個端點)

#Method端點認證測試狀態備註
1GET/vip/levelsJWT[ ]VIP 等級列表
2GET/vip/my-levelJWT[ ]我的 VIP 等級
3GET/vip/rebatesJWT[ ]反水規則
4GET/vip/admin/levelsAdminJWT[ ]管理 VIP 等級
5POST/vip/admin/levelsAdminJWT[ ]新增 VIP 等級
6PATCH/vip/admin/levels/:idAdminJWT[ ]更新 VIP 等級
7DELETE/vip/admin/levels/:idAdminJWT[ ]刪除 VIP 等級
8GET/vip/admin/rebatesAdminJWT[ ]管理反水規則
9POST/vip/admin/rebates/bulkAdminJWT[ ]批次更新反水
10POST/vip/admin/load-templateAdminJWT[ ]載入模板
11GET/vip/admin/preview-templateAdminJWT[ ]預覽模板
12POST/vip/admin/copy-site-dataAdminJWT[ ]同預設站點
13GET/admin/reports/vip-playersAdminJWT[ ]VIP 玩家列表

B.5.5 代理模組 API(51 個端點)

#Method端點認證測試狀態備註
1POST/affiliate/applyJWT[ ]申請成為代理
2GET/affiliate/dashboardJWT[ ]代理儀表板
3GET/affiliate/downlinesJWT[ ]下線列表
4GET/affiliate/commissionsJWT[ ]佣金明細
5GET/affiliate/settlementsJWT[ ]結算紀錄
6POST/affiliate/withdrawJWT[ ]代理提款
7GET/affiliate/withdrawalsJWT[ ]提款紀錄
8GET/affiliate/referral-codesJWT[ ]推廣碼列表
9POST/affiliate/referral-codesJWT[ ]建立推廣碼
10DELETE/affiliate/referral-codes/:idJWT[ ]刪除推廣碼
11GET/affiliate/alliance-info[ ]聯盟資訊(公開)
12GET/affiliate/tier-info[ ]等級資訊(公開)
13GET/affiliate/vip-milestones[ ]VIP 里程碑(公開)
14GET/affiliate/admin/agentsAdminJWT[ ]代理列表
15POST/affiliate/admin/create-agentAdminJWT[ ]新增代理
16GET/affiliate/admin/settlementsAdminJWT[ ]結算列表
17POST/affiliate/admin/settlements/:id/reviewAdminJWT[ ]審核結算
18GET/affiliate/admin/settlements/:id/risk-logsAdminJWT[ ]風控紀錄
19GET/affiliate/admin/withdrawalsAdminJWT[ ]提款列表
20POST/affiliate/admin/withdrawals/:id/reviewAdminJWT[ ]審核提款
21POST/affiliate/admin/withdrawals/:id/completeAdminJWT[ ]完成提款
22POST/affiliate/admin/bindAdminJWT[ ]手動綁定
23GET/affiliate/admin/bind-logsAdminJWT[ ]綁定紀錄
24GET/affiliate/admin/commission-ratesAdminJWT[ ]佣金費率
25POST/affiliate/admin/commission-ratesAdminJWT[ ]設定費率
26DELETE/affiliate/admin/commission-ratesAdminJWT[ ]刪除費率
27GET/affiliate/admin/vip-milestonesAdminJWT[ ]VIP 里程碑
28POST/affiliate/admin/vip-milestonesAdminJWT[ ]設定里程碑
29DELETE/affiliate/admin/vip-milestonesAdminJWT[ ]刪除里程碑
30GET/affiliate/admin/agent-tiersAdminJWT[ ]代理等級
31POST/affiliate/admin/agent-tiersAdminJWT[ ]設定等級
32DELETE/affiliate/admin/agent-tiersAdminJWT[ ]刪除等級
33GET/affiliate/admin/preview-templateAdminJWT[ ]預覽模板
34POST/affiliate/admin/load-templateAdminJWT[ ]載入模板
35POST/affiliate/admin/set-agent-tierAdminJWT[ ]設定代理等級
36POST/affiliate/admin/trigger-settlementAdminJWT[ ]觸發週結
37POST/affiliate/admin/trigger-daily-settlementAdminJWT[ ]觸發日結

其餘 14 個代理端點(前台代理操作和其他管理端點)依相同格式追蹤。

B.5.6 站點管理 API(12 個端點)

#Method端點認證測試狀態備註
1GET/site-config/admin/listAdminJWT[ ]站點列表
2POST/site-config/adminAdminJWT[ ]新增站點
3PATCH/site-config/admin/:idAdminJWT[ ]更新站點
4DELETE/site-config/admin/:idAdminJWT[ ]刪除站點
5GET/site-config/admin/:id/themesAdminJWT[ ]主題列表
6POST/site-config/admin/:id/themesAdminJWT[ ]新增主題
7PATCH/site-config/admin/themes/:idAdminJWT[ ]更新主題
8DELETE/site-config/admin/themes/:idAdminJWT[ ]刪除主題
9POST/site-config/admin/:id/domain-assetAdminJWT[ ]上傳域名素材
10POST/site-config/admin/:id/customer-service-iconAdminJWT[ ]上傳客服圖示
11PATCH/site-config/admin/:id/mascotsAdminJWT[ ]更新吉祥物
12GET/site-config/admin/:code/customer-serviceAdminJWT[ ]取得客服設定

B.5.7 報表 API(10 個端點)

#Method端點認證測試狀態備註
1GET/admin/reports/playersAdminJWT[ ]玩家報表
2GET/admin/reports/vip-playersAdminJWT[ ]VIP 玩家
3GET/admin/reports/bet-recordsAdminJWT[ ]投注紀錄
4GET/admin/reports/overviewAdminJWT[ ]總覽報表
5GET/admin/reports/profit-lossAdminJWT[ ]損益報表
6GET/admin/reports/gamesAdminJWT[ ]遊戲報表
7GET/admin/reports/promosAdminJWT[ ]活動報表
8GET/admin/reports/player-summaryAdminJWT[ ]玩家摘要
9GET/admin/reports/r2-logsAdminJWT[ ]R2 日誌
10GET/admin/reports/exportAdminJWT[ ]CSV 匯出

B.5.8 後台管理 API(25 個端點)

#Method端點認證測試狀態備註
1POST/admin/login[ ]管理員登入
2POST/admin/registerAdminJWT[ ]新增管理員
3GET/admin/profileAdminJWT[ ]管理員個人資料
4PATCH/admin/profileAdminJWT[ ]更新個人資料
5POST/admin/google-auth/setupAdminJWT[ ]設定 2FA
6POST/admin/google-auth/verifyAdminJWT[ ]驗證 2FA
7POST/admin/google-auth/disableAdminJWT[ ]停用 2FA
8GET/admin/google-auth/statusAdminJWT[ ]2FA 狀態
9GET/admin/permissions/allAdminJWT[ ]所有權限
10GET/admin/listAdminJWT[ ]管理員列表
11GET/admin/:idAdminJWT[ ]管理員詳情
12PATCH/admin/:idAdminJWT[ ]更新管理員
13DELETE/admin/:idAdminJWT[ ]刪除管理員
14PATCH/admin/:id/statusAdminJWT[ ]停用/啟用
15GET/admin/groups/listAdminJWT[ ]群組列表
16POST/admin/groups/createAdminJWT[ ]新增群組
17GET/admin/groups/:idAdminJWT[ ]群組詳情
18PATCH/admin/groups/:idAdminJWT[ ]更新群組
19DELETE/admin/groups/:idAdminJWT[ ]刪除群組
20GET/admin/logs/listAdminJWT[ ]操作紀錄
21GET/admin/finance/users/listAdminJWT[ ]用戶列表
22GET/admin/finance/users/:idAdminJWT[ ]用戶詳情
23PATCH/admin/finance/users/:idAdminJWT[ ]更新用戶
24PUT/admin/users/:userId/vendor-groupAdminJWT[ ]金流群組
25GET/admin/r2/listAdminJWT[ ]R2 列表

B.5.9 風控 API(8 個端點)

#Method端點認證測試狀態備註
1GET/admin/risk/ip-rules/listAdminJWT[ ]IP 規則列表
2POST/admin/risk/ip-rules/createAdminJWT[ ]新增 IP 規則
3PATCH/admin/risk/ip-rules/:idAdminJWT[ ]更新 IP 規則
4DELETE/admin/risk/ip-rules/:idAdminJWT[ ]刪除 IP 規則
5GET/admin/risk/lookupAdminJWT[ ]IP/FP 反查
6GET/admin/risk/login-failuresAdminJWT[ ]登入失敗
7GET/admin/risk/game-blacklistAdminJWT[ ]遊戲黑名單
8POST/admin/risk/game-blacklistAdminJWT[ ]新增黑名單

B.5.10 其他 API

#Method端點認證測試狀態備註
1GET/common/enums[ ]系統枚舉
2GET/common/health[ ]健康檢查
3GET/ranking/listOptional JWT[ ]排行榜
4GET/bet-record/listJWT[ ]用戶投注紀錄
5GET/live-sports/matches[ ]即時賽事
6GET/inbox/listJWT[ ]站內信列表
7PATCH/inbox/:id/readJWT[ ]標記已讀
8DELETE/inbox/:idJWT[ ]刪除信件
9GET/promo/listOptional JWT[ ]活動列表
10GET/promo/:idOptional JWT[ ]活動詳情
11POST/promo/:id/claimJWT[ ]領取活動
12GET/mission/listJWT[ ]任務列表
13POST/mission/:id/claimJWT[ ]領取任務
14GET/site-config/list[ ]站點配置(前台)
15GET/site-config/theme[ ]站點主題(前台)

B.6 API 測試檢查點模板

對每個 API 端點,可使用以下檢查點清單驗證。

B.6.1 通用 API 檢查點

markdown
## API 測試檢查點:[端點名稱]

### 基本驗證
- [ ] HTTP Status Code 正確(200/201/400/401/403/404/500)
- [ ] 回應格式正確:`{ code, message, result, timestamp, path }`
- [ ] timestamp 為有效 ISO 8601 格式
- [ ] path 對應請求路徑

### 認證驗證
- [ ] 無 Token → 401(受保護端點)
- [ ] 無效 Token → 401
- [ ] 過期 Token → 401
- [ ] 前台 Token 存取後台端點 → 401
- [ ] 無權限 → 403

### 參數驗證
- [ ] 必填參數缺失 → 400
- [ ] 參數格式錯誤 → 400
- [ ] 參數超出範圍 → 400
- [ ] SQL 注入字串 → 安全處理
- [ ] XSS 字串 → 安全處理

### 分頁驗證(列表端點)
- [ ] page=1, pageSize=20 → 正確回傳
- [ ] page=0 或負數 → 使用預設值
- [ ] pageSize=0 或超大值 → 限制最大值
- [ ] 空結果 → items=[], total=0
- [ ] total 數值正確

### 多站點驗證
- [ ] x-site-code header → 正確篩選
- [ ] siteCode query param → 正確篩選
- [ ] 無 siteCode → 全站資料或預設行為
- [ ] 跨站存取 → 正確隔離

### 錯誤處理
- [ ] 業務錯誤 → code 非 200,message 有意義
- [ ] 錯誤碼在 ERROR_CODES 中 → 前端可查表
- [ ] 錯誤訊息多語系 → 根據 locales header 變化

B.6.2 寫入端點額外檢查點

markdown
### 資料寫入驗證
- [ ] 新增成功 → 資料庫有對應記錄
- [ ] 更新成功 → 資料庫記錄已更新
- [ ] 刪除成功 → 資料庫記錄已刪除(或軟刪除)
- [ ] siteCode 正確 → Entity 的 siteCode 為預期值
- [ ] createdAt/updatedAt → 時間戳正確

### 並發安全
- [ ] 重複提交 → 不產生重複資料
- [ ] 並發修改 → 使用交易或樂觀鎖
- [ ] 操作紀錄 → admin-operation-log 記錄完整

附錄 C:常見測試陷阱

目標:列出 C9 平台測試中常見的陷阱和注意事項,幫助 QA 避免踩雷。


C.1 i18n 相關陷阱

C.1.1 ICU 格式大括號轉義

問題:next-intl 使用 ICU MessageFormat,大括號 {} 會被解析為變數佔位符。

// 錯誤 — 導致 IntlError: FORMATTING_ERROR
"格式為 {變數名}"

// 正確 — 使用單引號轉義大括號
"格式為 '{'變數名'}'"

測試注意

  • 若頁面出現 IntlError 或空白文字,先檢查 i18n JSON 中是否有未轉義的大括號
  • 新增翻譯後需測試所有 5 個語系檔案(zh-TW, en-US, zh-CN, th-TH, vi-VN)
  • 使用 useTranslations("common") 的 key 最常出問題

C.1.2 語系檔案不同步

問題:新增 i18n key 時只更新部分語系檔案,導致其他語系顯示 key 而非翻譯文字。

檢測方式

bash
# 比較各語系檔案的 key 數量
cd c9-ims/src/messages
wc -l zh-TW.json en-US.json zh-CN.json th-TH.json vi-VN.json

# 找出缺失的 key(需要自訂腳本比對)

建議:每次新增翻譯後,切換到每個語系確認頁面不會出現裸 key。

C.1.3 日期格式多語系

問題:不同語系的日期格式不同(如 zh-TW: 2026/03/01, en-US: 03/01/2026),測試時需注意。

注意:報表中的日期篩選和顯示需在各語系下驗證格式正確。


C.2 金額精度陷阱

C.2.1 USD 截斷規則

核心規則:所有金額使用 Math.floor(value * 1e6) / 1e6 無條件捨去至 6 位小數。

javascript
// 正確
truncateUsd(1.2345679) // → 1.234567(捨去第 7 位)

// 常見錯誤:使用 Math.round(四捨五入)
Math.round(1.2345679 * 1e6) / 1e6 // → 1.234568(錯誤!應為 1.234567)

// 常見錯誤:使用 toFixed(四捨五入 + 字串轉換)
(1.2345679).toFixed(6) // → "1.234568"(錯誤!)

測試注意

  • 存款匯率轉換後的 USD 金額必須使用截斷(非四捨五入)
  • VIP 反水計算結果必須截斷
  • 代理佣金計算結果必須截斷
  • JavaScript 浮點數精度問題:0.1 + 0.2 !== 0.3,需特別注意

C.2.2 各欄位精度對照

用途型別精度常見錯誤
金額decimal(18,6)6 位小數使用 Math.round 而非 Math.floor
匯率decimal(18,10)10 位小數儲存時精度丟失
百分比decimal(5,2)2 位小數返水百分比超過 99.99%
倍率decimal(10,2)2 位小數打碼倍率計算錯誤

C.2.3 金額比較

問題:浮點數比較可能因精度問題失敗。

javascript
// 錯誤
if (balance === 100.00) { ... }

// 正確(比較截斷後的值)
if (Math.abs(balance - 100.00) < 1e-6) { ... }

C.3 時區陷阱

C.3.1 系統時區 UTC+8

核心設定:MySQL TZ 設定為 +08:00,所有 Cron 排程基於伺服器時間。

排程觸發時間(UTC+8)注意事項
每日反水結算00:05計算前一日 00:00~23:59 的投注
月度保級每月 1 號 01:00計算上月整月的投注
代理週結每週一 03:00計算上週一至週日的佣金
代理日結每日 03:30計算前一日的佣金
賽事更新每 30 分鐘API-Football 資料快取

測試注意

  • 測試 Cron 排程時,確認伺服器時區為 UTC+8
  • 日期範圍篩選的開始和結束時間需考慮時區
  • createdAt 欄位在 MySQL 中儲存為 UTC+8 時間

C.3.2 前端日期處理

問題:前端的 new Date() 使用瀏覽器本地時區,可能與伺服器 UTC+8 不一致。

測試建議

  • 在不同時區的瀏覽器中測試日期篩選功能
  • 確認報表中的日期顯示與後端一致
  • applyDateRange() 使用的是 MySQL BETWEEN,確認邊界條件

C.4 快取陷阱

C.4.1 Redis 快取導致資料延遲

問題:Redis 快取有 TTL,修改資料後可能需要等待快取過期才能看到最新資料。

快取TTL影響
tokenVersion60s修改用戶後最多 60 秒舊 Token 仍有效
群組權限60s修改權限後最多 60 秒舊權限仍生效
VIP 等級3600s修改 VIP 後最多 1 小時前台顯示舊資料
VIP 返水3600s修改返水規則後最多 1 小時反水仍用舊規則

測試建議

  • 若測試資料不一致,先清除 Redis 快取再驗證
  • 測試快取失效場景時,注意等待 TTL 過期
  • 使用 redis-cli KEYS "cache:*" 檢查快取狀態

C.4.2 TanStack Query 快取(前端)

問題:TanStack Query 的 staleTime 預設 5 分鐘,5 分鐘內不會重新發送 API 請求。

影響場景

  • 在後台修改資料後,前台 5 分鐘內可能顯示舊資料
  • 切換頁面後返回,若快取未過期則使用快取資料
  • SiteSelector 切換時會清除快取,但手動操作可能不會

測試建議

  • 測試資料一致性時,使用強制 refetch(重新整理頁面或切換站點)
  • 驗證 queryClient.invalidateQueries() 是否在適當時機被呼叫

C.5 多站點陷阱

C.5.1 x-site-code Header vs siteCode Query Param

優先順序@AdminSiteCode() 裝飾器先讀 header,再讀 query param

場景HeaderQuery Param結果
Header 選單站x-site-code: C9-siteCode = "C9"
全站 + Tab-siteCode=A1siteCode = "A1"
兩者都有x-site-code: C9siteCode=A1siteCode = "C9"(header 優先)
兩者都無--siteCode = null(全站)

常見陷阱

  • apiClient interceptor 自動注入 x-site-code,若已在 query param 傳入不同站點,header 會覆蓋
  • getSiteConfigs API 必須跳過 siteCode 篩選,否則只能看到當前站

C.5.2 SiteCodeSubscriber 自動填入

問題SiteCodeSubscriber 在 Entity insert 時自動從環境變數 SITE_CODE 填入 siteCode。

測試注意

  • SITE_CODE 未設定,siteCode 可能為空或 undefined
  • 後台 Admin API 不依賴 SITE_CODE 環境變數,而是透過 @AdminSiteCode() 取得
  • Seed 腳本手動設定 siteCode,不依賴 Subscriber

C.5.3 AdminContentWrapper remount

問題AdminContentWrapperkey={selectedSiteCode ?? "__all__"} 會在站點切換時強制 remount 所有子元件。

測試注意

  • 切換站點會導致所有表單狀態丟失(未儲存的資料會消失)
  • 切換站點會觸發所有子頁面的 useEffect 重新執行
  • 若有長時間操作(如編輯活動),切換站點會中斷

C.6 NextAuth Session 陷阱

C.6.1 Token 快取在 apiClient

問題:apiClient 從 SessionSync 快取取得 JWT Token,若 session 過期但快取未清除,會導致 401 錯誤。

401 重試流程

  1. API 返回 401
  2. apiClient interceptor 清除舊 token
  3. 重取 session(NextAuth getSession)
  4. 使用新 token retry 原始請求
  5. 若 retry 仍失敗,導向登入頁

測試注意

  • 測試 401 重試機制時,確認不會無限重試
  • 確認 session 過期後重新登入流程順暢
  • 確認 SessionSync 在登出時正確清除

C.6.2 Credentials Provider 限制

問題:NextAuth 5 beta 的 Credentials Provider 不會自動刷新 token。

影響:管理員長時間不操作後可能需要重新登入。


C.7 其他常見陷阱

C.7.1 TypeORM Relation 載入

問題:TypeORM 預設不載入 relation,需要明確使用 relations: ['xxx']leftJoinAndSelect

測試影響:若 API 回傳的物件缺少關聯資料(如用戶缺少 VIP 資訊),可能是 relation 未正確載入。

C.7.2 MySQL CAST 搜尋

問題:JSON 欄位的模糊搜尋使用 CAST(column AS CHAR) LIKE :keyword,效能較差且無法使用索引。

測試注意:在大量資料下搜尋 JSON 欄位可能明顯變慢。

C.7.3 R2 路徑命名

問題:R2 檔案路徑使用站點名稱作為 prefix,不同站點的檔案在不同目錄下。

測試注意

  • 上傳檔案的 @SiteName() header 決定儲存路徑
  • 跨站存取 R2 檔案可能因路徑不同而失敗

C.7.4 前端路由必須使用 @/i18n/navigation

問題:使用 next/navigationuseRouterLink 等會丟失 locale 前綴。

tsx
// 錯誤 — 會丟失 locale
import { useRouter } from "next/navigation";

// 正確
import { useRouter } from "@/i18n/navigation";

測試注意:若頁面跳轉後語系突然變成預設語系,可能是使用了錯誤的 import。

C.7.5 Zod v4 驗證

問題:前後端都使用 Zod 進行驗證,但版本可能不一致,schema 定義可能有差異。

測試注意

  • 前端 Zod 驗證通過不代表後端也會通過
  • 後端 class-validator 可能有額外的驗證規則
  • 測試邊界值(空字串、null、undefined、超長字串等)

附錄 D:自動化測試擴展建議

目標:提供 C9 平台自動化測試的擴展方向和實施建議。


D.1 前台 (c9-ec) Vitest 擴展計劃

D.1.1 現況

  • 測試框架:Vitest
  • 測試類型:單元測試 + 元件測試
  • 執行方式:yarn test(全部)、yarn test:unit(單元)、yarn test:nuxt(元件)

D.1.2 擴展目標

測試層級當前覆蓋率目標覆蓋率說明
Composables30%80%45 個 composable 的邏輯測試
Components20%60%77 個元件的渲染和交互測試
Pages10%50%20 個頁面的整合測試
Utils50%90%工具函式的單元測試

D.1.3 優先測試目標

優先級目標原因
P1useConfig.ts多站點域名配置核心
P1金額計算相關 composables精度問題影響資金安全
P1認證相關 composables安全性核心
P2遊戲大廳元件核心用戶體驗
P2存款/提款流程金流核心功能
P3VIP 顯示元件等級和反水顯示
P3多語系切換i18n 正確性

D.1.4 測試範例

typescript
// composables/__tests__/useConfig.test.ts
import { describe, it, expect, vi } from 'vitest';
import { useConfig } from '../useConfig';

describe('useConfig', () => {
  it('should return correct site config for C9 domain', () => {
    vi.stubGlobal('location', { hostname: 'c9.example.com' });
    const config = useConfig();
    expect(config.siteCode).toBe('C9');
    expect(config.siteName).toBe('C9');
  });

  it('should inject site-name header', () => {
    // 驗證 HTTP 請求帶有 site-name header
  });
});

D.2 後端 (c9-be) Jest 擴展計劃

D.2.1 現況

  • 測試框架:Jest
  • 測試類型:單元測試 + E2E 測試
  • 執行方式:yarn test(單元)、yarn test:e2e(E2E)

D.2.2 擴展目標

測試層級當前覆蓋率目標覆蓋率說明
Service 層20%70%核心業務邏輯
Controller 層10%50%API 端點整合測試
Guard/Decorator30%80%認證和權限
Utils50%90%工具函式
Cron 排程0%60%排程邏輯

D.2.3 優先測試目標

優先級模組測試重點
P1auth註冊/登入/JWT/tokenVersion
P1adminRBAC 權限驗證
P1deposit存款流程/匯率轉換/金額計算
P1vipVIP 等級計算/反水結算
P2affiliate佣金計算/結算流程/風控
P2game遊戲回調/餘額更新
P2withdrawal提款流程/審核
P3promo活動條件/領取
P3mission任務進度/完成

D.2.4 測試範例

typescript
// modules/vip/__tests__/vip.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { VipService } from '../vip.service';
import { getRepositoryToken } from '@nestjs/typeorm';
import { VipLevel } from '../entities/vip-level.entity';

describe('VipService', () => {
  let service: VipService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        VipService,
        {
          provide: getRepositoryToken(VipLevel),
          useValue: {
            find: jest.fn().mockResolvedValue([
              { level: 0, requiredBet: 0, siteCode: 'C9' },
              { level: 1, requiredBet: 1000, siteCode: 'C9' },
            ]),
          },
        },
      ],
    }).compile();

    service = module.get<VipService>(VipService);
  });

  it('should calculate VIP level based on total bet', async () => {
    const level = await service.calculateLevel(500, 'C9');
    expect(level).toBe(0);
  });

  it('should upgrade to level 1 when bet reaches threshold', async () => {
    const level = await service.calculateLevel(1000, 'C9');
    expect(level).toBe(1);
  });

  it('should never downgrade VIP level', async () => {
    // VIP 等級只升不降的測試
  });
});

D.3 Playwright E2E 測試計劃

D.3.1 現況

  • 前台 (c9-ec) 已設定 Playwright
  • 執行方式:yarn test:e2e

D.3.2 E2E 測試情境

優先級情境步驟概述
P1完整存款流程登入 → 選擇存款方式 → 輸入金額 → 提交 → 驗證餘額
P1完整提款流程登入 → 新增銀行卡 → 申請提款 → 驗證訂單
P1遊戲啟動流程登入 → 進入遊戲大廳 → 選擇遊戲 → 啟動
P2後台管理員操作登入 → 審核存款 → 審核提款 → 查看報表
P2多站點切換登入 → 切換站點 → 驗證資料隔離
P2VIP 升級流程投注 → VIP 等級檢查 → 反水結算
P3代理推廣流程申請代理 → 建立推廣碼 → 下線註冊 → 佣金結算
P3多語系切換切換 5 種語系 → 驗證所有頁面文字

D.3.3 Playwright 設定範例

typescript
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests/e2e',
  timeout: 30000,
  fullyParallel: true,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: 'html',
  use: {
    baseURL: 'http://localhost:3010',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } },
    { name: 'Mobile Safari', use: { ...devices['iPhone 13'] } },
  ],
  webServer: [
    { command: 'yarn dev:ec', port: 3010, reuseExistingServer: true },
    { command: 'yarn dev:be', port: 8080, reuseExistingServer: true },
  ],
});

D.3.4 E2E 測試範例

typescript
// tests/e2e/deposit.spec.ts
import { test, expect } from '@playwright/test';

test.describe('Deposit Flow', () => {
  test.beforeEach(async ({ page }) => {
    // 登入
    await page.goto('/login');
    await page.fill('[name="account"]', 'test_user_C9_001');
    await page.fill('[name="password"]', 'Test123!@#');
    await page.click('button[type="submit"]');
    await page.waitForURL('/');
  });

  test('should complete ATM deposit', async ({ page }) => {
    await page.goto('/deposit');
    await page.click('text=ATM');
    await page.fill('[name="amount"]', '1000');
    await page.click('button:has-text("確認存款")');
    // 驗證訂單建立
    await expect(page.locator('.deposit-success')).toBeVisible();
  });
});

D.4 CI/CD 整合建議

D.4.1 GitHub Actions Workflow

yaml
# .github/workflows/test.yml
name: CI Test

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

jobs:
  test-backend:
    runs-on: ubuntu-latest
    services:
      mysql:
        image: mysql:8.0
        env:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: c9_test
        ports: ['3306:3306']
      redis:
        image: redis:7
        ports: ['6379:6379']
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install dependencies
        run: cd c9-be && yarn install --frozen-lockfile
      - name: Run unit tests
        run: cd c9-be && yarn test --coverage
      - name: Run E2E tests
        run: cd c9-be && yarn test:e2e

  test-frontend-ec:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install dependencies
        run: cd c9-ec && yarn install --frozen-lockfile
      - name: Run tests
        run: cd c9-ec && yarn test
      - name: Type check
        run: cd c9-ec && yarn typecheck

  test-frontend-ims:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install dependencies
        run: cd c9-ims && pnpm install --frozen-lockfile
      - name: Type check
        run: cd c9-ims && yarn typecheck
      - name: Lint
        run: cd c9-ims && yarn lint

D.4.2 測試覆蓋率目標

專案當前估計短期目標(3 個月)中期目標(6 個月)長期目標(1 年)
c9-be~15%40%60%75%
c9-ec~10%30%50%65%
c9-ims~5%20%40%55%

D.4.3 覆蓋率報告整合

bash
# c9-be: Jest 覆蓋率報告
cd c9-be && yarn test --coverage --coverageReporters=lcov

# c9-ec: Vitest 覆蓋率報告
cd c9-ec && yarn test --coverage

# 使用 Codecov 或 Coveralls 追蹤覆蓋率趨勢

D.4.4 自動化測試最佳實踐

實踐說明
測試金字塔大量單元測試 > 適量整合測試 > 少量 E2E 測試
測試獨立性每個測試案例獨立執行,不依賴其他測試的結果或狀態
測試資料隔離使用 beforeEach 設定/afterEach 清除測試資料
避免 sleep使用 waitFor / waitForSelector 而非固定等待時間
Mock 外部服務Mock 金流商 API、遊戲商 API、匯率 API
持續執行每次 PR 自動觸發測試,merge 前必須通過
平行執行使用 Vitest/Jest 的平行執行功能加速
Snapshot 測試對穩定的 UI 元件使用 snapshot 防止意外變更
錯誤截圖E2E 測試失敗時自動截圖,方便除錯

附錄 E:邊界值與異常情境測試

目標:針對系統各模組的邊界條件和異常情境設計測試案例,確保系統在極端情況下仍能正確運作。


E.1 金額邊界值測試

E.1.1 金額精度邊界

TC-ID測試說明輸入值預期結果優先級
TC-EDGE-AMT-001最小正金額0.000001 USD系統接受並正確處理P2
TC-EDGE-AMT-002零金額存款0.000000 USD系統拒絕(最小存款限制)P1
TC-EDGE-AMT-003負數金額-100.000000 USD系統拒絕(Zod/class-validator 驗證)P1
TC-EDGE-AMT-004超大金額999999999999.999999 USD不超過 decimal(18,6) 範圍P2
TC-EDGE-AMT-005截斷精度驗證100.1234567 USD截斷為 100.123456(非四捨五入)P1
TC-EDGE-AMT-006浮點精度問題0.1 + 0.2結果為 0.300000(非 0.30000000000000004)P1
TC-EDGE-AMT-007匯率精度邊界匯率 0.0000000001decimal(18,10) 正確儲存P2
TC-EDGE-AMT-008百分比上限99.99% 反水率decimal(5,2) 正確處理P2
TC-EDGE-AMT-009百分比零值0.00% 反水率反水為 0,不發放P2
TC-EDGE-AMT-010餘額為零時提款餘額 0.000000提款被拒絕,友善提示P1

E.1.2 匯率邊界

TC-ID測試說明情境預期結果優先級
TC-EDGE-RATE-001匯率 API 不可用台銀匯率 API 回應失敗使用快取匯率或拒絕存款(不可用預設匯率)P1
TC-EDGE-RATE-002匯率為零API 回傳匯率 0系統拒絕計算(除以零防護)P1
TC-EDGE-RATE-003匯率異常高API 回傳匯率 99999金額計算結果極小但正確P2
TC-EDGE-RATE-004匯率異常低API 回傳匯率 0.001金額計算結果極大,可能觸發上限P2
TC-EDGE-RATE-005匯率快取過期快取 TTL 3600s 過期重新取得最新匯率P2

E.2 字串邊界值測試

E.2.1 帳號和密碼

TC-ID測試說明輸入值預期結果優先級
TC-EDGE-STR-001空帳號""驗證失敗,提示必填P1
TC-EDGE-STR-002超長帳號(255 字元)"a" * 255超過限制長度時拒絕P2
TC-EDGE-STR-003帳號含特殊字元"user@#$%^"依系統規則接受或拒絕P2
TC-EDGE-STR-004帳號含空格"user name"拒絕或自動去空格P2
TC-EDGE-STR-005帳號含 Unicode"用戶名稱"依系統規則接受或拒絕P3
TC-EDGE-STR-006空密碼""驗證失敗,提示必填P1
TC-EDGE-STR-007超長密碼(1000 字元)"a" * 1000bcrypt 有 72 bytes 限制P3
TC-EDGE-STR-008密碼含 Unicode"密碼Abc123!@#"系統正確處理 Unicode 密碼P3
TC-EDGE-STR-009帳號前後空格" admin "自動 trim 或拒絕P2
TC-EDGE-STR-010Email 超長"a" * 250 + "@test.com"超過限制時拒絕P3

E.2.2 搜尋和篩選

TC-ID測試說明輸入值預期結果優先級
TC-EDGE-SEARCH-001空搜尋""回傳所有資料(忽略空搜尋)P2
TC-EDGE-SEARCH-002超長搜尋字串"a" * 1000不崩潰,正確處理P3
TC-EDGE-SEARCH-003SQL 特殊字元搜尋"%_'"正確轉義,安全搜尋P1
TC-EDGE-SEARCH-004只有空格的搜尋" "視為空搜尋或 trim 後處理P3
TC-EDGE-SEARCH-005Emoji 搜尋"🎮"正確處理 UTF-8 4 bytes 字元P3
TC-EDGE-SEARCH-006HTML 標籤搜尋""正常拒絕或轉義

L.2.2 POST /api/auth/login

請求格式

json
{
  "account": "string",
  "password": "string",
  "fingerprint": "string (選填)"
}

成功回應 result

json
{
  "token": "JWT string",
  "user": {
    "id": "number",
    "account": "string",
    "email": "string|null",
    "vipLevel": "number",
    "balance": "string (decimal)"
  }
}
驗證項目輸入預期結果
正常登入正確帳密code: 200, result.token 存在
密碼錯誤錯誤密碼業務錯誤碼
帳號不存在不存在帳號業務錯誤碼(同密碼錯誤,不洩漏帳號存在性)
帳號停用status='disabled'業務錯誤碼
Token 格式解碼 JWT含 userId, account, siteCode, tokenVersion
Token 過期設 exp7 天後過期

L.2.3 POST /api/auth/google-login

請求格式

json
{
  "idToken": "string (Google OAuth ID Token)",
  "fingerprint": "string (選填)"
}
驗證項目預期結果
有效 idToken(首次)自動建立用戶 + 回傳 token
有效 idToken(已綁定)直接登入回傳 token
無效 idToken業務錯誤碼
過期 idToken業務錯誤碼

L.2.4 POST /api/auth/avatar

請求格式:multipart/form-data,file 欄位

驗證項目預期結果
上傳 JPG < 2MBcode: 200, result 含 avatarUrl
上傳 PNG < 2MBcode: 200
上傳 > 5MB400 檔案過大
上傳非圖片400 格式不支援
未登入上傳401

L.3 存提款模組 API Contract

L.3.1 POST /api/deposit

請求格式

json
{
  "amount": "number (> 0)",
  "currency": "string (TWD/USDT)",
  "paymentMethod": "string (atm/credit/crypto)",
  "vendorChannelId": "number (選填)"
}

成功回應 result

json
{
  "orderId": "number",
  "orderNo": "string",
  "amount": "string (decimal)",
  "amountUsd": "string (decimal)",
  "exchangeRate": "string (decimal)",
  "paymentUrl": "string (金流商跳轉 URL)"
}
驗證項目輸入預期結果
正常存款合法金額code: 200, 含 orderNo
金額為 0amount: 0400 驗證錯誤
金額為負amount: -100400 驗證錯誤
金額超限amount: 99999999業務錯誤碼
未知支付方式paymentMethod: "xxx"400 驗證錯誤
未登入無 Token401
匯率精度驗證 exchangeRatedecimal(18,10)
USD 截斷驗證 amountUsdMath.floor 無條件捨去

L.3.2 GET /api/deposit/exchange-rate

成功回應 result

json
{
  "currency": "TWD",
  "rate": "32.1500000000",
  "updatedAt": "2026-03-02T12:00:00.000Z"
}
驗證項目預期結果
匯率格式decimal(18,10) 字串
更新時間ISO 8601
快取有效期同一分鐘內相同

L.3.3 POST /api/withdrawal

請求格式

json
{
  "amount": "number (> 0, USD)",
  "method": "string (bank/crypto)",
  "walletId": "number (bank-card 或 crypto-address 的 ID)",
  "twoFaCode": "string (選填,6位數字)"
}
驗證項目輸入預期結果
正常提領餘額足夠code: 200, 含 orderNo
餘額不足amount > balance業務錯誤碼
錢包未審核walletId 狀態非 approved業務錯誤碼
錢包不存在walletId: 99999業務錯誤碼
金額精度超過 6 位小數截斷至 6 位

L.4 遊戲模組 API Contract

L.4.1 GET /api/game/providers

Query 參數gameType (選填), siteCode (由 header 帶入)

成功回應 result

json
[
  {
    "id": "number",
    "providerCode": "string",
    "name": { "zh-TW": "string", "en-US": "string" },
    "icon": "string|null",
    "enabled": "boolean",
    "sortOrder": "number",
    "gameType": "number"
  }
]
驗證項目預期結果
name 多語系至少含 zh-TW 和 en-US
gameType 篩選回傳僅含指定 gameType
enabled 篩選前台 API 只回啟用的
排序按 sortOrder ASC

L.4.2 POST /api/game/launch

請求格式

json
{
  "providerCode": "string",
  "gameId": "string",
  "demo": "boolean (選填,預設 false)"
}

成功回應 result

json
{
  "launchUrl": "string (遊戲啟動 URL)",
  "token": "string (遊戲 session token)"
}
驗證項目輸入預期結果
正常啟動合法 provider + gameIdcode: 200, 含 launchUrl
遊戲不存在gameId: "invalid"業務錯誤碼
供應商不存在providerCode: "xxx"業務錯誤碼
遊戲黑名單用戶被封鎖code: 5010
試玩模式demo: true,未登入code: 200(不需 token)
試玩模式demo: true,已登入code: 200

L.4.3 S2S Callback — BetSolutions

請求格式(由遊戲商發送)

json
{
  "Token": "string",
  "TransactionId": "string",
  "RoundId": "string",
  "Amount": "number",
  "Type": "string (Bet/Win/Refund/Rollback)",
  "Signature": "string (HMAC)"
}
驗證項目預期結果
簽名正確正常處理交易
簽名錯誤拒絕,回 error code
重複 TransactionId冪等處理,不重複扣款
餘額不足(Bet)回傳 InsufficientBalance
Token 無效回傳 InvalidToken

L.4.4 S2S Callback — RSG

請求格式(DES 加密)

加密的 JSON body,需 DES 解密
驗證項目預期結果
DES 解密成功正常處理交易
解密失敗拒絕,回 error
交易類型:下注扣除餘額
交易類型:派彩增加餘額
交易類型:退款退回餘額

L.5 VIP 模組 API Contract

L.5.1 GET /api/vip/levels

成功回應 result

json
[
  {
    "id": "number",
    "level": "number",
    "name": { "zh-TW": "string", "en-US": "string" },
    "requiredBetAmount": "string (decimal)",
    "retentionBetAmount": "string (decimal)",
    "upgradeBonus": "string (decimal)",
    "monthlyBonus": "string (decimal)",
    "retentionLocked": "boolean"
  }
]
驗證項目預期結果
排序按 level ASC
金額格式decimal(18,6) 字串
等級連續0, 1, 2, ... 無跳號
siteCode 篩選僅回當前站的等級
name 多語系至少含 5 種語系

L.5.2 Admin VIP API

POST /api/vip/admin/copy-site-data

json
{
  "sourceSiteCode": "string",
  "targetSiteCode": "string",
  "type": "string (levels/rebates)"
}
驗證項目輸入預期結果
複製等級type: "levels"目標站等級與來源站一致
複製返水type: "rebates"目標站返水與來源站一致
來源站不存在sourceSiteCode: "XXX"業務錯誤碼
目標站=來源站same siteCode業務錯誤碼或忽略
Transaction 原子性複製中途失敗全部 rollback

L.6 代理模組 API Contract

L.6.1 GET /api/affiliate/dashboard

成功回應 result

json
{
  "totalDownlines": "number",
  "activeDownlines": "number",
  "totalCommission": "string (decimal)",
  "pendingCommission": "string (decimal)",
  "balance": "string (decimal)",
  "frozenBalance": "string (decimal)",
  "agentTier": "string",
  "referralCodes": ["string"]
}
驗證項目預期結果
金額格式全部 decimal(18,6)
下線數量>= 0
代理等級bronze/silver/gold/platinum 之一
推廣碼數量<= 10

L.6.2 POST /api/affiliate/referral-codes

請求格式

json
{
  "code": "string (英數字,唯一)"
}
驗證項目輸入預期結果
建立推廣碼合法 codecode: 200
重複代碼已存在的 code業務錯誤碼
超過上限已有 10 個業務錯誤碼
空代碼code: ""400 驗證錯誤
特殊字元code: "ab!@#"400 驗證錯誤

L.6.3 Admin 代理 API

POST /api/affiliate/admin/settlements/:id/review

json
{
  "action": "string (approve/reject)",
  "reason": "string (選填,reject 時必填)"
}
驗證項目輸入預期結果
核准結算action: "approve"狀態變 approved
拒絕結算action: "reject", reason: "..."狀態變 rejected
拒絕無理由action: "reject", 無 reason400
重複審核已 approved 的再次審核業務錯誤碼
結算不存在:id = 99999404 或業務錯誤

L.7 站點配置模組 API Contract

L.7.1 GET /api/site-config/admin/list

成功回應 result

json
[
  {
    "id": "number",
    "siteCode": "string",
    "name": "string",
    "domains": ["string"],
    "supportedLocales": ["string"],
    "defaultLocale": "string",
    "features": { "key": "boolean" },
    "activeThemeId": "number|null",
    "themes": [
      {
        "id": "number",
        "name": "string",
        "colors": { "primary": "string", "accent": "string" },
        "mode": "string"
      }
    ]
  }
]
驗證項目預期結果
回傳所有站點不受 x-site-code 影響
含主題列表themes 為陣列
domains 格式合法域名陣列
supportedLocales在 5 種語系範圍內

L.7.2 POST /api/site-config/admin

請求格式

json
{
  "siteCode": "string (唯一)",
  "name": "string",
  "domains": ["string"],
  "supportedLocales": ["zh-TW", "en-US"],
  "defaultLocale": "zh-TW",
  "features": {}
}
驗證項目輸入預期結果
正常建立合法資料code: 200, 回傳新站點
siteCode 重複已存在的 code業務錯誤碼
空 siteCodesiteCode: ""400
無效語系supportedLocales: ["xx-YY"]400 或業務錯誤

L.7.3 PATCH /api/site-config/admin/:id

驗證項目輸入預期結果
更新名稱成功更新
更新 features{ features: {...} }成功更新
更新不存在:id = 99999404 或業務錯誤
部分更新只傳 name其他欄位不變

L.7.4 主題 CRUD API

POST /api/site-config/admin/:siteConfigId/themes

json
{
  "name": "string",
  "colors": {
    "primary": "string (OKLCH)",
    "accent": "string (OKLCH)",
    "surface": "string (OKLCH)",
    "text": "string (OKLCH)",
    "border": "string (OKLCH)"
  },
  "mode": "string (light/dark)"
}
驗證項目輸入預期結果
建立主題合法色彩code: 200
站點不存在:siteConfigId = 99999404
缺少色彩colors 缺 primary400
刪除啟用中主題activeThemeId 指向此主題成功刪除,activeThemeId 清空

L.8 後台管理模組 API Contract

L.8.1 POST /api/admin/login

請求格式

json
{
  "account": "string",
  "password": "string",
  "twoFaCode": "string (選填,啟用 2FA 時必填)"
}
驗證項目輸入預期結果
正常登入正確帳密code: 200, 含 AdminJWT
密碼錯誤錯誤密碼業務錯誤碼
需要 2FA已啟用但未傳 code業務錯誤碼(需 2FA)
2FA 碼錯誤錯誤的 6 位碼業務錯誤碼
2FA 碼過期超過 30 秒的 TOTP業務錯誤碼
JWT payload解碼 token含 adminId, account, role:'admin', groupType

L.8.2 權限驗證端點

端點所需權限無權限回應
GET /admin/listadmin:read403
POST /admin/registeradmin:write403
GET /admin/finance/deposit-review/listdeposit:read403
POST /admin/finance/deposit-review/:id/reviewdeposit:write403
GET /admin/reports/playersreport:read403
POST /admin/risk/ip-rulesrisk:write403
GET /admin/groups/listadmin-group:read403
POST /admin/promospromo:write403
GET /admin/finance/users/listuser:read403
DELETE /admin/vendor-channels/:idvendor:write403

L.8.3 分頁回應格式

所有列表 API 應回傳統一分頁格式:

json
{
  "items": [],
  "pagination": {
    "page": "number",
    "pageSize": "number",
    "total": "number",
    "totalPages": "number"
  }
}

或簡化格式:

json
{
  "items": [],
  "total": "number"
}
驗證項目輸入預期結果
第一頁page=1, pageSize=20items.length <= 20
超出頁碼page=9999items = [], total 不變
pageSize 上限pageSize=1000限制為最大值(通常 100)
pageSize=0pageSize=0400 或使用預設值
不傳 page省略 page預設 page=1

L.9 風控模組 API Contract

L.9.1 POST /api/admin/risk/ip-rules

請求格式

json
{
  "ip": "string (IPv4/IPv6)",
  "type": "string (blacklist/whitelist)",
  "reason": "string (選填)",
  "expiresAt": "string (ISO 8601, 選填)",
  "siteCode": "string (選填)"
}
驗證項目輸入預期結果
新增黑名單合法 IPcode: 200
新增白名單type: "whitelist"code: 200
無效 IPip: "999.999.999.999"400
IPv6ip: "::1"code: 200
到期時間過去時間400 或業務錯誤
重複 IP同站同 IP 同類型業務錯誤碼

L.9.2 GET /api/admin/risk/lookup

Query 參數keyword (IP/指紋/帳號/姓名/Email/手機), siteCode (選填)

驗證項目輸入預期結果
IP 查詢keyword: "192.168.1.1"回傳相關用戶列表
指紋查詢keyword: fingerprint hash回傳相關用戶列表
帳號查詢keyword: "testuser"回傳相關登入紀錄
空關鍵字keyword: ""400 或回傳空

L.10 報表模組 API Contract

L.10.1 GET /api/admin/reports/overview

Query 參數startDate, endDate, siteCode (選填)

成功回應 result

json
{
  "summary": {
    "totalDeposit": "string (decimal)",
    "totalWithdrawal": "string (decimal)",
    "totalBet": "string (decimal)",
    "totalWin": "string (decimal)",
    "netProfit": "string (decimal)",
    "newUsers": "number",
    "activeUsers": "number"
  },
  "daily": [
    {
      "date": "string (YYYY-MM-DD)",
      "deposit": "string",
      "withdrawal": "string",
      "bet": "string",
      "win": "string",
      "newUsers": "number"
    }
  ]
}
驗證項目預期結果
金額格式全部 decimal(18,6) 字串
日期排序daily 按日期 ASC
siteCode 篩選僅含指定站點資料
日期範圍僅含範圍內日期
netProfit 計算totalBet - totalWin(或含其他)

L.10.2 GET /api/admin/reports/bet-records

Query 參數

  • page, pageSize
  • keyword (帳號/注單號)
  • gameType (1-10)
  • providerCode
  • status (pending/settled/cancelled)
  • startDate, endDate
  • siteCode
驗證項目預期結果
分頁含 items + pagination
遊戲類型篩選僅含指定 gameType
狀態篩選僅含指定 status
日期範圍createdAt 在範圍內
關鍵字搜尋帳號或注單號模糊匹配
金額欄位betAmount, winAmount 為 decimal 字串

L.10.3 GET /api/admin/reports/export

Query 參數type (players/bet-records/overview/profit-loss/games/player-summary), 加上各報表的篩選參數

驗證項目預期結果
Content-Typetext/csv 或 application/octet-stream
檔案名稱Content-Disposition 含有意義的檔名
CSV 格式標題行 + 資料行,UTF-8 BOM
大量資料不因資料量大而 timeout
空資料僅有標題行

附錄 M:行動裝置與響應式測試

驗證前台 (c9-ec) 和後台 (c9-ims) 在不同裝置與視窗尺寸下的顯示與互動

M.1 測試裝置矩陣

M.1.1 手機裝置

裝置螢幕尺寸解析度DPROS優先級
iPhone 15 Pro6.1"393×8523xiOS 17P1
iPhone 15 Pro Max6.7"430×9323xiOS 17P2
iPhone SE (3rd)4.7"375×6672xiOS 16P2
Samsung Galaxy S246.2"360×7803xAndroid 14P1
Samsung Galaxy S24 Ultra6.8"412×9153.5xAndroid 14P2
Google Pixel 86.2"412×9152.625xAndroid 14P2
Samsung Galaxy A546.4"360×8002xAndroid 13P3
Xiaomi 146.36"360×8003xAndroid 14P3

M.1.2 平板裝置

裝置螢幕尺寸解析度DPROS優先級
iPad Pro 12.9"12.9"1024×13662xiPadOS 17P1
iPad Air (5th)10.9"820×11802xiPadOS 17P2
iPad mini (6th)8.3"744×11332xiPadOS 17P3
Samsung Galaxy Tab S911"800×12801.5xAndroid 14P3

M.1.3 桌面斷點

斷點名稱寬度範圍典型裝置優先級
sm640px - 767px大手機橫向P2
md768px - 1023px平板直向P1
lg1024px - 1279px平板橫向/小筆電P1
xl1280px - 1535px標準筆電P1
2xl1536px+桌面大螢幕P2

M.2 前台 (c9-ec) 響應式測試

M.2.1 首頁 (Home)

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
導航列漢堡選單展開/收合漢堡選單或部分顯示完整導航列
Banner 輪播全寬 + 觸控滑動全寬 + 觸控全寬 + 箭頭導航
遊戲分類橫向滾動 Tab2 行 Grid單行 Tab
遊戲卡片2 欄 Grid3 欄 Grid4-6 欄 Grid
底部導航列固定底部 5 Tab隱藏隱藏
客服浮動按鈕右下角右下角右下角
跑馬燈顯示(文字截斷)顯示顯示
頁尾單欄堆疊2 欄4 欄

M.2.2 登入/註冊頁

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
表單寬度全寬 padding 16px居中 max-w-md居中 max-w-md
輸入框全寬全寬全寬
密碼顯示切換觸控可用觸控/點擊點擊
社群登入按鈕全寬堆疊橫排橫排
鍵盤彈出表單不被遮擋表單不被遮擋N/A
驗證訊息顯示在欄位下方同左同左

M.2.3 遊戲大廳

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
分類篩選橫向滾動 Tab橫向 Tab固定 Tab
遊戲卡片2 欄,觸控啟動3 欄4-6 欄
搜尋框全寬,點擊展開固定寬度固定寬度
載入更多下拉觸發按鈕按鈕
遊戲詳情全螢幕 modal側邊 drawermodal
試玩按鈕可觸控可觸控hover 顯示

M.2.4 個人中心

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
側邊選單底部 Tab 導航左側摺疊選單左側固定選單
頭像上傳觸控可用觸控/點擊點擊
餘額顯示顯眼位置頂部頂部
交易紀錄卡片式列表表格式表格式
銀行卡列表卡片堆疊2 欄3 欄

M.2.5 存款頁

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
支付方式全寬 Tab橫排 Tab橫排 Tab
金額輸入全寬,數字鍵盤全寬固定寬度
快捷金額按鈕2x3 Grid3x2 Grid橫排
QR Code居中顯示居中居中
匯率資訊金額下方側邊側邊

M.2.6 VIP 頁面

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
等級進度條全寬全寬居中 max-w
等級卡片橫向滾動2 欄 Grid3-4 欄 Grid
返水表格橫向滾動完整顯示完整顯示
等級權益折疊式列表表格表格

M.2.7 代理推廣頁

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
推廣碼列表卡片堆疊表格表格
複製按鈕觸控可用同左同左
統計資訊2 欄 Grid4 欄 Grid4 欄 Grid
下線列表帳號遮罩 + 卡片表格表格
佣金圖表全寬全寬居中 max-w

M.3 後台 (c9-ims) 響應式測試

M.3.1 Sidebar 導航

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
Sidebar 狀態預設隱藏預設摺疊預設展開
觸發方式漢堡按鈕漢堡按鈕Toggle 按鈕
Overlay有背景遮罩有背景遮罩
子選單可展開可展開可展開
Active 狀態高亮顯示同左同左

M.3.2 Header

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
SiteSelector下拉正常下拉正常下拉正常
語系切換下拉正常下拉正常下拉正常
個人選單下拉正常下拉正常下拉正常
麵包屑隱藏或截斷顯示顯示

M.3.3 列表頁面(通用)

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
SiteTabs橫向滾動橫向滾動完整顯示
FilterBar欄位堆疊2 欄4 欄
SimpleTable橫向滾動部分滾動完整顯示
分頁簡化(< > 頁碼)完整完整
操作按鈕dropdown 或 icon文字按鈕文字按鈕
匯出按鈕IconIcon + 文字Icon + 文字

M.3.4 表單頁面(通用)

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
表單寬度全寬居中 max-w-2xl居中 max-w-2xl
欄位排列單欄雙欄雙欄
日期選擇器原生 pickerPopoverPopover
Select原生或 PopoverPopoverPopover
提交按鈕全寬底部固定右對齊右對齊
驗證訊息欄位下方同左同左

M.3.5 Dialog / Modal

測試項目手機 (< 768px)平板 (768-1023px)桌面 (1024px+)
寬度近全寬(padding)max-w-lgmax-w-lg
高度max-h-[80vh] 滾動max-h-[80vh]max-h-[80vh]
關閉方式X 按鈕 + 背景點擊同左 + ESC同左 + ESC
表單內 Dialog可正常輸入同左同左
確認 Dialog按鈕可觸控同左同左

M.4 觸控互動測試

M.4.1 手勢操作

手勢測試頁面預期行為
左右滑動前台 Banner切換輪播
左右滑動前台遊戲分類切換分類 Tab
下拉前台遊戲列表載入更多(若有)
長按前台推廣碼複製文字(系統選單)
捏合縮放所有頁面應禁止或正常
雙擊所有頁面不應觸發非預期行為

M.4.2 觸控目標尺寸

元素最小尺寸驗證方式
按鈕44 x 44 pxChrome DevTools 測量
連結44 x 44 px 觸控區域實機測試
核取方塊44 x 44 px 觸控區域實機測試
下拉選項44 px 高度實機測試
Tab 標籤44 px 高度實機測試
關閉按鈕44 x 44 px不可過小

M.5 橫向/直向切換測試

M.5.1 前台測試項目

頁面直向→橫向橫向→直向
首頁佈局正常調整佈局正常恢復
遊戲大廳Grid 欄位增加Grid 欄位減少
遊戲中遊戲視窗適應遊戲視窗適應
存款頁表單寬度調整表單寬度調整
VIP 頁卡片排列調整卡片排列調整

M.5.2 後台測試項目

頁面直向→橫向橫向→直向
列表頁表格橫向滾動消失表格橫向滾動出現
儀表板圖表重新適應圖表重新適應
表單頁欄位排列調整欄位排列調整

共用驗證

  • [ ] 切換後無 JavaScript 錯誤
  • [ ] 切換後無元素重疊
  • [ ] 切換後滾動位置合理
  • [ ] 切換後 Modal/Dialog 不脫位
  • [ ] 切換後表單輸入不遺失

M.6 鍵盤與無障礙測試

M.6.1 Tab 鍵導航順序

頁面預期 Tab 順序
登入頁帳號 → 密碼 → 登入按鈕 → 社群登入
註冊頁帳號 → 密碼 → 確認密碼 → Email → 手機 → 推廣碼 → 註冊按鈕
後台列表SiteTabs → FilterBar → 搜尋按鈕 → 表格 → 分頁
Dialog第一個可聚焦元素 → ... → 確認按鈕 → 取消按鈕

M.6.2 ARIA 標籤驗證

元素必要 ARIA驗證
導航列role="navigation", aria-label螢幕閱讀器可識別
對話框role="dialog", aria-modal="true"聚焦困在 Dialog 內
表格role="table"<table>螢幕閱讀器可讀行列
按鈕aria-label(icon-only 按鈕)有語義說明
表單<label> 關聯或 aria-label欄位有標籤
載入中aria-busy="true"通知輔助技術
分頁aria-current="page"標示當前頁
Toastrole="alert"自動通知

M.6.3 色彩對比度

元素類型WCAG AA 要求驗證工具
一般文字對比度 >= 4.5:1Chrome DevTools / axe
大型文字 (18px+)對比度 >= 3:1Chrome DevTools / axe
UI 元件對比度 >= 3:1Chrome DevTools / axe
狀態標籤對比度 >= 3:1確認各 StatusBadge 顏色
連結對比度 >= 4.5:1 + 可辨識不只用顏色區分

M.7 效能基準(行動裝置)

M.7.1 Lighthouse 行動版指標

指標前台目標後台目標測量條件
Performance>= 80>= 70Mobile, Throttled 4G
FCP< 2.0s< 2.5sThrottled 4G
LCP< 3.0s< 3.5sThrottled 4G
CLS< 0.1< 0.15頁面載入完成
TBT< 300ms< 400msThrottled 4G
TTI< 4.0s< 5.0sThrottled 4G

M.7.2 網路條件模擬

網路類型下載速度延遲測試重點
4G Fast12 Mbps40ms基準測試
4G Slow4 Mbps100ms一般使用者
3G1.5 Mbps300ms最差情境
Offline → OnlineN/AN/A斷線恢復
測試項目3G 預期4G 預期
首頁載入< 8s< 3s
登入操作< 5s< 2s
遊戲列表< 6s< 2.5s
圖片載入lazy load 運作lazy load 運作
API 失敗顯示重試提示正常回應

文件結尾

版本歷史

  • v1.0 (2026-03-01):初版,涵蓋第 1-6 章(測試環境、前台/後台/後端測試案例、E2E 測試、多站點隔離)
  • v2.0 (2026-03-02):新增第 7-10 章(安全性測試、效能測試、回歸測試清單、Bug 報告模板)及附錄 A-J
  • v2.1 (2026-03-02):新增附錄 K(資料庫 Schema 測試)、L(API Contract 測試)、M(行動裝置與響應式測試)

文件統計

  • 總行數:8,200+
  • 總測試案例數:~950+
  • 涵蓋模組數:16 個權限模組 + 23 個後端模組
  • 涵蓋頁面數:前台 20 頁 + 後台 68 頁
  • 涵蓋 API 端點數:205+
  • 涵蓋資料表數:49 張
  • 附錄數量:13 個(A-M)

文件維護:本文件應隨系統功能更新同步維護,每次重大功能上線後更新對應的測試案例。 問題回饋:若發現文件錯誤或遺漏,請建立 Issue 標記為 doc-bug

最後更新: