◆ wport | pm_31

Site Admin Dashboard Mockup PRD(給後端 API 規格產生器使用)

Site Admin Dashboard

來源 doc/feature/pm_31/siteadmin-dashboard-mockup.md

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 欄位為準,符合以下六種之一即計為外籍使用者:
    1. 僑生/港澳台(在學)
    2. 外國籍留學生(在學中)
    3. 僑外生(畢業尋職中)
    4. 外國專業人士(在台工作中)
    5. 獲准居留之新住民
    6. 移工(留才久用候選人)
  • 使用者修改身分類型後,以查詢當下的身分為準,歷史不追溯。
  • 本功能為純讀取,不涉及任何寫入操作,無新增動作上限需求。

5. 資料實體與欄位(Data Entities & Fields)

backend-api-spec-generator 會依此節與 Storybook 的 interface/mock data 推導 API 結構。 欄位命名請與 Storybook/TS 介面一致。

5.1 實體列表

實體名稱說明來源頁面/區塊
DashboardStatsDashboard 統計數據回傳結構整個 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_dateCOUNT(company.*)
發布職缺數區間內曾有 published 狀態的不重複職缺數(同一職缺多次上架/下架只算 1)全站曾有 published 狀態的不重複職缺數

使用者區塊

指標分子(區間內)分母(全站)
使用者數user.created_at BETWEEN start_date AND end_dateCOUNT(user.*)
履歷公開數⚠️ 無時戳,不計算區間當下 resume.published_status = 1 的履歷數量
應徵次數job_application.created_at BETWEEN start_date AND end_dateCOUNT(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 匯出、自動寄報表、公司狀態篩選

文件結束