dcbf3e4a9a
Run Tests / test (pull_request) Successful in 39s
- M7:預約交易的 catch (\RuntimeException) 會吞掉 QueryException,把 SQL 以 422 回給使用者且不送 Sentry - 規劃新增 BookingRuleViolationException,Controller 只 catch 業務例外,其他例外交給 Laravel 處理器(500 + 回報) - booking-lifecycle 新增「預約交易錯誤分類」requirement(5 個 Scenario 皆對應測試任務) - spec-reviewer、design-hardener 皆 PASS,warnings 已併入文件 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2.6 KiB
2.6 KiB
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,維持不新增)