Home
System Architecture

Chat Management Backstage

聊天管理後台系統架構設計與完成度總覽

9Modules
9DB Tables
10Pages
48Test Files
Scroll

System Architecture

Monorepo 架構,client / server / shared / e2e 四層分離,透過根層 concurrently 統一管理開發與部署。

系統架構圖

前端 SPA → Vite Proxy → Express API → SQLite,Production 模式由 Express 直接 serve 前端靜態檔案

System Architecture Diagram
Frontend
React 18 + Vite + TypeScript
Ant Design 6.x 元件庫 + antd-style 樣式管理
React Router v6 路由 + Axios HTTP Client
dayjs UTC+8 時間顯示
Backend
Express.js + TypeScript
SQLite (better-sqlite3) 零配置資料庫
Knex.js Query Builder + Migration/Seed
Cookie-based JWT + bcryptjs
Shared
Zod Schema + TypeScript Types
前後端共用驗證邏輯與型別定義
@shared/* path alias 跨專案引用
9 套 Schema 對應 9 個 API 模組
Testing
Vitest + Playwright
三層測試:Unit / Integration / E2E
supertest + :memory: SQLite 隔離測試
Playwright 錄影 + 自動合成 Demo 影片
DevOps
Docker + concurrently
多階段 Docker build(node:20-alpine)
docker compose up 一鍵啟動
分環境 .env.development / .env.production
Auth
JWT HttpOnly Cookie + RBAC
Config-based 權限管理(22 權限 × 2 角色)
requirePermission() middleware 路由守衛
SameSite=Strict 防護 + 敏感欄位遮罩

Backend Architecture

9 個後端模組全部遵循 Route → Controller → Service 三層分離,透過工廠注入模式傳遞 DB 依賴。

Module Pattern — 每個模組使用 createXxxRoutes(db: Knex): Router 工廠函式,顯式傳遞 DB 依賴,不使用全域單例。Integration test 可直接傳入 :memory: SQLite 實例。

Database Strategy — 為何選用 SQLite + 如何保留切換彈性

選用理由
SQLite(better-sqlite3)
零配置部署:無需安裝額外資料庫服務,clone 後即可開發
同步 API:better-sqlite3 為 in-process 同步引擎,延遲極低
Demo 定位:單用戶管理後台,不需要並發寫入能力
測試友善:memory: 模式讓每個測試檔案擁有獨立 DB 實例
切換彈性
Knex.js 抽象層 + 工廠注入
Knex Query Builder:所有 SQL 透過 Knex API 組裝,不含 SQLite 專屬語法
Migration 機制:14 個 migration 檔案定義完整 schema,可重播至任意 DB
工廠注入createXxxRoutes(db) 傳入 Knex 實例,切換 DB 只需改 knexfile.ts 的 client 設定
已驗證:Integration test 使用 :memory: vs Production 使用 file DB,證明抽象層無洩漏

Middleware Pipeline

express.json() cookie-parser CORS Encoding DB Init operationLogger API Routes Static Files 404 Handler Error Handler

9 Backend Modules

/api/auth
認證模組
login / logout / me / password / permissions
/api/admins
帳號管理
CRUD + toggle / role / password reset
/api/chatrooms
聊天室
列表查詢(唯讀)+ 名稱搜尋
/api/chat_messages
聊天監控
多條件篩選 + 軟刪除 + 操作紀錄
/api/blacklist
黑名單 + IP 封鎖
player / ip 雙路由 + upsert 封鎖邏輯
/api/players
玩家管理
暱稱審核 approve/reject + 重設暱稱
/api/reports
檢舉審核
核准自動封鎖(transaction)+ 駁回
/api/broadcasts
系統廣播
動態 status 計算 + 軟刪除下架
/api/operation-logs
操作紀錄
afterware 自動寫入 + 篩選查詢

Unified Response Envelope

Success
{ "success": true,
  "data": { ... } }
Error
{ "success": false,
  "error": {
    "code": "AUTH_...",
    "message": "..."
  }
}
Paginated
{ "success": true,
  "data": [...],
  "pagination": {
    "page": 1,
    "total": 100
  }
}

Frontend Architecture

React 18 SPA,10 個頁面依權限動態渲染,Design System 支援 Dark / Light / System 三態切換。

Component Tree

ThemeProvider ConfigProvider AuthProvider RouterProvider AdminLayout Pages

10 Frontend Pages

Route Page Permission Description
/login LoginPage Public 帳號密碼登入 + 已登入自動跳轉
/chat ChatMonitoringPage chat:read 訊息監控 + 刪除 + 封鎖 + 暱稱重設
/blacklist BlacklistPage blacklist:read Player / IP 封鎖管理 + 新增 Modal
/chatrooms ChatroomPage chatroom:read 聊天室列表(唯讀)+ 搜尋
/broadcasts BroadcastPage broadcast:read 發送廣播 + 狀態標籤 + 下架
/operation-logs OperationLogPage operation_log:read 操作紀錄篩選 + request JSON 展開
/reports ReportReviewPage report:read 檢舉審核(核准自動封鎖)
/nickname-reviews NicknameReviewPage nickname:read 暱稱審核(駁回自動重設)
/admins ManagerPage admin:read 帳號管理(角色/密碼/啟停用)
/* NotFoundPage Public 404 頁面(在 AdminLayout 內顯示)

Shared Layer — Zod 一處定義,三處使用

Backend
validate(schema) middleware
驗證 req.body,失敗回傳統一 error envelope;parsed data 覆寫原始 body(strip unknown fields)
Frontend
zodToAntdRules(schema)
將 Zod schema 轉換為 Ant Design Form 的 rules 格式,前後端驗證邏輯一致
Types
z.infer<typeof schema>
自動從 Zod schema 推導 TypeScript 型別,不需手動維護 interface

Design System

Seed Tokens (Light)
colorPrimary: #1A6FD4
colorSuccess: #34C759 (iOS Green)
colorWarning: #FF9500 (iOS Orange)
colorError: #FF3B30 (iOS Red)
colorInfo: #5856D6 (iOS Indigo)
colorBgLayout: #F2F2F7
Theme Features
三態切換:Light / Dark / System(跟隨 OS)
Token 層級:Seed → Map(自動推導)→ Component
Dark Mode:darkAlgorithm 自動推導,僅覆寫 colorPrimary: #2E88EE
圓角:borderRadius 10px / 14px / 8px
陰影:Card / Modal 使用 iOS 細膩陰影
持久化:localStorage 保存主題偏好

UI Screenshots

Database Schema

9 張資料表、14 個 migration、三種刪除策略。SQLite 零配置,Knex.js 抽象層讓未來可切換 DB。

Entity-Relationship Diagram

9 張資料表的欄位結構與關聯關係

Database ER Diagram

9 Data Tables

Table PK Type Purpose Delete Strategy RFC
admins INT AUTO 管理員帳號(角色、狀態) rfc_01
operation_logs INT AUTO 操作稽核紀錄(request JSON) 不可刪除 rfc_02
chatrooms VARCHAR(50) 聊天室列表(業務 ID) deleted_at rfc_03
players VARCHAR(50) 玩家帳號(含暱稱審核欄位) deleted_at rfc_03
chatroom_players INT AUTO 聊天室 ↔ 玩家多對多關聯 deleted_at rfc_03
chat_messages INT AUTO 聊天訊息(軟刪除) deleted_at rfc_03
blacklist INT AUTO 玩家/IP 封鎖(統一表) is_blocked rfc_04
reports INT AUTO 玩家檢舉審核 不可刪除 rfc_05
broadcasts INT AUTO 系統廣播(動態計算 status) deleted_at rfc_06

設計慣例

時間儲存
全部 UTC+0 儲存
前端 dayjs 轉 UTC+8 顯示
快照欄位
operator 為寫入時快照
player_nickname 改為 JOIN
Magic Value
chatroom_id = 'all'
代表全域(避免 NULL UNIQUE)
FK 約束
SQLite 預設不強制 FK
應用層自行維護一致性

RBAC Permission System

Config-Based RBAC:22 項權限 × 2 角色,前後端雙重守衛,無需額外 DB 表。

General Manager
16 項權限
聊天監控、黑名單管理、IP封鎖、聊天室、操作紀錄、檢舉審核、暱稱審核、玩家暱稱重設、修改自己密碼
Senior Manager
22 項權限(全部)
繼承 General Manager 所有權限 + 帳號管理(CRUD + toggle + 重設密碼)+ 系統廣播(發送 + 下架)

Permission Matrix(22 × 2)

Category Permission General Senior
auth auth:change_own_password
chat chat:read / chat:delete
blacklist blacklist:read / create / delete
ip_block ip_block:read / create / delete
chatroom chatroom:read
operation_log operation_log:read
report report:read / review
nickname nickname:read / review
player player:reset_nickname
admin admin:read / create / toggle / reset_password
broadcast broadcast:read / create / delete
守衛機制:① 後端 requirePermission() middleware 在 route 層級強制驗證 → ② 前端 ProtectedRoute 阻擋無權限頁面 → ③ Sidebar menuItems.filter() 隱藏無權限選單項目

Testing Strategy

三層測試金字塔 — Unit / Integration / Component / E2E,:memory: SQLite 與 production 同引擎。

Unit Tests
4
middleware + config
Integration
20
API pipeline + DB
Component
15
React + Testing Library
E2E Tests
9
Playwright specs

Test Coverage

測試環境資源

Resource Server Vitest Client Vitest E2E (Playwright)
Database :memory: SQLite dev.sqlite(resetDb)
HTTP supertest(不佔 port) dev server(3000 + 5173)
隔離性 完全隔離 完全隔離 共用 dev DB
Demo Video 自動生成 — Playwright 開啟 video: 'on' 錄影,測試完成後 compose-video.ts 將 .webm 片段轉為 MP4 + 燒入 SRT 字幕 + 插入標題卡 + 串接合成 output/demo.mp4。一份 E2E 測試同時達成 CI 品質保障 + 功能展示影片。

Gherkin-first 開發流程

PRD 定義 FR 撰寫 .feature RFC 測試計畫 Task 穿插測試 功能 + 測試同步寫

System Completion

12 個開發 Phase 全部完成,9 個功能模組全部上線,涵蓋原始需求的所有功能項目。

12 Development Phases

P00專案初始化
P01Auth + Response
P02操作紀錄
P03聊天室 + 監控
P04黑名單 + IP
P05暱稱 + 檢舉
P06系統廣播
P07Design System
P08E2E + Demo
P09暱稱重設 API
P10環境變數配置
P12Production Mode

Assignment Requirements vs Delivery

Backend API (Assignment §5)
  • login — JWT HttpOnly Cookie 登入
  • getChatHistory — 多條件篩選 + 分頁
  • deleteMessage — 軟刪除 + 操作紀錄
  • blockPlayer — upsert 封鎖 + chatroom 指定
  • unblockPlayer — is_blocked 狀態切換
  • broadcastMessage — 動態 status + 下架
  • getChatrooms — 列表 + 名稱搜尋
  • getOperationLogs — afterware 自動寫入
Frontend Pages (Assignment §5)
  • Login Page — 表單驗證 + 已登入跳轉
  • Chat Monitoring — 刪除 / 封鎖 / 暱稱重設
  • Blacklist Management — Player + IP 雙模式
  • Broadcast Message — 發送 + 狀態 Tag + 下架
  • Operation Logs — 篩選 + request 展開
  • Player Reports — 核准自動封鎖
  • Nickname Approval — 駁回自動重設

Live Demo

E2E 測試自動錄製的系統操作展示影片,涵蓋主要功能流程。

系統操作展示

由 Playwright E2E 測試自動錄製,經 compose-video.ts 合成

Future Improvements

以下為系統正式上線後的完整優化規劃,按優先級排序。涵蓋安全加固、即時通訊升級、UI/UX 優化、 資料庫遷移等面向,每個階段包含具體技術方案、量化效益指標與風險評估。

P0  安全加固

預估 0.5 天
Rate Limiting
問題:登入 API 無頻率限制,可暴力破解密碼
方案express-rate-limit — 登入 5 次/分鐘/IP,全域 API 100 次/分鐘
影響:app.ts + auth/route.ts
驗收:超頻返回 429,E2E 驗證鎖定行為
預估 0.5 天
CSRF 防護強化
問題:HttpOnly Cookie 防 XSS,但未完整防禦 CSRF
方案:Cookie 加入 SameSite=Strict 屬性(已部分實作),可進階採用 Double Submit Cookie 模式
影響:auth/controller.ts + client interceptor
預估 1 天
帳號鎖定機制
問題:連續登入失敗無限制
方案:admins 新增 failed_attempts + locked_until 欄位,5 次失敗鎖定 15 分鐘
影響:新增 migration + auth/service.ts + errorCodes.ts
預估 0.5 天
Security Headers
問題:缺少標準安全回應標頭,瀏覽器無法啟用內建防護
方案:引入 helmet middleware — 自動設定 X-Content-Type-Options、X-Frame-Options、 Content-Security-Policy、Strict-Transport-Security 等標頭
影響:app.ts 新增一行 middleware

P1  即時通訊 & 架構補強

預估 3 天
WebSocket 即時通訊
問題:聊天監控頁面需手動刷新,管理員操作(禁言/刪訊)無法即時同步給其他在線管理員
為何選 WebSocket 而非 SSE
• 管理後台需要雙向通訊 — server 推送新訊息 + client 回報已讀/操作狀態
• 多管理員同時操作需即時同步(A 禁言某玩家,B 的畫面應即時反映)
• SSE 受限瀏覽器 6 連線上限,多分頁場景容易耗盡
方案Socket.IO — 自動降級 polling、內建 reconnect 與 room 機制
架構
• Server:socketManager.ts 掛載於 Express HTTP server,JWT 驗證 middleware
• Room 設計:每個 chatroom 對應一個 room,管理員進入監控頁自動 join
• 事件頻道:chat:message / chat:delete / admin:action / player:status
• Client:新增 useSocket hook + SocketContext,頁面卸載自動 disconnect
影響:server/src/socket/ 新模組 + ChatMonitoringPage 重構 + package.json 新增 socket.io / socket.io-client
效益:訊息延遲從手動刷新(秒級)降至 <100ms,管理員協作體驗大幅提升
預估 1 天
In-Memory Cache
問題:每次 API 請求直接查詢 SQLite,高頻讀取可優化
方案:Node.js node-cache 快取 RBAC 權限設定(長 TTL)+ 黑名單查詢(30s TTL)
Invalidation 策略:寫入操作後主動 del(key) 清除對應快取,避免髒讀。 operationLogger afterware 作為觸發點,確保 cache 與 DB 一致性
影響:新增 cache.ts + permission middleware + blacklist service
效益:RBAC 查詢 RT 預估降低 80%(記憶體 vs. SQLite I/O)
預估 1 天
Error Boundary 策略
問題:前端缺乏系統性錯誤處理,React render error 可能白屏
方案:頂層 ErrorBoundary + Axios interceptor 統一處理 401/403/429/500/離線
細節:401 自動導回登入、403 顯示權限不足提示、429 顯示冷卻倒數、 500 顯示通用錯誤頁、離線狀態顯示 banner 提示
影響:新增 ErrorBoundary.tsx + 增強 api/client.ts + App.tsx

P2  UI/UX 優化 & 工程實務

預估 3 天
UI/UX 體驗升級
問題:10 個頁面缺乏統一的載入狀態、空狀態、微互動回饋,使用者體驗不連貫
方案(分三階段)
Phase 1 — 載入體驗(1 天)
• 全域引入 Skeleton 骨架屏取代 Spin,表格 / 卡片 / 表單各一套模板
• 路由切換加入 NProgress 頂部進度條
• 操作按鈕加入 loading 態,防止重複提交
Phase 2 — 空狀態 & 引導(1 天)
• 為「無資料」「篩選無結果」「搜尋無結果」設計三種 Empty 元件
• 關鍵操作(禁言/封鎖/刪除)加入 Popconfirm 二次確認,取代原生 confirm
Phase 3 — 微互動(1 天)
• 表格列新增/刪除時加入 framer-motion list animation
• 成功操作 toast 改用 Antd message 帶圖標,2 秒自動消失
• Sidebar 選中項加入 indicator 動畫
影響:新增 Skeleton components + 更新所有 page loading 邏輯
預估 2 天
響應式設計 & 無障礙
問題:後台僅適配桌面版,無平板/行動裝置支援;缺乏基本無障礙標記
方案
• AdminLayout Sidebar 加入 Drawer 模式,≤768px 時自動收合為 hamburger
• 表格在小螢幕改為 Card List 排列(Antd Table responsive breakpoint)
• 所有 icon-only 按鈕補上 aria-label,表單元件確保 label 關聯
• 色彩對比度檢查,確保 WCAG 2.1 AA 標準(contrast ratio ≥ 4.5:1)
影響:AdminLayout.tsx + 各 page 表格元件 + theme tokens 微調
效益:支援管理員以平板巡場監控,擴大使用場景
預估 1 天
前端效能優化
問題:聊天監控頁面訊息量大時 DOM 節點爆增,列表渲染卡頓
方案
• 聊天訊息列表引入 react-virtuoso 虛擬滾動,僅渲染可視區域
• 路由層級 React.lazy + Suspense 拆分 code splitting,首屏只載入當前頁面
• 搜尋/篩選輸入加入 useDeferredValue 防止高頻 re-render
效益:萬級訊息頁面 FPS 維持 60,首屏 JS bundle 預估減少 40%
影響:ChatMonitoringPage + router config + 搜尋元件
預估 1 天
CI/CD Pipeline
問題:測試通過完全依賴開發者手動執行
方案:GitHub Actions — lint → vitest run → npm run build,push to main / PR 時自動觸發
進階:E2E 為可選步驟,PR 標題帶 [e2e] 時觸發 Playwright on CI
影響:新增 .github/workflows/ci.yml
預估 2 天
Unit Test 覆蓋率提升
問題:Unit test 僅 4 個,utility functions 未覆蓋
方案:補齊 ResponseHelper / AppError / zodToAntdRules / Zod schemas 邊界值
目標:middleware ≥ 90%、utility ≥ 85%、整體 statement coverage ≥ 70%
預估 2 天
共用 Component 抽取
問題:10 個頁面僅 2 個 reusable component,相似 UI pattern 各自實作
方案:抽取 ConfirmActionModal / SearchFilterForm / StatusTag / DataTable(統一分頁/排序)
原則:確認 3+ 使用場景才抽取,每個元件附帶 Storybook-like 範例

P3  規模化演進

預估 3–5 天
資料庫遷移:SQLite → PostgreSQL
觸發指標:同時在線管理員 >5 人且出現 SQLITE_BUSY 錯誤, 或單表資料量超過 50 萬筆查詢回應 >200ms
為何遷移
• SQLite 單寫入鎖 — 多管理員同時操作聊天/黑名單/廣播時會產生寫入排隊
• 無原生全文搜尋 — 聊天訊息搜尋只能 LIKE,效能線性退化
• 無連線池 — 無法水平擴展至多 server instance
方案(分階段降低風險)
Step 1:本地建立 PostgreSQL,修改 Knex config 切換 dialect(Knex 抽象層已到位)
Step 2:跑全部 14 個 migration,驗證 SQL 相容性(已知問題:DATETIME → TIMESTAMP、BOOLEAN → BOOLEAN、autoIncrement 差異)
Step 3:撰寫資料遷移 script — pg_dump / knex seed 匯入既有資料
Step 4:E2E 全量回歸測試確認功能一致
附加效益:可啟用 pg_trgm 做模糊搜尋、JSONB 存結構化 log、支援 connection pooling
風險:部署環境需額外維運 PostgreSQL(可用 managed service 如 Supabase / Neon 降低維運成本)
預估 2 天
WebSocket 進階功能
觸發指標:P1 WebSocket 基礎版上線後,管理員反映需要更多即時協作功能
方案
在線狀態追蹤:顯示哪些管理員正在監控哪個聊天室,避免重複操作
打字指示器:管理員在輸入廣播/回覆時,其他人看到 "XXX 正在輸入…"
操作衝突預警:當兩位管理員同時編輯同一筆黑名單/廣播時,彈出提示
即時通知中心:新檢舉、新玩家申請暱稱等事件推送至 Notification Bell
影響:擴展 socket event 頻道 + 新增 AdminPresence 元件 + NotificationCenter
視用戶反饋決定
JWT Refresh Token
觸發指標:用戶反映頻繁被登出(當前 JWT 4 小時過期)
方案:Access Token 15min + Refresh Token 7d rotation,Axios interceptor 自動在 401 時 用 Refresh Token 換發新 Access Token
安全設計:Refresh Token 存 HttpOnly Cookie(獨立 path /api/auth/refresh), 單次使用後即失效(rotation),偷取舊 token 無法重放
影響:auth module 全面重構 + client interceptor + 新增 refresh migration
視資料量決定
Broadcast 狀態持久化
觸發指標:廣播數量超過 1000 筆,列表查詢回應 >500ms
方案:新增 status column + cron 定時更新(node-cron 每分鐘),或結合 P1 的 cache 層做 computed cache
影響:新增 migration + broadcast/service.ts
視查詢效能決定
資料庫 Index 優化
觸發指標:任一查詢 API p95 回應時間 >200ms
候選欄位
chat_messages(chatroom_id, created_at) — 聊天室訊息時序查詢
blacklist(target_type, target) — 黑名單比對
operation_logs(created_at) — 操作日誌時間範圍查詢
reports(status, created_at) — 待處理檢舉篩選
方案:透過 Knex migration 新增複合索引,搭配 EXPLAIN QUERY PLAN 驗證命中
預估 2 天
操作日誌儀表板
觸發指標:管理團隊 >3 人,需追蹤操作趨勢與異常行為
方案:新增 Dashboard 頁面 — 每日操作量趨勢圖(Ant Design Charts)、 操作類型分佈圓餅圖、管理員活躍度排行、異常操作高亮(短時間大量刪除/封鎖)
資料來源:operation_logs 現有欄位即可支撐,不需新增 schema
影響:新增 DashboardPage + 對應 API 聚合查詢