實作 openspec change provider-verification-workflow(25/25 tasks): - is_verified 升級為 verification_status 四狀態機(unsubmitted/pending/ approved/rejected),migration 自動轉換既有資料,API 以 accessor 保留 is_verified 相容輸出 - 教練端:證照上傳(≤3 張、複用 CompressesImages)、送審、駁回原因 顯示與重送(/coach/verification 新頁面) - Admin 端:審核佇列、通過/駁回(原因必填)、撤銷 approved;移除 toggle-verified 端點(防繞過狀態機);裁決後 flush 課程快取 - 通知:審核通過/駁回(站內+Email,駁回含原因) - 可見性與預約入口改判 approved(行為等價) - 測試 +18(ProviderVerificationTest 10、AdminVerificationTest 8), 既有 4 個測試檔 helper 遷移;Swagger 同步 - 規格同步:provider-verification 全面改寫、admin-user-management toggle 段落改為移除聲明 容器內全套件 173 passed / 439 assertions。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4.4 KiB
ADDED Requirements
Requirement: 教練驗證狀態機
provider_profiles.verification_status SHALL 為四狀態字串:unsubmitted(註冊預設)、pending、approved、rejected。合法轉移僅限:unsubmitted→pending(送審)、pending→approved(通過)、pending→rejected(駁回)、rejected→pending(重新送審,同時清空 rejection_reason)、approved→rejected(撤銷,原因必填)。原 boolean is_verified 欄位移除,API 輸出以 accessor 保留 is_verified(= status 為 approved)。
Scenario: 新教練註冊預設未送審
- WHEN 教練完成註冊
- THEN
verification_status = unsubmitted,不出現在 Admin 待審佇列
Scenario: 非法轉移被拒絕
- WHEN 嘗試對
unsubmitted教練執行 approve,或對approved教練執行 approve - THEN 回傳 HTTP 422,狀態不變
Requirement: 教練上傳證照與送審
教練 SHALL 能於後台上傳 1~3 張證照圖片(jpeg/png/webp、≤10MB,伺服器端壓縮為 .jpg,存 providers/{user_id}/certifications/)並送出審核。證照僅於 unsubmitted / rejected 狀態可增刪;pending / approved 狀態鎖定。送審需至少 1 張證照。
Scenario: 上傳證照
- WHEN
unsubmitted教練POST /api/provider/verification/certifications上傳合法圖片且現有 < 3 張 - THEN 壓縮儲存並建立
provider_certifications紀錄,回傳圖片資訊
Scenario: 超過 3 張上限
- WHEN 教練已有 3 張證照再上傳
- THEN 回傳 HTTP 422
Scenario: 送審成功
- WHEN 教練至少有 1 張證照,
POST /api/provider/verification/submit - THEN 狀態轉為
pending,rejection_reason清空
Scenario: 無證照不可送審
- WHEN 教練無任何證照即送審
- THEN 回傳 HTTP 422,狀態不變
Scenario: pending 期間證照鎖定
- WHEN
pending或approved教練嘗試上傳或刪除證照 - THEN 回傳 HTTP 422
Scenario: 查詢自身驗證狀態
- WHEN 教練
GET /api/provider/verification - THEN 回傳
status、rejection_reason、certifications[](id、url)
Requirement: Admin 審核佇列與裁決
Admin SHALL 能查詢審核佇列(GET /api/admin/verifications?status=pending,預設 pending,含教練資料與證照 URL),並對 pending 教練執行通過(PUT /api/admin/verifications/{userId}/approve)或駁回(PUT /api/admin/verifications/{userId}/reject,reason 必填、max 500)。Admin SHALL 能駁回 approved 教練(撤銷驗證,原因必填)。裁決後 SHALL flush diving_offers 快取(可見性立即生效)。原 PUT /api/admin/providers/{id}/toggle-verified 端點 SHALL 移除。
Scenario: 通過審核
- WHEN Admin 對 pending 教練執行 approve
- THEN 狀態轉
approved,教練課程立即恢復公開可見性
Scenario: 駁回需附原因
- WHEN Admin 執行 reject 未帶
reason - THEN 回傳 HTTP 422,狀態不變
Scenario: 撤銷已通過教練
- WHEN Admin 對 approved 教練執行 reject 並附原因
- THEN 狀態轉
rejected,課程立即從公開列表消失;既有預約照常(沿用既定政策)
Scenario: 舊 toggle 端點已移除
- WHEN 任何人請求
PUT /api/admin/providers/{id}/toggle-verified - THEN 回傳 HTTP 404
Requirement: 審核結果通知
系統 SHALL 於 approve / reject 後通知該教練(站內 + Email):通過通知告知課程已可公開曝光;駁回通知包含駁回原因。通知失敗不阻斷審核主流程。
Scenario: 通過通知
- WHEN Admin approve
- THEN 教練收到站內通知與 Email,內容含審核通過訊息
Scenario: 駁回通知含原因
- WHEN Admin reject 並附原因
- THEN 教練收到的通知內容包含該原因
MODIFIED Requirements
Requirement: 未驗證教練的課程不對公開端點曝光
公開課程端點(列表、詳情、schedules、reviews)SHALL 僅曝光 provider_id 為 null 或教練 verification_status = 'approved' 的課程(原以 is_verified = true 判定,語意等價)。POST /api/member/bookings 的可預約檢查同步改以 approved 判定。其餘行為(404、422、既有預約不受影響)不變。
Scenario: 非 approved 狀態一律不曝光
- WHEN 課程教練的狀態為 unsubmitted / pending / rejected
- THEN 公開端點不回傳該課程,新預約被拒