Files
CFDivePlatform/openspec/changes/archive/2026-10-18-fix-booking-exception-handling/proposal.md
T
a620906209 72daf9baa0
Run Tests / test (pull_request) Successful in 37s
chore(openspec): 歸檔 fix-booking-exception-handling 並同步主規格
- booking-lifecycle 主規格新增「預約交易錯誤分類」requirement
- tasks 3.2 正式環境驗證完成(建立、確認預約正常,未觀察到 500)
- 待辦文件標記 M7 完成

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 01:45:26 +08:00

30 lines
2.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Proposal
## Why
`MemberBookingController::store` 與 `ProviderBookingController::confirm` 用 `catch (\RuntimeException $e)` 把交易內的業務失敗轉成 422,並直接回傳 `$e->getMessage()`。`Illuminate\Database\QueryException` 經由 `PDOException` 也是 `RuntimeException` 的子類別,因此交易內的資料庫錯誤(死結、逾時、約束違反、連線中斷)會被同一個 catch 接住:SQL 與資料表結構被當成 422 訊息回給使用者(資訊洩漏),且不經過 Laravel 例外處理器、不會送到 Sentry,營運端看不到伺服器故障(待辦 M7,`docs/analysis/2026-10-14-project-review-todo.md`)。
## What Changes
- 新增專用的業務例外 `BookingRuleViolationException`;兩個預約交易閉包內的業務規則失敗(名額不足、重複預約)改拋此例外
- 兩個 Controller 只 catch `BookingRuleViolationException` 並回 422 與其訊息;其他例外(含 `QueryException`)不再被攔截,交給 Laravel 例外處理器產生 500 並回報(既有 `Sentry\Laravel\Integration::handles` 會送到 Sentry)
- 業務失敗的 422 狀態碼與訊息文字維持不變
- 資料庫錯誤的回應由「422 + 原始例外訊息」改為「500 + Laravel 預設通用訊息」(`APP_DEBUG=false` 時 body 為 `{"message":"Server Error"}`)
## Capabilities
### New Capabilities
(無)
### Modified Capabilities
- `booking-lifecycle`:新增「預約交易錯誤分類」requirement,明定業務規則失敗回 422 與既有訊息、非業務例外回 500 且不洩漏資料庫細節並被回報
## Impact
- **程式碼**:新增 `app/Exceptions/BookingRuleViolationException.php`;修改 `app/Http/Controllers/API/MemberBookingController.php`(`store`)、`app/Http/Controllers/API/ProviderBookingController.php`(`confirm`)
- **API 回應格式**:業務失敗(422)不變。資料庫錯誤的回應由 422 改為 500,body 為 Laravel 預設格式 `{"message":"Server Error"}`,**不含**專案慣例的 `status` 欄位——這是刻意選擇(交給 Laravel 處理、不另寫轉換),與其他端點未被攔截的 500 一致
- **前端**:`CourseDetailView.vue`、`coach/BookingManagerView.vue` 以 `e.response?.data?.message` 顯示錯誤;資料庫錯誤時會顯示 `Server Error`(原本顯示 SQL 訊息),不需修改前端
- **監控**:預約交易內的資料庫錯誤開始出現在 Sentry
- **測試**:新增 Feature 測試;既有 `BookingOversellTest`、`BookingLifecycleTest` 的 422 行為不變
- **相依、migration、路由、Swagger**:無變更(`app/Docs/` 目前沒有記錄這兩個端點的 500,維持不新增)