Files
a620906209 da48a3652d feat:實作 Coach Portal — 教練後台課程管理
後端:
- Migration:diving_offers 新增 provider_id(nullable FK)
- Migration:users.role ENUM 加入 provider 值
- Migration:diving_offers.spot 改為 nullable
- AuthController:registerProvider business_name 改為選填
- AuthController:updateProviderProfile 補上 certifications / dive_sites / services / facilities / website / social_media
- ProviderOfferController:教練課程 CRUD(index/show/store/update/destroy),實作 provider_id 所有權不變式(404 → 403 兩步驟)

前端(frontend/):
- coachAuth store、coachAxios(獨立於 member auth)
- /coach/* 路由群組 + beforeEach guard
- CoachNavBar、CoachLayout(教練頁隱藏會員 NavBar)
- LoginView、RegisterView、DashboardView(表格 + 刪除確認)
- OfferFormView(新增/編輯共用)、ProfileView

OpenSpec:
- openspec/config.yaml 補入專案 context 與 rules
- 新增 specs:coach-offers-api / coach-portal-ui / provider-auth
- 更新 spec:diving-offers-api 加入 provider_id
- 歸檔:openspec/changes/archive/2026-05-10-coach-portal

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-10 03:34:14 +08:00

2.2 KiB
Raw Permalink Blame History

ADDED Requirements

Requirement: 課程列表 API

後端 SHALL 提供公開的 GET /api/diving-offers endpoint,回傳分頁的潛水課程列表,支援關鍵字搜尋與篩選,無需認證即可存取。response 中每筆課程包含 provider_id 欄位(可為 null)。

Scenario: 取得全部課程列表

  • WHEN 客戶端發送 GET /api/diving-offers 且不帶任何參數
  • THEN 回傳 HTTP 200body 包含 { data: [...], meta: { total, per_page, current_page } },預設每頁 12 筆,每筆資料含 provider_id

Scenario: 依關鍵字搜尋課程

  • WHEN 客戶端發送 GET /api/diving-offers?q=墾丁
  • THEN 回傳 titlelocation 包含「墾丁」的課程列表

Scenario: 依地區篩選課程

  • WHEN 客戶端發送 GET /api/diving-offers?region=南部
  • THEN 只回傳 region 欄位等於「南部」的課程

Scenario: 依標籤篩選課程

  • WHEN 客戶端發送 GET /api/diving-offers?tag=初學者
  • THEN 只回傳 tag 欄位包含「初學者」的課程

Scenario: 分頁參數

  • WHEN 客戶端發送 GET /api/diving-offers?page=2&per_page=6
  • THEN 回傳第 2 頁資料,每頁 6 筆,meta 包含正確的分頁資訊

Requirement: 課程詳情 API

後端 SHALL 提供公開的 GET /api/diving-offers/{id} endpoint,回傳單一課程完整資訊,無需認證即可存取。

Scenario: 取得存在的課程詳情

  • WHEN 客戶端發送 GET /api/diving-offers/1(該 id 存在)
  • THEN 回傳 HTTP 200body 包含 { data: { id, title, location, spot, rating, reviews, price, badges, description, tag, region, created_at } }

Scenario: 課程不存在

  • WHEN 客戶端發送 GET /api/diving-offers/99999(該 id 不存在)
  • THEN 回傳 HTTP 404body 包含 { message: "課程不存在" }

Requirement: CORS 允許前端 Origin

後端 SHALL 在 config/cors.php 中允許來自前端開發 originhttp://localhost:5173)的跨域請求。

Scenario: 前端跨域請求課程列表

  • WHEN 瀏覽器從 http://localhost:5173 發送 GET /api/diving-offers
  • THEN 後端回應包含正確的 CORS header,瀏覽器不阻擋請求