◆ wport | pm_34

薪資幣別切換 Mockup PRD(PM_34)

薪資幣別切換

來源 doc/feature/pm_34/edit-job-salary-currency-mockup.md

薪資幣別切換 Mockup PRD(PM_34)

此文件依 prd-gen 訪談結果撰寫,供 backend-api-spec-generator 與前後端實作對齊。


1. 文件資訊

  • 文件類型:Mockup 需求規格書(前後端共用視圖)
  • 適用對象:前端開發、後端開發、產品、QA
  • 最後更新:2026/04/14
  • 版本:3.0.0
  • 對應 StorybookMockups/Recruitment/EditJobSalaryCurrency
  • 建立日期:2026/04/10

2. 開發進度與設計來源

開發進度

  • Storybook Mockup:✅ 已完成(commit 71e7f32
  • 前端 PR #:TBD
  • 後端 PR #:TBD

設計來源

  • Figma 連結:無
  • 既有畫面參照
    • edit-job(熱火數碼現行前端畫面)
    • 既有職缺列表/職缺詳情/職缺搜尋頁
    • 既有履歷編輯頁(期望待遇)

3. 模擬頁面摘要(Mockup Summary)

3.1 功能概述

  • 功能名稱:薪資幣別切換(職缺 + 履歷)
  • 主要使用者角色
    • 企業 HR/招募人員(編輯職缺薪資)
    • 求職者(編輯履歷期望待遇、使用搜尋篩選)
  • 核心目標
    • 解決薪資幣別固定 NTD 造成海外市場無法使用的問題
    • 支援全球化招募(先以越南市場擴張為主要動機)
    • 保證「編輯值、儲存值、顯示值、搜尋條件」幣別一致

3.2 範圍界定

  • PRD 文件策略(同一份文件、三個模組)
    • 本需求同時涵蓋 edit-jobjob-searchresume-edit 三個模組。
    • 為避免規則分散與版本不一致,統一收斂於同一份 PRD 管理(single source of truth)。
    • 文件內依模組分段描述;實作與驗收可拆分任務,但共用同一套幣別規則與資料定義。
  • 包含範圍
    • 職缺端:edit-job 可編輯薪資幣別,預設值依「公司所在地」
    • 職缺端:列表/詳情/搜尋結果顯示幣別一致
    • 搜尋端:薪資篩選可選幣別(同幣別篩選)
    • 履歷端:期望待遇可編輯薪資幣別(與職缺同一幣別規則)
    • 幣別清單:支援 ISO 4217 全量法定貨幣
  • 排除範圍
    • 不做即時匯率換算
    • 不做跨幣別換算比較/排序
    • 不做多幣別同時顯示(單筆資料只存單一幣別)

3.3 成功條件

  • 企業可成功上架非 NTD 幣別職缺
  • 職缺與履歷皆可正確儲存與呈現 ISO 幣別代碼對應
  • 搜尋可用幣別條件過濾職缺(不做換算)
  • 上線後追蹤指標:非 NTD 職缺數量成長

4. 商業規則對齊(Business Rules Alignment)

4.1 本功能使用到的業務規則

規則 ID規則摘要是否關鍵備註
BR-008職缺發布條件(必填欄位)✅ 是standard salary 必填(含金額與幣別)
BR-009職缺狀態管理與可見性✅ 是幣別異常時職缺需轉下架
BR-015職缺搜尋顯示條件✅ 是搜尋新增幣別條件(同幣別)
BR-NEW-CURRENCY-1幣別預設策略✅ 是預設依公司所在地推導
BR-NEW-CURRENCY-2幣別異常處理✅ 是不支援 code 清空並要求重填

4.2 補充說明(新增動作上限/約束)

  • 本功能無「新增資源」上限議題;幣別可選範圍為 ISO 4217 全量(不限制 30 種)。
  • 儲存層僅存 ISO code(例如 TWDVND),不存匯率資料。

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

5.1 實體列表

實體名稱說明來源頁面/區塊
CurrencyMasterISO 4217 幣別主檔後端設定 / 共用查詢
JobSalaryInfo職缺薪資與幣別edit-job、職缺顯示、搜尋
ResumeExpectedSalary履歷期望待遇與幣別履歷編輯頁

5.2 實體欄位定義(TypeScript 介面)

type CurrencyCode = string; // ISO 4217, e.g. "TWD", "VND", "USD"

interface CurrencyMaster {
  code: CurrencyCode;
  name_en: string;
  name_zh?: string;
  symbol?: string;
  status: "active" | "deprecated";
}

interface JobSalaryInfo {
  job_id: string;
  salary_mode: "standard" | "custom";
  salary_min?: number | null;
  salary_max?: number | null;
  salary_period?: "hourly" | "monthly" | "yearly" | null;
  salary_currency_code?: CurrencyCode | null;
}

interface ResumeExpectedSalary {
  resume_id: string;
  expected_salary_mode: "standard" | "custom";
  expected_salary_min?: number | null;
  expected_salary_max?: number | null;
  expected_salary_period?: "hourly" | "monthly" | "yearly" | null;
  expected_salary_currency_code?: CurrencyCode | null;
}

6. 畫面區塊與資料需求(UI Sections & Data Needs)

6.1 區塊列表

區塊 ID區塊名稱說明
SEC-1Edit Job Salary職缺薪資欄位可選幣別
SEC-2Job List / Job Detail顯示幣別與薪資一致
SEC-3Job Search Filter幣別篩選條件
SEC-4Resume Expected Salary履歷期望待遇可選幣別

6.2 各區塊資料需求

SEC-1 Edit Job Salary

  • 初始值:依公司所在地預設幣別
  • 儲存值:salary_currency_code(ISO code)
  • 驗證:salary_mode=standard 時,薪資金額 + 幣別必填

SEC-2 Job List / Job Detail

  • 顯示值:由職缺儲存值回填,不可自行推導
  • 異常值:若 code 不存在主檔,不顯示錯誤碼;按異常規則處理(見第 12 節)

SEC-3 Job Search Filter

  • 幣別下拉來源:CurrencyMaster(active)
  • 僅同幣別篩選,不做換算比較

SEC-4 Resume Expected Salary

  • 與職缺同一幣別清單
  • expected_salary_mode=custom 時,薪資金額 + 幣別必填

7. 使用者動作與後端需求(User Actions & Backend Needs)

動作 ID動作名稱類型需要後端涉及實體說明
ACT-1開啟 edit-job查詢(Read)✅ 是JobSalaryInfo, CurrencyMaster回傳薪資資料 + 幣別清單 + 預設幣別
ACT-2編輯職缺幣別寫入(Write)✅ 是JobSalaryInfo儲存 ISO code
ACT-3搜尋條件選擇希望待遇幣別查詢(Read)✅ 是CurrencyMasterSearch filter 幣別下拉來源
ACT-4搜尋結果卡片顯示薪資幣別查詢(Read)✅ 是JobSalaryInfoJob card 薪資需帶幣別
ACT-5Job 頁顯示薪資幣別查詢(Read)✅ 是JobSalaryInfoJob detail 薪資需帶幣別
ACT-6編輯履歷期望待遇幣別寫入(Write)✅ 是ResumeExpectedSalarycustom 模式必填
ACT-7顯示履歷與快照履歷幣別查詢(Read)✅ 是ResumeExpectedSalaryResume edit/preview 都需顯示幣別
ACT-8不支援幣別異常處理狀態轉換✅ 是JobSalaryInfo清空幣別並下架職缺

邊界場景(逐一)

  1. 再次進入編輯頁:沿用既有 unsaved 提示;不新增草稿機制。
  2. 不支援幣別 code:清為空值,要求重新選擇;若是職缺則轉下架。
  3. 未登入:可看職缺幣別,不可編輯職缺/履歷幣別。
  4. 手機/桌機:都必須提供可用幣別選擇與一致驗證。

8. API Hints(提示用,非最終 API 設計)

8.1 資料讀取需求(Read)

  • HINT-GET-1:取得幣別主檔

    • 輸入:{ status?: "active" }
    • 輸出:CurrencyMaster[]
  • HINT-GET-2:取得職缺編輯資料(含幣別)

    • 輸入:{ job_id }
    • 輸出:JobSalaryInfo + default_currency_code
  • HINT-GET-3:取得履歷期望待遇(含幣別)

    • 輸入:{ resume_id }
    • 輸出:ResumeExpectedSalary
  • HINT-GET-4:搜尋職缺條件初始化(希望待遇 filter)

    • 輸入:{ locale?, user_type? }
    • 輸出:currency_filter_options: CurrencyMaster[]
    • 說明:搜尋頁的「希望待遇」幣別下拉需由 API 提供,不寫死前端常數
  • HINT-GET-5:搜尋職缺列表(卡片)

    • 輸入:{ keyword?, location?, salary_min?, salary_max?, salary_currency_code? }
    • 輸出:jobs[].salary_{min,max,period,currency_code}
    • 說明:當帶入 salary_currency_code 時,採同幣別過濾;每張 job card 需顯示該幣別
  • HINT-GET-6:取得職缺詳情(Job 頁)

    • 輸入:{ job_id }
    • 輸出:JobSalaryInfo
    • 說明:Job 頁薪資顯示必須使用資料內 salary_currency_code,不得前端推導預設幣別
  • HINT-GET-7:取得履歷快照資料(Preview / Snapshot)

    • 輸入:{ resume_id }{ snapshot_id }
    • 輸出:resume_expected_salary.{ expected_salary_min, expected_salary_max, expected_salary_period, expected_salary_currency_code }
    • 說明:履歷編輯態與快照態都要顯示幣別,格式規則一致

8.2 資料寫入需求(Write)

  • HINT-MUTATION-1:更新職缺薪資

    • 輸入:{ job_id, salary_mode, salary_min, salary_max, salary_period, salary_currency_code }
    • 驗證:salary_mode=standard 時,金額與幣別必填,code 必須存在 CurrencyMaster(active|deprecated) 策略內
  • HINT-MUTATION-2:更新履歷期望待遇

    • 輸入:{ resume_id, expected_salary_mode, expected_salary_min, expected_salary_max, expected_salary_period, expected_salary_currency_code }
    • 驗證:expected_salary_mode=custom 時,金額與幣別必填

8.3 本次 API 實作範圍(新增確認)

  • 除了 edit-jobresume-edit 的寫入 API,本次需一併涵蓋以下讀取能力:
    1. search job 的希望待遇 filter 幣別選擇來源
    2. search job 結果卡片薪資幣別顯示
    3. job 詳情頁薪資幣別顯示
    4. resumeresume snapshot 的期望待遇幣別顯示

9. 導航 / Storybook Map

  • Storybook 標題Mockups/Recruitment/EditJobSalaryCurrency
  • Story IDmockups-recruitment20-edit-job-salary-currency--default
  • Stories 路徑storybook/src/stories/mockups/recruitment/EditJobSalaryCurrency.stories.ts
  • Mockup 元件storybook/src/mockups/edit-job-salary-currency-demo.vue
  • Storybook(Publish URL)https://storybook.wport.me/?path=/docs/mockups-recruitment20-edit-job-salary-currency--docs
  • 對應 production 路由(示意)
    • company/jobs/:jobId/edit
    • jobs/:jobId
    • jobs/search
    • resume/edit

三個模組的具體前端頁面

  1. Edit Job Salary

    • Route: company/jobs/:jobId/edit
    • Source page: W101-Web/main-web/packages/recruitment/src/views/jobs/edit-job/index.vue
    • Related components:
      • W101-Web/main-web/packages/recruitment/src/components/JobManager/JobDescriptionCard.vue
      • W101-Web/main-web/packages/recruitment/src/components/JobManager/RecruitmentConditionsCard.vue
      • W101-Web/main-web/packages/recruitment/src/components/JobManager/ApplicationMethodCard.vue
  2. Job Search

    • Route: jobs/search
    • Source page: W101-Web/main-site/pages/jobs/index.vue
    • Related components:
      • W101-Web/main-site/components/SearchFilterCard/index.vue
      • W101-Web/main-site/components/job/JobCard.vue
  3. Resume Edit (Expected Salary)

    • Route: resume/edit
    • Source page: W101-Web/main-web/packages/user/src/components/ResumeSections/JobPreference/index.vue
    • Related component:
      • W101-Web/main-web/packages/user/src/components/ResumeSections/JobPreference/preview-mode.vue

Mockup 實作摘要

  • 類型:existing_increment(既有頁面增量)
  • 母版頁W101-Web/main-web/packages/recruitment/src/views/jobs/edit-job/index.vue
  • Delta:在「希望待遇」欄位的 compensation_scheme=standard 模式下,原「元」文字位置替換為 ISO 4217 幣別下拉選單(filterable,~130 筆法定貨幣)
  • 技術手段:Vue <Teleport> 注入到母版元件 DOM 內部,像素級對齊(Playwright 驗證 diff=0px)
  • 條件顯示:僅 compensation_scheme === 'standard' 時可見

10. Flowcharts(User / System / Navigation)

10.1 User Flow(共用子流程:幣別載入與驗證)

flowchart TD
    A[使用者進入職缺或履歷編輯頁] --> B[載入幣別主檔與當前資料]
    B --> C{是否有既有幣別?}
    C -->|有| D[顯示既有幣別]
    C -->|無| E[依公司所在地預設幣別]
    D --> F[使用者可切換幣別]
    E --> F
    F --> G{模式檢查}
    G -->|standard/job| H[薪資與幣別必填]
    G -->|custom/resume| I[薪資與幣別必填]
    H --> J[提交儲存]
    I --> J
    J --> K[成功後顯示於列表/詳情/search/履歷]

10.2 System Flow(前端狀態與資料流)

sequenceDiagram
    participant UI as 前端頁面
    participant API as Backend API
    participant DB as Database

    UI->>API: GET /currency-master
    API->>DB: query currency master (ISO 4217)
    DB-->>API: currency list
    API-->>UI: currency list

    UI->>API: GET job/resume salary payload
    API-->>UI: payload + default_currency_code

    UI->>API: PATCH salary payload
    API->>API: validate mode + required + currency code
    API->>DB: persist salary fields
    DB-->>API: ok
    API-->>UI: success

10.3 Navigation Flow(入口與狀態約束)

入口狀態欄位約束預期行為
edit-jobsalary_mode=standardsalary + currency 必填未填不可上架
resume-editexpected_salary_mode=customexpected salary + currency 必填未填不可儲存該段
job-searchselected_currency不做換算僅同幣別結果
job-detail/listcurrency_code 異常code 不支援顯示前觸發資料修正流程
flowchart LR
    N1[入口: edit-job / resume-edit / search] --> N2[讀取資料]
    N2 --> N3{幣別 code 可用?}
    N3 -->|是| N4[正常顯示與操作]
    N3 -->|否| N5[清空幣別 + 要求重填]
    N5 --> N6{是否職缺?}
    N6 -->|是| N7[職缺轉下架]
    N6 -->|否| N8[履歷停留編輯狀態]

11. Mock Data Schema(Mock 資料結構)

{
  "currency_master": [
    { "code": "TWD", "name_en": "New Taiwan Dollar", "status": "active" },
    { "code": "VND", "name_en": "Vietnamese Dong", "status": "active" },
    { "code": "USD", "name_en": "US Dollar", "status": "active" }
  ],
  "job_salary_info": {
    "job_id": "job_123",
    "salary_mode": "standard",
    "salary_min": 45000,
    "salary_max": 60000,
    "salary_period": "monthly",
    "salary_currency_code": "VND"
  },
  "resume_expected_salary": {
    "resume_id": "resume_456",
    "expected_salary_mode": "custom",
    "expected_salary_min": 30000,
    "expected_salary_max": 50000,
    "expected_salary_period": "monthly",
    "expected_salary_currency_code": "USD"
  }
}

12. 實作備註(Implementation Notes)

  • 儲存規範:只存 ISO code,不做匯率表與換算欄位。
  • 顯示規範:UI 可顯示 NTD,但資料層建議統一 TWD(mapping 由前後端共識維護)。
  • 預設規則:職缺預設幣別依公司所在地;查無對應時 fallback TWD
  • 異常規則(已確認):若遇到不支援幣別 code,清空該值並要求使用者重選;職缺自動轉下架避免錯誤揭露。
  • 既有 unsaved 流程:沿用現有未儲存離頁提醒,不新增中斷還原機制。
  • 資料修正建議:加一支後台修正腳本檢查 invalid code 並標記待補填。

13. 下一步(Next Steps)

  • Storybook Mockup(SEC-1 edit-job) ✅ 已完成
  • 定稿 CurrencyMaster 資料來源(靜態檔或後台可維護表)。
  • 先出 schema(你已指定),再進 API 與前端串接。
  • 產出 QA 測試矩陣:職缺端、履歷端、搜尋端、異常 code 下架情境。
  • 上線後觀測 KPI:非 NTD(非 TWD)職缺數量。

文件結束