chore(openspec): 歸檔 feature-test-coverage、provider-verification-workflow 變更
Run Tests / test (pull_request) Failing after 1m53s

兩個 change 全任務完成(feature-test-coverage 40/40、provider-verification-workflow 48/48)。

同步規格:
- feature-test-coverage/spec.md 補齊 ## Requirements 區塊標頭(結構修正)
- Admin 教練審核 scenario 改為 approve 端點(toggle-verified 已由 #36 移除)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 19:19:52 +08:00
parent 4383239bab
commit 80f5cf179f
12 changed files with 6 additions and 3 deletions
@@ -0,0 +1,14 @@
## MODIFIED Requirements
### Requirement: 管理員切換教練驗證狀態
(本 requirement 由 provider-verification 的「Admin 審核佇列與裁決」取代)
`PUT /api/admin/providers/{id}/toggle-verified` SHALL 移除——單鍵切換允許繞過審核狀態機(無原因駁回、未送審直接通過)。教練驗證狀態的變更一律透過 `PUT /api/admin/verifications/{userId}/approve|reject`
#### Scenario: toggle 端點回 404
- **WHEN** Admin 請求 `PUT /api/admin/providers/{id}/toggle-verified`
- **THEN** 回傳 HTTP 404
#### Scenario: 教練列表仍顯示驗證狀態
- **WHEN** Admin 請求 `GET /api/admin/providers`
- **THEN** 每筆教練資料包含 `verification_status`(與相容用 `is_verified` accessor
@@ -0,0 +1,84 @@
## 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、reviewsSHALL 僅曝光 `provider_id` 為 null 或教練 `verification_status = 'approved'` 的課程(原以 `is_verified = true` 判定,語意等價)。`POST /api/member/bookings` 的可預約檢查同步改以 `approved` 判定。其餘行為(404、422、既有預約不受影響)不變。
#### Scenario: 非 approved 狀態一律不曝光
- **WHEN** 課程教練的狀態為 unsubmitted / pending / rejected
- **THEN** 公開端點不回傳該課程,新預約被拒