Site Admin Dashboard Mockup PRD(給後端 API 規格產生器使用)
此範本專門給 30%-feature-gen 產出的 mockup PRD 使用。
backend-api-spec-generator 會讀取這份文件與 Storybook mockups 來產生後端 API 規格。
1. 文件資訊
2. 開發進度與設計來源
開發進度
- 前端 PR #:[TBD / 待開發後補上]
- 後端 PR #:[TBD / 待開發後補上]
設計來源
- Figma 連結:無(直接使用 Naive UI Admin 現有元件)
- Pixsole / 既有畫面:無
3. 模擬頁面摘要(Mockup Summary)
3.1 功能概述
- 功能名稱:Site Admin Dashboard(站台管理儀表板)
- 主要使用者角色:Site Admin(WPort 官方人員)
- 核心目標:
- 讓站台管理員透過時間篩選快速掌握平台關鍵數據(公司、使用者、外籍使用者)
- 監控平台健康度,及早發現異常(如註冊數下降)
- 追蹤外籍使用者指標(WPort 核心業務方向)
3.2 範圍界定
- 包含範圍:
- 時間區間篩選器(開始日期 + 結束日期,粒度:天,預設:本週)
- 公司區塊:2 張統計卡片
- 使用者區塊:3 張統計卡片
- 外籍區塊:3 張統計卡片
- 排除範圍:
- 趨勢圖表(nice-to-have,未來版本)
- CSV 匯出(nice-to-have,未來版本)
- 自動寄報表(nice-to-have,未來版本)
- 公司狀態篩選(nice-to-have,未來版本)
3.3 成功條件
- 站台管理員能在 Dashboard 頁面選擇時間區間,即時查看 8 項指標
- 指標數據正確反映資料庫狀態,快取延遲不超過 1 小時
- 外籍使用者判定邏輯正確,符合六種身分類型定義
4. 商業規則對齊(Business Rules Alignment)
供 backend-api-spec-generator 對齊 prd/business-rules.md。
新功能若有新規則,先在此描述,再視情況回寫至 business-rules。
4.1 本功能使用到的業務規則
| 規則 ID | 規則摘要 | 是否關鍵 | 備註 |
|---|
| BR-021 | 僑外生特區顯示與篩選規則——外籍使用者定義 | ✅ 是 | 外籍判定的六種 work_identity_type 與此規則一致 |
| BR-002 | 信箱認證後完成個人資料才能新增履歷 | ℹ️ 參考 | 影響「履歷公開數」的分母理解 |
| BR-010 | 履歷建立條件與數量限制 | ℹ️ 參考 | 每人最多 6 份履歷,影響履歷統計理解 |
4.2 補充說明
- 外籍使用者定義:以使用者當下的
work_identity_type 欄位為準,符合以下六種之一即計為外籍使用者:
- 僑生/港澳台(在學)
- 外國籍留學生(在學中)
- 僑外生(畢業尋職中)
- 外國專業人士(在台工作中)
- 獲准居留之新住民
- 移工(留才久用候選人)
- 使用者修改身分類型後,以查詢當下的身分為準,歷史不追溯。
- 本功能為純讀取,不涉及任何寫入操作,無新增動作上限需求。
5. 資料實體與欄位(Data Entities & Fields)
backend-api-spec-generator 會依此節與 Storybook 的 interface/mock data 推導 API 結構。
欄位命名請與 Storybook/TS 介面一致。
5.1 實體列表
| 實體名稱 | 說明 | 來源頁面/區塊 |
|---|
| DashboardStats | Dashboard 統計數據回傳結構 | 整個 Dashboard 頁面 |
| DateRange | 時間區間篩選參數 | 篩選器 |
5.2 實體欄位定義(TypeScript 介面)
DateRange(查詢參數)
interface DashboardQuery {
start_date: string; // YYYY-MM-DD,區間開始日期(含)
end_date: string; // YYYY-MM-DD,區間結束日期(含)
}
DashboardStats(回傳結構)
interface StatCard {
period_count: number; // 區間內數量(分子)
total_count: number; // 全站總數量(分母)
}
interface StatCardCurrentOnly {
total_count: number; // 僅顯示當下總數(無時戳,無法計算區間)
}
interface DashboardStats {
company: {
registered: StatCard; // 註冊公司數
published_jobs: StatCard; // 發布職缺數(不重複)
};
user: {
registered: StatCard; // 使用者數
published_resumes: StatCardCurrentOnly; // 履歷公開數(無時戳)
applications: StatCard; // 應徵次數
};
foreigner: {
registered: StatCard; // 外籍使用者數
published_resumes: StatCardCurrentOnly; // 外籍履歷公開數(無時戳)
applications: StatCard; // 外籍應徵次數
};
cached_at: string; // ISO 8601,快取時間,供前端顯示「資料更新時間」
}
6. 畫面區塊與資料需求(UI Sections & Data Needs)
6.1 區塊列表
| 區塊 ID | 區塊名稱 | 說明 |
|---|
| SEC-1 | 時間篩選器 | 開始日期 + 結束日期選擇器,預設本週 |
| SEC-2 | 公司統計區塊 | 2 張卡片:註冊公司數、發布職缺數 |
| SEC-3 | 使用者統計區塊 | 3 張卡片:使用者數、履歷公開數、應徵次數 |
| SEC-4 | 外籍統計區塊 | 3 張卡片:外籍使用者數、外籍履歷公開數、外籍應徵次數 |
6.2 各區塊資料需求
SEC-1 時間篩選器
- 元件:兩個日期選擇器(DatePicker),分別為開始日期與結束日期
- 預設值:本週一 ~ 今天
- 驗證:開始日期不得晚於結束日期;選定後觸發查詢
- 行為:變更日期後重新呼叫 API 取得新數據
SEC-2 公司統計區塊
- 標題:「公司 Company」
- 卡片 1 — 註冊公司數:
- 顯示格式:
{period_count} / {total_count}
- 說明文字:區間內新註冊 / 全站總公司數
- 卡片 2 — 發布職缺數:
- 顯示格式:
{period_count} / {total_count}
- 說明文字:區間內曾上架的不重複職缺 / 全站曾上架的不重複職缺
SEC-3 使用者統計區塊
- 標題:「使用者 User」
- 卡片 1 — 使用者數:
- 顯示格式:
{period_count} / {total_count}
- 說明文字:區間內新註冊 / 全站總使用者數
- 卡片 2 — 履歷公開數:
- 顯示格式:
{total_count}(僅顯示當下總數)
- 說明文字:當前公開中的履歷數量
- ⚠️ 因無 publish 時戳,此卡片不受時間篩選影響
- 卡片 3 — 應徵次數:
- 顯示格式:
{period_count} / {total_count}
- 說明文字:區間內應徵次數 / 全站總應徵次數
SEC-4 外籍統計區塊
- 標題:「外籍 Foreigner」
- 卡片 1 — 外籍使用者數:
- 顯示格式:
{period_count} / {total_count}
- 說明文字:區間內新註冊外籍使用者 / 全站外籍使用者總數
- 卡片 2 — 外籍履歷公開數:
- 顯示格式:
{total_count}(僅顯示當下總數)
- 說明文字:當前外籍使用者公開中的履歷數量
- ⚠️ 因無 publish 時戳,此卡片不受時間篩選影響
- 卡片 3 — 外籍應徵次數:
- 顯示格式:
{period_count} / {total_count}
- 說明文字:區間內外籍使用者應徵次數 / 全站外籍應徵總次數
7. 使用者動作與後端需求(User Actions & Backend Needs)
| 動作 ID | 動作名稱 | 類型 | 需要後端 | 涉及實體 | 說明 |
|---|
| ACT-1 | 載入 Dashboard | 查詢(Read) | ✅ 是 | DashboardStats | 頁面載入時以預設時間區間(本週)查詢 |
| ACT-2 | 變更時間區間 | 查詢(Read) | ✅ 是 | DashboardStats | 修改開始/結束日期後重新查詢 |
| ACT-3 | 日期驗證 | UI | ❌ 否 | DateRange | 前端驗證開始日期 ≤ 結束日期 |
場景與邊界行為
| 場景 | 進入條件 | 畫面與行為 |
|---|
| 正常查看 | Admin 進入 Dashboard | 預設本週,8 張卡片顯示數字 |
| 切換時間區間 | 修改開始/結束日期 | 重新查詢,卡片數字更新;查詢中顯示 loading |
| 區間內無數據 | 所選時間範圍內無活動 | 分子顯示 0,分母仍顯示全站總數 |
| 履歷公開卡片 | 任何時間 | 不顯示分子/分母格式,僅顯示當下總數,不受時間篩選影響 |
| 開始日期 > 結束日期 | 使用者選錯日期 | 前端阻擋,提示「開始日期不得晚於結束日期」,不送出請求 |
| API 回傳錯誤 | 伺服器異常 | 顯示錯誤提示,保留上次成功的數據(若有) |
| 快取資料 | 任何時間 | 頁面底部或卡片區域顯示「資料更新時間:{cached_at}」 |
8. API Hints(提示用,非最終 API 設計)
8.1 資料讀取需求(Read)
- HINT-GET-1:取得 Dashboard 統計數據
- 對應區塊:SEC-2, SEC-3, SEC-4
- 輸入:
start_date(YYYY-MM-DD)、end_date(YYYY-MM-DD)
- 回傳:
DashboardStats 完整結構
- 快取策略:Server-side cache,key 為
start_date + end_date,TTL 1 小時
- 權限:僅 Site Admin 可存取
8.2 資料寫入需求(Write)
無。本功能為純讀取,不涉及任何寫入操作。
8.3 數據計算邏輯
公司區塊
| 指標 | 分子(區間內) | 分母(全站) |
|---|
| 註冊公司數 | company.created_at BETWEEN start_date AND end_date | COUNT(company.*) |
| 發布職缺數 | 區間內曾有 published 狀態的不重複職缺數(同一職缺多次上架/下架只算 1) | 全站曾有 published 狀態的不重複職缺數 |
使用者區塊
| 指標 | 分子(區間內) | 分母(全站) |
|---|
| 使用者數 | user.created_at BETWEEN start_date AND end_date | COUNT(user.*) |
| 履歷公開數 | ⚠️ 無時戳,不計算區間 | 當下 resume.published_status = 1 的履歷數量 |
| 應徵次數 | job_application.created_at BETWEEN start_date AND end_date | COUNT(job_application.*) |
外籍區塊
與使用者區塊邏輯相同,額外加上條件:使用者當下的 work_identity_type 為以下六種之一:
| code(待對齊) | 說明 |
|---|
| (待確認) | 僑生/港澳台(在學) |
| (待確認) | 外國籍留學生(在學中) |
| (待確認) | 僑外生(畢業尋職中) |
| (待確認) | 外國專業人士(在台工作中) |
| (待確認) | 獲准居留之新住民 |
| (待確認) | 移工(留才久用候選人) |
實際 code 值需與後端 dict_work_identity_type 對齊。
9. 導航 / Storybook Map
10. Flowcharts(User / System / Navigation)
10.1 User Flow(使用者操作流程)
flowchart TD
U1[Site Admin 進入 Dashboard 頁面] --> U2[系統以預設時間區間<br/>本週一~今天 載入數據]
U2 --> U3[顯示 8 張統計卡片<br/>公司 2 張 / 使用者 3 張 / 外籍 3 張]
U3 --> U4{Admin 是否變更時間區間?}
U4 -->|是| U5[選擇開始日期與結束日期]
U4 -->|否| U6[查看數據完畢]
U5 --> U7{開始日期 ≤ 結束日期?}
U7 -->|否| U8[顯示錯誤提示<br/>開始日期不得晚於結束日期]
U8 --> U5
U7 -->|是| U9[重新查詢 API]
U9 --> U10{API 回傳成功?}
U10 -->|是| U3
U10 -->|否| U11[顯示錯誤提示<br/>保留上次成功數據]
U11 --> U4
10.2 System Flow(前端狀態與資料流)
sequenceDiagram
participant Admin as Site Admin
participant FE as Frontend<br/>(Naive UI Admin)
participant API as Backend API
participant Cache as Server Cache
Admin->>FE: 進入 Dashboard 頁面
FE->>FE: 計算預設時間區間(本週一~今天)
FE->>API: GET /siteadmin/dashboard/stats<br/>?start_date=YYYY-MM-DD&end_date=YYYY-MM-DD
API->>Cache: 檢查快取(key: start_date+end_date)
alt 快取命中且未過期(< 1 小時)
Cache-->>API: 回傳快取數據
else 快取未命中或已過期
API->>API: 查詢資料庫<br/>計算 8 項指標
API->>Cache: 寫入快取(TTL: 1 小時)
end
API-->>FE: 回傳 DashboardStats JSON
FE-->>Admin: 渲染 8 張統計卡片 + 資料更新時間
Admin->>FE: 變更時間區間
FE->>FE: 驗證 start_date ≤ end_date
alt 驗證失敗
FE-->>Admin: 顯示錯誤提示
else 驗證通過
FE->>API: GET /siteadmin/dashboard/stats<br/>?start_date=NEW&end_date=NEW
API-->>FE: 回傳新數據
FE-->>Admin: 更新卡片數字
end
11. Mock Data Schema(Mock 資料結構)
- 資料來源:僅 mock,不呼叫真實 API
- CRUD 行為:純讀取,無寫入操作
- Mock 數據範例:
const mockDashboardStats: DashboardStats = {
company: {
registered: { period_count: 12, total_count: 678 },
published_jobs: { period_count: 5, total_count: 345 },
},
user: {
registered: { period_count: 45, total_count: 2345 },
published_resumes: { total_count: 876 },
applications: { period_count: 23, total_count: 4567 },
},
foreigner: {
registered: { period_count: 18, total_count: 890 },
published_resumes: { total_count: 342 },
applications: { period_count: 11, total_count: 1234 },
},
cached_at: '2026-03-13T10:00:00+08:00',
};
12. 實作備註(Implementation Notes)
- 禁止事項:
- ❌ 本文件不直接定義最終 API path/method,僅提供 Hints
- ❌ 不直接修改
prd/business-rules.md,新規則先在「商業規則對齊」描述,再由人決定是否回寫
- 注意事項:
- 欄位命名與 Storybook/TS interface 一致
- 使用 Naive UI Admin 既有元件風格(NCard、NStatistic、NDatePicker 等)
- 外籍判定的
work_identity_type code 值需與後端 dict_work_identity_type 資料表對齊
- 「發布職缺數」計算不重複職缺:同一職缺多次上架/下架只算 1 次
- 「履歷公開數」與「外籍履歷公開數」因無 publish 時戳,不受時間篩選影響,僅顯示當下總數
- 快取策略:server-side cache,以
start_date + end_date 為 key,TTL 1 小時
13. 下一步(Next Steps)
- 與後端對齊
dict_work_identity_type 的實際 code 值
- 與後端確認「發布職缺」的歷史狀態是否有紀錄(若無,需調整計算邏輯)
- 產出 Storybook mockup 並補上連結
- 與後端對齊 API 規格後實作
- 未來版本:趨勢圖表、CSV 匯出、自動寄報表、公司狀態篩選
文件結束