Files
CFDivePlatform/openspec/specs/review-lifecycle/spec.md
T
a620906209 0cd1047b10
Run Tests / test (pull_request) Successful in 30s
docs(openspec): 補齊所有 spec 缺少的 Purpose section 與規格標頭
repo 內 35/38 份既有 spec 都是舊版歸檔流程留下的原始 delta 內容(`##
ADDED Requirements`,缺標題與 Purpose),openspec CLI 現版本嚴格驗證
(--strict)會報錯或警告。逐一補上:

- 缺標題/Purpose 的 30 份:加上 `# <name> Specification` 標題 + 依內容
  撰寫的 Purpose 段落,`## ADDED Requirements` 改回 `## Requirements`
- compose-cloud-baseline、scheduler-container:已有標題與
  Requirements,只補 Purpose 包裝
- provider-verification:已有標題與 Purpose,只需把
  `## ADDED Requirements` 改回 `## Requirements`
- admin-user-management、notification-email:各有一條 requirement 缺
  SHALL/MUST 關鍵字(純敘述句或表格),補上規範用語,內容不變

`openspec validate --specs --strict`:38/38 全過(原本 4/38)。純文件
補齊,未變更任何 requirement 的實質內容或行為描述。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011LpcY9b7y9x4fusHBTXciQ
2026-08-03 04:11:06 +08:00

5.8 KiB
Raw Blame History

review-lifecycle Specification

Purpose

定義評價系統的完整生命週期:新增/修改/刪除評價的資格驗證、課程統計即時重算、匿名公開顯示與分頁排序,以及評價觸發的 Provider 通知。

Requirements

Requirement: Member 新增評價

已完成特定課程的 Member SHALL 能對該課程留下一次評價(星等 + 文字)。

Scenario: 成功新增評價

  • WHEN 已登入 Member 送出 POST /api/member/reviews,包含 diving_offer_idrating15 整數)、comment(非空字串),且系統查詢 bookings JOIN course_schedules 找到至少一筆 member_id = X AND diving_offer_id = Y AND status = 'completed'
  • THEN 系統建立 Review,回傳 201

Scenario: 未完成課程不可評價(資格驗證)

  • WHEN Member 送出評價,但 bookings 中不存在任何 status = 'completed' 且對應 diving_offer_id 的紀錄
  • THEN 系統回傳 403,message:「須完成此課程後才能評價」

Scenario: 每門課只能評一次

  • WHEN reviews 中已存在同一 member_id + diving_offer_id 的紀錄
  • THEN 系統回傳 422(非 409),message:「已評價,如需修改請使用編輯功能」

Scenario: 星等範圍驗證

  • WHEN rating 不在 15 之間
  • THEN 系統回傳 422

Requirement: 評價後即時更新課程統計

Member 新增、修改或刪除評價時,系統 SHALL 在同一 DB transaction 內重算 diving_offers.ratingreviews。Provider 或 Admin 手動標記 booking 為 completed 亦同樣觸發評價資格。

Scenario: 新增評價後重算

  • WHEN Review 建立成功
  • THEN diving_offers.rating = ROUND(AVG(rating), 1)diving_offers.reviews = COUNT(*) 即時更新

Scenario: 刪除評價後重算

  • WHEN Review 被 Member 或 Admin 刪除
  • THEN ratingreviews 在同一 transaction 內重算;若剩餘 0 筆評價,rating = 0reviews = 0

Requirement: Member 修改評價

Member SHALL 能修改自己的評價,系統保留最近一次修改前的版本並標記已修改。

Scenario: 成功修改評價

  • WHEN Member 送出 PUT /api/member/reviews/{id},包含新的 ratingcomment
  • THEN 系統將舊版 rating / comment 寫入 review_edits(若已存在則覆蓋);更新 Review 內容;將 is_edited = true;重算課程統計

Scenario: 只能修改自己的評價

  • WHEN Member 嘗試修改他人的評價
  • THEN 系統回傳 403

Requirement: Member 刪除評價

Member SHALL 能刪除自己的評價,Admin SHALL 能刪除任何評價。

Scenario: Member 刪除自己的評價

  • WHEN Member 送出 DELETE /api/member/reviews/{id}
  • THEN 系統刪除 Review 及對應的 review_edits / review_votes;重算課程統計

Scenario: Admin 刪除任意評價

  • WHEN Admin 送出 DELETE /api/admin/reviews/{id}
  • THEN 系統刪除 Review 及關聯資料;重算課程統計

Scenario: 只能刪除自己的評價(非 Admin)

  • WHEN 非 Admin Member 嘗試刪除他人評價
  • THEN 系統回傳 403

Requirement: 評價公開顯示(匿名)

任何人(含未登入)SHALL 能查看課程評價列表,評價人統一顯示為「匿名潛水者」。Provider 在 Coach Portal 亦可查看自己課程的評價(只讀)。評價列表 SHALL 支援分頁,預設每頁 20 筆,最大 50 筆。

Scenario: 取得評價列表(含 summary,含分頁)

  • WHEN 任何人送出 GET /api/diving-offers/{id}/reviews?sort=helpful|rating|newest&page=1&per_page=20
  • THEN 系統回傳 summary(平均星等、總數、1–5 星分布)與分頁後的 reviews 列表;reviewer_name 一律為「匿名潛水者」;已登入 Member 額外回傳 is_mine;未登入 has_voted 固定為 falseis_mine 欄位省略;回傳包含分頁 metacurrent_pagelast_pageper_pagetotal

Scenario: per_page 超出上限時截斷

  • WHEN 請求帶有 per_page=200
  • THEN 系統以 per_page=50 處理,不回傳錯誤

Scenario: 三種排序

  • WHEN sort=helpful(預設)
  • THENhelpful_count DESC, created_at DESC 排序
  • WHEN sort=rating
  • THENrating DESC, created_at DESC 排序
  • WHEN sort=newest
  • THENcreated_at DESC 排序

Scenario: votes 透過 eager loading 查詢

  • WHEN 已登入 Member 送出評價列表請求
  • THEN has_voted 欄位透過 eager loaded votes collection 判斷,不額外發 SQL 查詢

Requirement: 課程完成標記(評價資格觸發)

Provider 或 Admin SHALL 能手動將 confirmed 預約標記為 completed,讓 Member 可立即評價,不需等待排程。

Scenario: Provider 手動完成

  • WHEN Provider 送出 PUT /api/provider/bookings/{id}/completeBooking status 為 confirmed
  • THEN Booking status 改為 completedMember 即可對該課程送出評價

Scenario: Admin 手動完成

  • WHEN Admin 送出 PUT /api/admin/bookings/{id}/completeBooking status 為 confirmed
  • THEN Booking status 改為 completed

Requirement: 評價建立後觸發 Provider 通知

評價系統 SHALL 在 Member 成功建立評價後,通知課程所屬 Provider(僅站內通知,不寄 Email)。ReviewService::create() MUST 在評價資料儲存成功後觸發通知,以 try/catch 包裹確保主業務不受影響。

Scenario: 評價成功送出

  • WHEN ReviewService::create() 建立新評價,reviews 資料表寫入成功
  • THEN $provider->notify(new ReviewReceivedNotification($review)) 被呼叫,Provider 站內通知新增一筆

Scenario: 通知失敗不影響評價建立

  • WHEN notify 呼叫失敗(例:DB 寫入通知失敗)
  • THEN 評價資料已正確儲存,HTTP response 成功回傳,錯誤記錄至 log