a620906209
|
b218fa0964
|
fix(swagger): 修正 VPS 無法顯示 Swagger UI 的問題
Run Tests / test (pull_request) Successful in 33s
問題根因:
1. deploy.yml 未執行 l5-swagger:generate,VPS 上不存在 api-docs.json
2. @OA\Server 使用相對路徑 "/api",Swagger UI Try it out 無法正確打到 VPS API
修正:
- @OA\Server 改用 L5_SWAGGER_CONST_HOST 常數,透過 .env 各環境設定
- deploy.yml 在 config:cache 後補上 l5-swagger:generate 步驟
- .env.example 補上 L5_SWAGGER_CONST_HOST 與 L5_SWAGGER_GENERATE_ALWAYS 說明
VPS .env 需手動加入:
L5_SWAGGER_CONST_HOST=https://api.hank-space.com/api
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
2026-06-23 15:23:18 +08:00 |
|
a620906209
|
60ff56a571
|
docs(swagger): 補全缺漏端點標註 + 更新 README 文件 URL
Run Tests / test (pull_request) Successful in 32s
新增 11 個先前缺漏的 @OA 標註:
- Token Refresh(Member / Provider / Admin)
- Provider 資格驗證申請(show / upload / delete cert / submit)
- 即時訊息聊天室(unread-counts / list / send / mark-read)
其他:
- l5-swagger.php 標題改為 CFDive Platform API
- README 補充 Swagger UI URL 與 JSON 端點位置
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
2026-06-23 15:08:15 +08:00 |
|
a620906209
|
43720482c4
|
feat(verification): 教練審核流程完整版——狀態機/證照送審/Admin 裁決/通知
Run Tests / test (pull_request) Successful in 2m3s
實作 openspec change provider-verification-workflow(25/25 tasks):
- is_verified 升級為 verification_status 四狀態機(unsubmitted/pending/
approved/rejected),migration 自動轉換既有資料,API 以 accessor 保留
is_verified 相容輸出
- 教練端:證照上傳(≤3 張、複用 CompressesImages)、送審、駁回原因
顯示與重送(/coach/verification 新頁面)
- Admin 端:審核佇列、通過/駁回(原因必填)、撤銷 approved;移除
toggle-verified 端點(防繞過狀態機);裁決後 flush 課程快取
- 通知:審核通過/駁回(站內+Email,駁回含原因)
- 可見性與預約入口改判 approved(行為等價)
- 測試 +18(ProviderVerificationTest 10、AdminVerificationTest 8),
既有 4 個測試檔 helper 遷移;Swagger 同步
- 規格同步:provider-verification 全面改寫、admin-user-management
toggle 段落改為移除聲明
容器內全套件 173 passed / 439 assertions。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-06-12 00:26:12 +08:00 |
|
a620906209
|
6414222a18
|
feat(images): 課程圖片伺服器端壓縮——scaleDown 2048 + JPEG 85,上限放寬至 10MB
Run Tests / test (pull_request) Successful in 2m0s
實作 openspec change course-image-compression(O3.1 體感優化):
- 新增 App\Traits\CompressesImages:與聊天圖片管線參數一致的共用壓縮邏輯
- CourseImageController 封面/相簿套用壓縮,上傳上限 2MB→10MB(容納手機原圖)
- 前端課程卡片與相簿縮圖加 loading=lazy(詳情頁首屏封面刻意不加)
- CourseImageTest +4 案例(10MB 邊界、轉存 .jpg、>2048 縮小、小圖不放大)
- course-image-upload 主規格同步(新增伺服器端壓縮 requirement)
容器內全套件 155 passed / 400 assertions。
聊天端改用 trait 留待後續(該處無測試覆蓋,不在本 change 重構)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-06-11 23:43:24 +08:00 |
|
a620906209
|
90d0a57e73
|
feat(offers): 補齊 provider-verification 可見性缺口——子端點過濾與預約入口檢查
Run Tests / test (pull_request) Successful in 1m56s
實作 openspec change provider-verification-gaps(8/8 tasks):
- schedules/reviews publicList 套用 visibleToPublic,隱藏課程回 404
- MemberBookingController::store Layer 1 擋未驗證教練課程的新預約(422)
- 政策:教練被取消驗證只擋新預約,既有 pending/confirmed/completed 照常
- 主規格 Notes 已知限制轉為正式 Requirements
- 測試 +5(可見性子端點 3、預約入口 2),既有 booking/review 測試 helper
補 verified ProviderProfile
- 容器內全套件 151 passed / 388 assertions;另以 demo 資料端到端驗證
(已驗證教練 200/200/200、未驗證 404/404/404)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-06-11 22:48:59 +08:00 |
|
a620906209
|
3c38d085bd
|
feat(offers): 未驗證教練的課程不對公開端點曝光
is_verified 原本只有 Admin toggle 開關、無任何業務約束(稽核 P1-1)。
- DivingOffer 新增 visibleToPublic scope:provider_id null 或教練已驗證
- 公開 index/show 套用過濾,未驗證教練課程列表排除、詳情 404
- toggle-verified 後 flush diving_offers 快取標籤,切換立即生效
- 新增 provider-verification 規格(含已知限制註記)與 7 條可見性測試
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-06-11 17:42:43 +08:00 |
|
a620906209
|
aeb8c975e2
|
security(auth): 移除公開 admin/register 端點,改由 app:create-admin 建立管理員
P0 漏洞:原 POST /api/admin/register 無任何防護,任何人可註冊管理員帳號。
- 移除路由、AuthController::registerAdmin、對應 Swagger 文件
- 新增 app:create-admin artisan command(密碼門檻 min:8)
- 補 AdminAccountCreationTest 防止端點被重新打開
- 同步 admin-auth 規格,並收錄 2026-06-11 稽核報告與路線圖文檔
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-06-11 17:36:33 +08:00 |
|
a620906209
|
2a0e9255ae
|
security(auth): P2 帳號鎖定 + OAuth state 驗證
- Account lockout:連續失敗 5 次鎖定 15 分鐘(Fixed Window,Cache)
- Member / Provider 各自獨立 namespace
- Email 正規化(strtolower+trim)
- 不存在帳號不累計計數(防 Cache 污染)
- companion key 記錄 locked_until(ISO 8601)
- OAuth CSRF 防護:移除 stateless(),手動 state 生成與驗證
- session('oauth_state') + session('state') 雙寫確保 Socialite 內建驗證通過
- state mismatch redirect 至 /login?error=oauth_failed
- throttle 從 5,1 調整為 10,1,避免 IP throttle 在 lockout 前觸發
- NormalizesEmail Trait、config/auth_lockout.php
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
2026-06-03 01:20:25 +08:00 |
|
a620906209
|
d9f0fe11c6
|
security(auth): P1 Token Refresh + sessionStorage
- 新增三個 refresh 端點(member/provider/admin),revoke 舊 token 發行新 7 天 token
- axios.js / coachAxios.js:401 interceptor 改為 refresh-then-retry,含 isRefreshing queue 防並發、isRedirecting flag 防雙重 redirect
- auth.js / coachAuth.js / AuthCallbackView.vue:localStorage 全改為 sessionStorage
- echo.js / notificationAxios.js:同步改為 sessionStorage
- notifications.js:401 時停止 polling(stopPolling),不印 error log
- 新增 TokenRefreshTest.php(11 tests / 24 assertions):refresh 成功/失效/跨角色 403
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
2026-06-02 04:33:35 +08:00 |
|
a620906209
|
cb9c9a9385
|
security(auth): P0 認證安全強化
- Token 過期時間設為 7 天(sanctum.php expiration)
- prune-expired 每日排程清除過期 token 記錄
- Google OAuth redirect 改用 URL fragment(#token=)避免 token 出現在 server log
- SocialAuthController env() 改 config() 修正 config:cache 下 redirect 失效問題
- 登入端點加 rate limiting:member/provider throttle:5,1,admin throttle:3,1
- axios/coachAxios 加 401 response interceptor,token 過期自動登出
- 修正 migration SQLite 相容性(MODIFY COLUMN),Feature tests 從 7 通過恢復至 41
- 新增 AuthRateLimitTest(5 tests)驗證各角色頻率限制行為
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
2026-06-02 01:54:40 +08:00 |
|
a620906209
|
1ba4ca893a
|
fix: 修正即時聊天室 presence channel 間歇性失效
三個根本原因:
1. updateEchoToken() 呼叫 disconnect/connect 會中斷已訂閱的
presence channel,改為只更新 auth header(不重連)。
同時將 setAuth() 的呼叫順序改為先 updateEchoToken() 再
startRealtime(),確保訂閱時使用最新 token。
2. BookingPresenceChannel::join() 未對 schedule null 做防守,
載入後若 schedule 不存在會 500,導致 auth 靜默失敗。
3. WebSocket 重連後 presence channel 不會自動恢復,
在 BookingChat 加入 reconnected 事件處理,重連後重訂閱。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
2026-05-28 17:46:15 +08:00 |
|
a620906209
|
ab24f210a6
|
feat: 即時預約聊天室(realtime booking chat)
## 新增功能
- 會員與教練在 confirmed 預約期間可互傳文字與圖片訊息
- Presence Channel 顯示對方在線狀態(即時加入/離線)
- 已讀回執:對方讀取訊息後即時更新
- 預約完成(completed)後訊息封存唯讀
- 圖片上傳使用 intervention/image 處理(移除 EXIF、限制尺寸、強制重新編碼)
## 通知系統
- 收到新訊息時 Bell Icon 即時更新(NotificationCreated via private channel)
- 預約列表卡片顯示未讀角標(GET /api/bookings/messages/unread-counts 批次查詢)
- 瀏覽器分頁在背景時推送 Web Notification
## 基礎建設
- 引入 Laravel Reverb 作為自架 WebSocket 伺服器
- docker-compose 新增 reverb service(連接 proxy_net,供 NPM 代理)
- 前端安裝 laravel-echo + pusher-js,初始化 Echo plugin
- Dockerfile 補 GD JPEG/WebP/FreeType 支援
## 清理
- 移除 test_broadcast.php 與 resources/js/echo.js(Blade 殘留)
- 移除 /ping、/testpost 測試路由
- channels.php 改用 class-based 授權語法,移除 debug log
- BookingChat.vue otherType 提取為 computed 消除重複
- docker-entrypoint.sh 健康檢查改用 env var 取代硬編碼密碼
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
2026-05-28 03:59:14 +08:00 |
|
a620906209
|
250c50fc74
|
Merge pull request 'chore: 清除廢棄的 DB 表與 Model' (#5) from chore/db-cleanup into master
Tests / PHP 8.2 (push) Failing after 2s
Tests / PHP 8.3 (push) Failing after 1s
Reviewed-on: #5
|
2026-05-25 08:37:55 +00:00 |
|
a620906209
|
ff2484a48f
|
chore: 清除廢棄的 DB 表與 Model
pull requests / uneditable (pull_request_target) Failing after 1s
Tests / PHP 8.2 (pull_request) Has been cancelled
Tests / PHP 8.3 (pull_request) Has been cancelled
- 新增 migration 刪除 coach_profiles、coach_member、plans、subscriptions 四張廢棄表
- 刪除對應的空殼 Model:CoachProfile、Plan、Subscription
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
2026-05-25 16:34:04 +08:00 |
|
a620906209
|
0dda2bb2a3
|
docs:補全所有 API 端點 Swagger 文件(73 個端點)
Tests / PHP 8.2 (pull_request) Failing after 2s
Tests / PHP 8.3 (pull_request) Failing after 2s
- 修正 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>
|
2026-05-24 18:24:50 +00:00 |
|
a620906209
|
efb1f22be3
|
feat:實作 API 效能優化 — Redis 快取、分頁、DB 索引
- 引入 Redis(predis)快取層:Admin Stats(5分鐘)、課程列表(3分鐘,tag-based 失效)、評價分布(10分鐘)
- ReviewController::publicList 改為 paginate + eager load votes,消除 N+1
- AdminReviewController::index 加入分頁(預設 20,最大 100)
- 新增 notifications / diving_offers 效能索引 migration
- 新增 docker-compose.override.yml 本機開發 port mapping 機制(不進 git)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
2026-05-25 00:17:16 +08:00 |
|
a620906209
|
0bce40a5bf
|
feat:實作通知系統 — 站內通知、Email 通知、Polling 機制
後端
- 新增 6 個 Notification class(預約建立/確認/拒絕/取消/完成、收到評價),database + mail 雙 channel
- 新增 NotificationController(list / unread-count / markRead / markAllRead / destroy)
- 整合通知觸發至 MemberBookingController、ProviderBookingController、CompleteFinishedBookings、ReviewController
- 新增 notifications / jobs / failed_jobs migration
- Docker Compose 加入 queue-worker、mailpit service
- DivingOffer 補上 provider() 關聯
前端
- 新增 notificationStore(Polling 30s/60s 自適應 + Page Visibility API)
- 新增 NotificationBell(未讀 Badge)、NotificationDrawer(側邊通知中心)
- main.js:auth store init 前置於 router.use(),修正 beforeEach guard 時序問題
- notificationAxios:依路徑動態選擇 member/coach token
- NotificationDrawer:改用 new URL().pathname 提取 action_url 路徑
OpenSpec
- 歸檔 notification-system change
- 同步 notification-core / notification-email / notification-triggers specs 至主規格
- 更新 booking-lifecycle / review-lifecycle spec(補充通知觸發 requirement)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
2026-05-17 22:26:14 +08:00 |
|
a620906209
|
ca2ed14de3
|
feat:實作課程圖片上傳 — 封面 + 相簿管理
後端:
- Migration:diving_offers 新增 cover_image 欄位、新增 course_images 表(含索引)
- CourseImage Model(CREATED_AT、url accessor)
- DivingOffer:cover_image_url accessor、hasMany courseImages、static::deleting() 孤兒清理
- CourseImageController:封面上傳/刪除、相簿上傳(max 3)/刪除,統一 mimes+size 驗證
- DivingOfferController:index/show 回傳加入 cover_image_url 與 images 陣列
- 修正 APP_URL 加入 port(:8080),Storage::url() 才能產生正確圖片連結
前端:
- courseImageApi.js:uploadCover/deleteCover/uploadImage/deleteImage
- CourseCard:有封面顯示 <img>,無封面顯示漸層佔位
- CourseDetailView:封面大圖 + 相簿縮圖橫列(點擊開新分頁)
- OfferFormView(編輯模式):封面預覽/更換/刪除、相簿縮圖管理(達 3 張隱藏上傳按鈕)
基礎設施:
- docker-entrypoint.sh:加入 storage:link --force
- docker-compose.yml:移除 storage-data named volume(改用 bind mount,避免 Nginx 讀不到圖片)
測試:
- CourseImageTest.php:14 個 Feature Test 全部 PASS(Storage::fake)
涵蓋:上傳成功/格式驗證/大小驗證/所有權、刪除/無封面不報錯、
相簿上限/sort_order 遞增、孤兒清理
OpenSpec:
- course-images change 歸檔至 archive/2026-05-12-course-images
- 新增 specs/course-image-upload 主規格(含 bind mount 持久化說明)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
2026-05-12 03:54:45 +08:00 |
|
a620906209
|
8ef293332a
|
feat:實作評價系統 — 匿名評價、有幫助投票、手動完成預約
後端:
- 新增 reviews / review_edits / review_votes migration(含索引)
- Review / ReviewEdit / ReviewVote Model
- ReviewController:評價 CRUD、資格驗證(completed booking)、rating 即時重算
- toggleHelpful:Member 限定、GREATEST 原子防負、DB transaction 同步
- AdminReviewController:全量列表、刪除(含重算)
- AdminBookingController:全量列表、手動標記 completed
- ProviderBookingController 新增 complete 方法(教練手動完成預約)
- DevelopmentSeeder:快速重建測試資料(admin/coach/member + offers + bookings)
- EnsureAdmin middleware 正式納入 bootstrap/app.php
- Nginx server_name 加入 cfdive.local
前端:
- 課程詳情頁加入評價區塊(星等分布、排序切換、撰寫/修改/刪除、有幫助 Toggle)
- Coach Portal 新增「課程評價」頁(只讀,依課程分組)
- Coach 預約管理加入「完成」按鈕
- Admin 新增「預約管理」頁(標記完成)、「評價管理」頁(刪除)
- Admin / Coach Navbar 新增對應連結
OpenSpec:
- review-system change 歸檔至 archive/2026-05-12-review-system
- 新增 specs/review-lifecycle 與 specs/review-voting 主規格
- review-voting spec 補充 Member 限定與 GREATEST 原子更新說明
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
2026-05-12 02:46:54 +08:00 |
|
a620906209
|
88c0c09ccb
|
feat:實作預約系統 — 時段管理、預約生命週期與前端整合
後端:
- 新增 course_schedules / bookings migration(含索引)
- BookingStatus / ScheduleStatus PHP BackedEnum
- CourseSchedule / Booking Model(七狀態機 VALID_TRANSITIONS)
- ScheduleController、ProviderBookingController、MemberBookingController
- 雙層名額驗證(API 層快速失敗 + DB lockForUpdate 防超賣)
- 24h 取消截止、pending 不佔位設計
- ExpirePendingBookings(每小時)/ CompleteFinishedBookings(每日)Scheduler
- Docker cron 配置、CACHE_STORE 改為 file 修正 502
前端:
- 課程詳情頁加入時段選擇與預約流程
- 我的預約頁(展開式卡片、狀態說明、連結課程詳情)
- Coach 時段管理(上午/下午時間選擇器、新課程引導)
- Coach 預約管理(依課程分組、待確認徽章)
- Navbar 新增「我的預約」與「時段/預約管理」入口
- 密碼格式提示與即時比對
OpenSpec:
- booking-system change 歸檔至 archive/2026-05-12-booking-system
- 新增 specs/course-scheduling 與 specs/booking-lifecycle 主規格
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
2026-05-12 00:24:51 +08:00 |
|
a620906209
|
24145419b0
|
feat:實作 Admin Panel — 平台管理後台
後端:
- AdminStatsController:總會員/教練/課程數統計 API
- AdminUserController:會員與教練列表、詳情、啟用/停用、教練驗證(toggle 反轉語意)
- AdminOfferController:全平台課程列表與刪除
- routes/api.php:新增 /api/admin/stats、members、providers、offers 等路由
前端(frontend/):
- adminAuth store、adminAxios(第三套獨立認證)
- /admin/* 路由群組 + requiresAdmin guard
- AdminNavBar、AdminLayout
- App.vue:isCoachPage → isBackofficePage(/coach/* 和 /admin/* 皆隱藏會員 NavBar)
- LoginView、DashboardView(統計卡片)
- MembersView、ProvidersView(含驗證操作)、OffersView(含刪除確認)
OpenSpec:
- 新增 specs:admin-auth / admin-user-management / admin-offer-management / admin-stats / admin-panel-ui
- 歸檔:openspec/changes/archive/2026-05-10-admin-panel
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
2026-05-10 04:07:13 +08:00 |
|
a620906209
|
3827223be3
|
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 |
|
a620906209
|
e44d69a973
|
feat:實作 Member Portal MVP 前端與後端整合
後端:
- 新增 DivingOffer Model / DivingOfferController(列表+詳情 API,支援搜尋/篩選/分頁)
- 修正 Google OAuth callback 改為 redirect 至前端(SocialAuthController)
- 新增 config/cors.php 允許前端 origin
- .gitignore 新增 frontend/ 排除規則
前端(frontend/):
- Vue 3 + Vite + Tailwind CSS + Pinia + Vue Router
- 頁面:首頁、課程列表、課程詳情、登入、註冊、個人資料、OAuth callback
- 整合至 Docker(multi-stage build,nginx 靜態服務於 port 5173)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
2026-05-10 01:41:28 +08:00 |
|
a620906209
|
6e7ec350a3
|
docs:移除coach swagger註解
|
2025-05-12 02:43:37 +08:00 |
|
a620906209
|
75e73542ff
|
docs:api文檔添加
|
2025-05-12 01:23:12 +08:00 |
|
a620906209
|
125d4bf8d8
|
fix:coach相關改provider
|
2025-05-12 01:22:09 +08:00 |
|
a620906209
|
3d7660a24c
|
init
|
2025-05-11 03:45:17 +08:00 |
|