docs:補全所有 API 端點 Swagger 文件(73 個端點)
Tests / PHP 8.2 (pull_request) Failing after 2s
Tests / PHP 8.3 (pull_request) Failing after 2s
pull requests / uneditable (pull_request_target) Failing after 0s

- 修正 AuthApiDoc.php 路徑錯位(/register/member → /member/register 等)
  及 change-password 方法(Post→Put);補上 POST /logout、GET /user
- 新增 AuthSupplementDoc.php(Google OAuth 2 端點)
- 新增 PublicApiDoc.php(共用 Schema + 公開課程 4 端點)
- 新增 MemberApiDoc.php(預約、評價、通知共 13 端點)
- 新增 ProviderApiDoc.php(課程、圖片、時段、預約管理共 18 端點)
- 新增 AdminApiDoc.php(統計、會員/教練/課程管理共 16 端點)
- 更新 README.md
- 歸檔 swagger-api-docs-completion change,同步主規格

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 01:17:25 +08:00
parent e8cd82cdee
commit 4feeeff94a
22 changed files with 6492 additions and 66 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-24
@@ -0,0 +1,63 @@
## Context
現有 `app/Docs/AuthApiDoc.php` 已建立 Swagger 基礎設定(`@OA\Info`、`@OA\Server`、`@OA\SecurityScheme`)並文件化 15 個 Auth 端點。其餘 61 個端點分散在 8 個 Controller 中,沒有任何 `@OA` 標注。`darkaonline/l5-swagger` 已安裝,執行 `php artisan l5-swagger:generate` 即可重新產生 JSON。
## Goals / Non-Goals
**Goals:**
- 補齊所有 61 個未文件化端點的 `@OA` 標注
- 定義共用 Schema(分頁 meta、統一錯誤格式、DivingOffer、Review、Booking 等)
- 文件依模組分檔,每個新檔對應一個 `app/Docs/*Doc.php`
- 每個端點包含:summary、parameters、request body(POST/PUT)、response(200/201/400/401/403/422)
**Non-Goals:**
- 不修改任何 Controller / Route / Model 邏輯
- 不為尚未實作的端點(金流、訂閱)補文件
## Decisions
### 決策 1:分檔策略 — 依模組建立獨立 Doc 類別
**選擇**:每個模組一個 `app/Docs/*Doc.php`
| 檔案 | 涵蓋端點 |
|------|---------|
| `AuthApiDoc.php` | **修正路徑錯誤**(`/register/member` → `/member/register` 等);補 `POST /logout`、`GET /user` |
| `PublicApiDoc.php` | 公開端點(diving-offers、reviews、schedules) |
| `MemberApiDoc.php` | Member bookings、reviews、helpful、notifications |
| `ProviderApiDoc.php` | Provider offers、images、schedules、bookings |
| `AdminApiDoc.php` | Admin stats、users、offers、bookings、reviews |
| `AuthSupplementDoc.php` | **僅** Google OAuth 2 個端點(`SocialAuthController`) |
**理由**:單一大檔難以維護;按模組分檔讓每個 Doc 類別職責清晰,對應 Controller 結構
**替代方案**:直接在 Controller 方法上加 `@OA` → 拒絕,Controller 文件與業務邏輯混雜,讀性差
### 決策 2:共用 Schema 集中定義在 `PublicApiDoc.php`
共用 Schema(`DivingOfferSchema`、`ReviewSchema`、`BookingSchema`、`PaginationMeta`、`ApiErrorResponse`)集中放在 `PublicApiDoc.php` 頂層 `@OA\Schema` 標注。
**理由**:l5-swagger 掃描所有 `app/` 目錄,Schema 定義位置不影響其他檔案引用;放在 Public 層語意上最自然(核心資料結構)
### 決策 3:Security 標注策略
- 公開端點:不加 `security`
- Member 端點:`security={{"bearerAuth": {}}}`(現有 scheme)
- Provider 端點:`security={{"bearerAuth": {}}}`
- Admin 端點:`security={{"bearerAuth": {}}}`
三個 role 共用同一個 `bearerAuth` scheme,由後端 middleware 區分角色,不需要在 Swagger 定義三個不同 scheme。
## Risks / Trade-offs
- **[Risk] 手寫標注與實際 response 不同步** → 以實際 Controller 程式碼為準手寫;未來有 API 變更時需同步更新 Doc 檔
- **[Risk] Schema 巢狀複雜導致 Swagger UI 渲染慢** → 分頁 response 使用 `allOf` 組合,避免深層巢狀
## Migration Plan
1. 依序建立 5 個新 Doc 檔案
2. 在容器內執行 `php artisan l5-swagger:generate`
3. 開啟 `http://localhost:8080/api/documentation` 確認 UI 正確渲染
4. 確認所有 tag 與端點均出現在 Swagger UI
**Rollback**:直接刪除新增的 Doc 檔案,重新 generate 即可回復到只有 Auth 端點的狀態
@@ -0,0 +1,37 @@
## Why
目前 Swagger 文件僅涵蓋 15 個 Auth 端點,其餘 61 個端點(課程、評價、預約、通知、圖片上傳、Coach Portal、Admin Panel)完全未文件化,導致前後端協作與第三方整合缺乏規格依據。現有 `darkaonline/l5-swagger` 套件已安裝,補全文件的邊際成本低。
## What Changes
- 為所有未文件化端點補上 `@OA` PHPDoc 標注(`app/Docs/` 目錄下依模組分檔)
- 定義完整的 Request / Response Schema(含分頁 meta、錯誤格式)
- 補全 Swagger Security 設定(Bearer token per-role)
- 重新產生 `storage/api-docs/api-docs.json`
**端點範圍(新增 61 個):**
- Public API:GET diving-offers 列表/詳情、reviews、schedules(4)
- Member API:bookings CRUD、reviews CRUD、helpful 投票、notifications(10)
- Provider API:offers CRUD + 圖片、schedules CRUD、bookings 管理(19)
- Admin API:stats、members、providers、offers、bookings、reviews 管理(17)
- Auth 補全:Google OAuth、change-password(3 roles)(7)
## Capabilities
### New Capabilities
- `swagger-public-api`:公開端點 Swagger 文件(diving-offers、reviews、schedules)
- `swagger-member-api`:Member 端點 Swagger 文件(bookings、reviews、notifications)
- `swagger-provider-api`:Provider 端點 Swagger 文件(offers、images、schedules、bookings)
- `swagger-admin-api`:Admin 端點 Swagger 文件(stats、user/offer/booking/review 管理)
- `swagger-auth-supplement`:補全 Auth 端點(Google OAuth、change-password)
### Modified Capabilities
(無,本 change 純為文件補全,不變更任何 API 行為)
## Impact
- 新增:`app/Docs/PublicApiDoc.php`、`MemberApiDoc.php`、`ProviderApiDoc.php`、`AdminApiDoc.php`、`AuthSupplementDoc.php`
- 更新:`storage/api-docs/api-docs.json`(自動產生)
- 不影響任何 Controller、Model、Route、Migration
@@ -0,0 +1,40 @@
## ADDED Requirements
### Requirement: Admin 端點 Swagger 文件
`app/Docs/AdminApiDoc.php` SHALL 文件化所有需要 Admin Bearer token 的管理端點。
#### Scenario: Admin stats 端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** `GET /admin/stats` 端點有文件,response 包含 `total_members`、`total_providers`、`total_offers`;403 非 admin 亦有定義
#### Scenario: Admin 會員管理端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件,標示 `security: bearerAuth`:
- `GET /admin/members`(分頁 response,含 member_profile)
- `GET /admin/members/{id}`
- `PUT /admin/members/{id}/toggle-active`(response: is_active 新狀態)
- `GET /admin/check-member/{id}`
#### Scenario: Admin 教練管理端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件:
- `GET /admin/providers`(分頁 response,含 provider_profile)
- `GET /admin/providers/{id}`
- `PUT /admin/providers/{id}/toggle-active`
- `PUT /admin/providers/{id}/toggle-verified`(response: is_verified 新狀態)
- `GET /admin/check-provider/{id}`
#### Scenario: Admin 課程、預約、評價管理端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件:
- `GET /admin/offers`(分頁 response)
- `DELETE /admin/offers/{id}`
- `GET /admin/bookings`(分頁 response)
- `PUT /admin/bookings/{id}/complete`
- `GET /admin/reviews`(分頁 response,含 per_page 參數,最大 100)
- `DELETE /admin/reviews/{id}`
@@ -0,0 +1,21 @@
## ADDED Requirements
### Requirement: Auth 補全端點 Swagger 文件
`app/Docs/AuthSupplementDoc.php` SHALL 補全未文件化的 Auth 相關端點(Google OAuth、change-password)。
#### Scenario: Google OAuth 端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件:
- `GET /auth/google/redirect`(response: redirect_url,說明用途為取得 Google OAuth redirect URL)
- `GET /auth/google/callback`(response: token + user,說明此為 OAuth callback,通常由瀏覽器自動呼叫)
#### Scenario: change-password 端點文件化(三個 role)
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件,各自標示對應 role 的 `security: bearerAuth`:
- `PUT /member/change-password`(request: current_password、password、password_confirmation)
- `PUT /provider/change-password`(同上)
- `PUT /admin/change-password`(同上)
- 422 驗證失敗 response 亦有定義
@@ -0,0 +1,33 @@
## ADDED Requirements
### Requirement: Member 端點 Swagger 文件
`app/Docs/MemberApiDoc.php` SHALL 文件化所有需要 Member Bearer token 的端點(bookings、reviews、helpful 投票、notifications)。
#### Scenario: Member bookings 端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件,並標示 `security: bearerAuth`:
- `POST /member/bookings`(request: schedule_id;response 201: Booking)
- `GET /member/bookings`(response: Booking 陣列 + 分頁 meta)
- `GET /member/bookings/{id}`(response: Booking 詳情)
- `DELETE /member/bookings/{id}`(response 200: message)
#### Scenario: Member reviews 端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件:
- `POST /member/reviews`(request: diving_offer_id、rating、comment;403 資格驗證失敗;422 重複評價)
- `PUT /member/reviews/{id}`(request: rating?、comment?;403 非本人)
- `DELETE /member/reviews/{id}`(403 非本人)
- `POST /reviews/{id}/helpful`(toggle,response: helpful_count、has_voted)
#### Scenario: Member notifications 端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件:
- `GET /notifications`(response: 通知陣列 + 分頁 meta)
- `GET /notifications/unread-count`(response: count)
- `PATCH /notifications/{id}/read`
- `PATCH /notifications/read-all`
- `DELETE /notifications/{id}`
@@ -0,0 +1,43 @@
## ADDED Requirements
### Requirement: Provider 端點 Swagger 文件
`app/Docs/ProviderApiDoc.php` SHALL 文件化所有需要 Provider Bearer token 的端點(offers CRUD、圖片、schedules、bookings)。
#### Scenario: Provider offers CRUD 端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件,標示 `security: bearerAuth`:
- `GET /provider/offers`(分頁 response)
- `POST /provider/offers`(request: title、location、spot?、price、region、tag?、badges?、description?)
- `GET /provider/offers/{id}`(403 非本人)
- `PUT /provider/offers/{id}`(request 同上,所有欄位 nullable)
- `DELETE /provider/offers/{id}`
#### Scenario: Provider 圖片管理端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件:
- `POST /provider/offers/{id}/cover`(multipart/form-data: image;response: cover_image_url)
- `DELETE /provider/offers/{id}/cover`
- `POST /provider/offers/{id}/images`(multipart/form-data: images[];最多 10 張)
- `DELETE /provider/images/{id}`
#### Scenario: Provider schedules 端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件:
- `GET /provider/schedules`(query: offer_id?;response: CourseSchedule 陣列)
- `POST /provider/schedules`(request: diving_offer_id、date、period、capacity)
- `PUT /provider/schedules/{id}`
- `DELETE /provider/schedules/{id}`
#### Scenario: Provider bookings 端點文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 以下端點均有文件:
- `GET /provider/bookings`(response: Booking 陣列,含 member 資訊)
- `PUT /provider/bookings/{id}/confirm`
- `PUT /provider/bookings/{id}/reject`
- `PUT /provider/bookings/{id}/complete`
- `PUT /provider/bookings/{id}/cancel`
@@ -0,0 +1,30 @@
## ADDED Requirements
### Requirement: 公開端點 Swagger 文件及共用 Schema
`app/Docs/PublicApiDoc.php` SHALL 文件化所有無需認證的公開端點,並定義全域共用 Schema。
#### Scenario: 共用 Schema 定義完整
- **WHEN** 執行 `php artisan l5-swagger:generate`
- **THEN** 以下 Schema 出現在產生的 JSON:`DivingOffer`、`Review`、`CourseSchedule`、`PaginationMeta`、`ApiErrorResponse`
#### Scenario: GET /api/diving-offers 文件化
- **WHEN** 開啟 Swagger UI
- **THEN** `GET /diving-offers` 端點顯示 query parameters(`q`、`region`、`tag`、`per_page`、`page`)及包含分頁 meta 的 response schema
#### Scenario: GET /api/diving-offers/{id} 文件化
- **WHEN** 開啟 Swagger UI
- **THEN** `GET /diving-offers/{id}` 端點顯示 path parameter `id` 及包含 `cover_image_url`、`images` 陣列的 response schema;404 response 亦有定義
#### Scenario: GET /api/diving-offers/{id}/reviews 文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 端點顯示 `sort`(helpful/rating/newest)、`page`、`per_page` 參數;response 包含 `summary`(average、total、distribution)與分頁 `meta`
#### Scenario: GET /api/diving-offers/{id}/schedules 文件化
- **WHEN** 開啟 Swagger UI
- **THEN** 端點顯示 response 包含 `CourseSchedule` 陣列(id、date、period、capacity、booked_count、status)
@@ -0,0 +1,44 @@
## 1. 修正 AuthApiDoc.php 既有錯誤
- [x] 1.1 [後端] `AuthApiDoc.php` 修正所有路徑錯位:`/register/member` → `/member/register`、`/login/member` → `/member/login`、`/logout/member` → `/member/logout`、`/profile/member` → `/member/profile`(provider、admin 同樣修正)
- [x] 1.2 [後端] `AuthApiDoc.php` 修正 change-password 路徑:`/password/member` → `/member/change-password`、`/password/provider` → `/provider/change-password`、`/password/admin` → `/admin/change-password`
- [x] 1.3 [後端] `AuthApiDoc.php` 補上 `POST /logout`(通用登出)與 `GET /user`(取得當前使用者)
## 2. AuthSupplementDoc(Google OAuth 專用)
- [x] 2.1 [後端] 建立 `app/Docs/AuthSupplementDoc.php`,補上 `GET /auth/google/redirect`(response: redirect_url)與 `GET /auth/google/callback`(response: token + user)兩個端點
## 3. 共用 Schema 與 PublicApiDoc
- [x] 3.1 [後端] 建立 `app/Docs/PublicApiDoc.php`,定義共用 Schema:`DivingOffer`、`Review`、`CourseSchedule`、`Booking`、`PaginationMeta`、`ApiErrorResponse`
- [x] 3.2 [後端] `PublicApiDoc.php` 補上 `GET /diving-offers`(query: q、region、tag、per_page、page;response: DivingOffer 分頁)
- [x] 3.3 [後端] `PublicApiDoc.php` 補上 `GET /diving-offers/{id}`(response: DivingOffer 含 cover_image_url、images 陣列;404)
- [x] 3.4 [後端] `PublicApiDoc.php` 補上 `GET /diving-offers/{id}/reviews`(query: sort、page、per_page;response: summary + reviews 分頁 + meta)
- [x] 3.5 [後端] `PublicApiDoc.php` 補上 `GET /diving-offers/{id}/schedules`(response: CourseSchedule 陣列)
## 4. MemberApiDoc
- [x] 4.1 [後端] 建立 `app/Docs/MemberApiDoc.php`,補上 Member bookings:`POST /member/bookings`(201)、`GET /member/bookings`(分頁)、`GET /member/bookings/{id}`、`DELETE /member/bookings/{id}`
- [x] 4.2 [後端] `MemberApiDoc.php` 補上 Member reviews:`POST /member/reviews`(403/422)、`PUT /member/reviews/{id}`(403)、`DELETE /member/reviews/{id}`(403)
- [x] 4.3 [後端] `MemberApiDoc.php` 補上 `POST /reviews/{id}/helpful`(response: helpful_count、has_voted)
- [x] 4.4 [後端] `MemberApiDoc.php` 補上 notifications:`GET /notifications`(分頁)、`GET /notifications/unread-count`、`PATCH /notifications/{id}/read`、`PATCH /notifications/read-all`、`DELETE /notifications/{id}`
## 5. ProviderApiDoc
- [x] 5.1 [後端] 建立 `app/Docs/ProviderApiDoc.php`,補上 Provider offers CRUD:`GET /provider/offers`、`POST /provider/offers`、`GET /provider/offers/{id}`(403)、`PUT /provider/offers/{id}`、`DELETE /provider/offers/{id}`
- [x] 5.2 [後端] `ProviderApiDoc.php` 補上圖片管理:`POST /provider/offers/{id}/cover`(multipart)、`DELETE /provider/offers/{id}/cover`、`POST /provider/offers/{id}/images`、`DELETE /provider/images/{id}`
- [x] 5.3 [後端] `ProviderApiDoc.php` 補上 schedules:`GET /provider/schedules`(query: offer_id?)、`POST /provider/schedules`、`PUT /provider/schedules/{id}`、`DELETE /provider/schedules/{id}`
- [x] 5.4 [後端] `ProviderApiDoc.php` 補上 bookings 管理:`GET /provider/bookings`、`PUT /provider/bookings/{id}/confirm`、`PUT /provider/bookings/{id}/reject`、`PUT /provider/bookings/{id}/complete`、`PUT /provider/bookings/{id}/cancel`
## 6. AdminApiDoc
- [x] 6.1 [後端] 建立 `app/Docs/AdminApiDoc.php`,補上 `GET /admin/stats`(response: total_members/providers/offers;403)
- [x] 6.2 [後端] `AdminApiDoc.php` 補上會員管理:`GET /admin/members`(分頁)、`GET /admin/members/{id}`、`PUT /admin/members/{id}/toggle-active`、`GET /admin/check-member/{id}`
- [x] 6.3 [後端] `AdminApiDoc.php` 補上教練管理:`GET /admin/providers`(分頁)、`GET /admin/providers/{id}`、`PUT /admin/providers/{id}/toggle-active`、`PUT /admin/providers/{id}/toggle-verified`、`GET /admin/check-provider/{id}`
- [x] 6.4 [後端] `AdminApiDoc.php` 補上課程/預約/評價管理:`GET /admin/offers`、`DELETE /admin/offers/{id}`、`GET /admin/bookings`、`PUT /admin/bookings/{id}/complete`、`GET /admin/reviews`(per_page 最大 100)、`DELETE /admin/reviews/{id}`
## 7. 驗證
- [x] 7.1 [整合測試] 執行 `docker exec cfdive-app php artisan l5-swagger:generate`,確認無 parse error
- [x] 7.2 [整合測試] 開啟 `http://localhost:8080/api/documentation`,展開各 tag 確認路徑正確(`/member/register` 而非 `/register/member`)
- [x] 7.3 [整合測試] 確認端點總數 73(原始估計 76 因 AuthApiDoc 實際有 18 個端點非 15 個),`GET /diving-offers/{id}/reviews` 顯示分頁 meta schema