chore:歸檔 api-performance-optimization,同步主規格 #1

Merged
a620906209 merged 3 commits from feature/swagger-api-docs into master 2026-05-24 17:21:44 +00:00
9 changed files with 313 additions and 0 deletions
Showing only changes of commit e8cd82cdee - Show all commits
@@ -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 bodyPOST/PUT)、response200/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 層語意上最自然(核心資料結構)
### 決策 3Security 標注策略
- 公開端點:不加 `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 APIGET diving-offers 列表/詳情、reviews、schedules4
- Member APIbookings CRUD、reviews CRUD、helpful 投票、notifications10
- Provider APIoffers CRUD + 圖片、schedules CRUD、bookings 管理(19
- Admin APIstats、members、providers、offers、bookings、reviews 管理(17
- Auth 補全:Google OAuth、change-password3 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_idresponse 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、comment403 資格驗證失敗;422 重複評價)
- `PUT /member/reviews/{id}`request: rating?、comment?403 非本人)
- `DELETE /member/reviews/{id}`403 非本人)
- `POST /reviews/{id}/helpful`toggleresponse: 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: imageresponse: 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 schema404 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 既有錯誤
- [ ] 1.1 [後端] `AuthApiDoc.php` 修正所有路徑錯位:`/register/member``/member/register``/login/member``/member/login``/logout/member``/member/logout``/profile/member``/member/profile`provider、admin 同樣修正)
- [ ] 1.2 [後端] `AuthApiDoc.php` 修正 change-password 路徑:`/password/member``/member/change-password``/password/provider``/provider/change-password``/password/admin``/admin/change-password`
- [ ] 1.3 [後端] `AuthApiDoc.php` 補上 `POST /logout`(通用登出)與 `GET /user`(取得當前使用者)
## 2. AuthSupplementDocGoogle OAuth 專用)
- [ ] 2.1 [後端] 建立 `app/Docs/AuthSupplementDoc.php`,補上 `GET /auth/google/redirect`response: redirect_url)與 `GET /auth/google/callback`response: token + user)兩個端點
## 3. 共用 Schema 與 PublicApiDoc
- [ ] 3.1 [後端] 建立 `app/Docs/PublicApiDoc.php`,定義共用 Schema`DivingOffer``Review``CourseSchedule``Booking``PaginationMeta``ApiErrorResponse`
- [ ] 3.2 [後端] `PublicApiDoc.php` 補上 `GET /diving-offers`query: q、region、tag、per_page、pageresponse: DivingOffer 分頁)
- [ ] 3.3 [後端] `PublicApiDoc.php` 補上 `GET /diving-offers/{id}`response: DivingOffer 含 cover_image_url、images 陣列;404
- [ ] 3.4 [後端] `PublicApiDoc.php` 補上 `GET /diving-offers/{id}/reviews`query: sort、page、per_pageresponse: summary + reviews 分頁 + meta
- [ ] 3.5 [後端] `PublicApiDoc.php` 補上 `GET /diving-offers/{id}/schedules`response: CourseSchedule 陣列)
## 4. MemberApiDoc
- [ ] 4.1 [後端] 建立 `app/Docs/MemberApiDoc.php`,補上 Member bookings`POST /member/bookings`201)、`GET /member/bookings`(分頁)、`GET /member/bookings/{id}``DELETE /member/bookings/{id}`
- [ ] 4.2 [後端] `MemberApiDoc.php` 補上 Member reviews`POST /member/reviews`403/422)、`PUT /member/reviews/{id}`403)、`DELETE /member/reviews/{id}`403
- [ ] 4.3 [後端] `MemberApiDoc.php` 補上 `POST /reviews/{id}/helpful`response: helpful_count、has_voted
- [ ] 4.4 [後端] `MemberApiDoc.php` 補上 notifications`GET /notifications`(分頁)、`GET /notifications/unread-count``PATCH /notifications/{id}/read``PATCH /notifications/read-all``DELETE /notifications/{id}`
## 5. ProviderApiDoc
- [ ] 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}`
- [ ] 5.2 [後端] `ProviderApiDoc.php` 補上圖片管理:`POST /provider/offers/{id}/cover`multipart)、`DELETE /provider/offers/{id}/cover``POST /provider/offers/{id}/images``DELETE /provider/images/{id}`
- [ ] 5.3 [後端] `ProviderApiDoc.php` 補上 schedules`GET /provider/schedules`query: offer_id?)、`POST /provider/schedules``PUT /provider/schedules/{id}``DELETE /provider/schedules/{id}`
- [ ] 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
- [ ] 6.1 [後端] 建立 `app/Docs/AdminApiDoc.php`,補上 `GET /admin/stats`response: total_members/providers/offers403
- [ ] 6.2 [後端] `AdminApiDoc.php` 補上會員管理:`GET /admin/members`(分頁)、`GET /admin/members/{id}``PUT /admin/members/{id}/toggle-active``GET /admin/check-member/{id}`
- [ ] 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}`
- [ ] 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. 驗證
- [ ] 7.1 [整合測試] 執行 `docker exec cfdive-app php artisan l5-swagger:generate`,確認無 parse error
- [ ] 7.2 [整合測試] 開啟 `http://localhost:8080/api/documentation`,展開各 tag 確認路徑正確(`/member/register` 而非 `/register/member`
- [ ] 7.3 [整合測試] 確認端點總數 ≥ 76,`GET /diving-offers/{id}/reviews` 顯示分頁 meta schema