Files
CFDivePlatform/openspec/specs/coach-portal-ui/spec.md
T
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

107 lines
4.3 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.
## ADDED Requirements
### Requirement: 教練註冊頁
前端 SHALL 提供 `/coach/register` 頁面,供教練填寫帳號資訊與業者資料後申請帳號,成功後導向 `/coach/login`
#### Scenario: 註冊成功
- **WHEN** 教練填入必填欄位(name / email / password / password_confirmation)並送出
- **THEN** 呼叫 `POST /api/provider/register`,成功後導向 `/coach/login?registered=1`,顯示「註冊成功,請登入」提示
#### Scenario: Email 重複
- **WHEN** 送出已存在的 email
- **THEN** 頁面顯示後端回傳的錯誤訊息,不跳轉
#### Scenario: 密碼不一致
- **WHEN** password 與 password_confirmation 不一致
- **THEN** 後端回傳 422,頁面顯示欄位錯誤提示
#### Scenario: business_name 為選填
- **WHEN** 教練不填寫工作室名稱直接送出
- **THEN** 正常完成註冊,business_name 存為 null
---
### Requirement: 教練登入頁
前端 SHALL 提供 `/coach/login` 頁面,供教練以 email/password 登入,成功後導向 `/coach/dashboard`
#### Scenario: 登入成功
- **WHEN** 教練填入正確帳密並送出
- **THEN** 呼叫 `POST /api/provider/login`token 存入 coachAuth storelocalStorage key: coach_token),導向 `/coach/dashboard`
#### Scenario: 登入失敗
- **WHEN** 帳密錯誤
- **THEN** 頁面顯示錯誤訊息,不跳轉
#### Scenario: 已登入教練訪問登入頁
- **WHEN** coachAuth.isLoggedIn 為 true 時訪問 `/coach/login`
- **THEN** 自動導向 `/coach/dashboard`
---
### Requirement: 課程 Dashboard
前端 SHALL 提供 `/coach/dashboard` 頁面(需教練登入),顯示自己的課程列表,並提供新增、編輯、刪除操作入口。
#### Scenario: 載入課程列表
- **WHEN** 已登入教練訪問 Dashboard
- **THEN** 呼叫 `GET /api/provider/offers`,以表格或卡片渲染課程(標題、地點、價格、狀態)
#### Scenario: 無課程時顯示空狀態
- **WHEN** 教練尚無課程
- **THEN** 顯示「尚無課程,立即新增第一堂課」提示與新增按鈕
#### Scenario: 刪除課程確認
- **WHEN** 教練點擊刪除按鈕
- **THEN** 顯示確認提示,確認後呼叫 `DELETE /api/provider/offers/{id}`,成功後更新列表
---
### Requirement: 新增課程表單
前端 SHALL 提供 `/coach/offers/new` 頁面,教練填寫課程資訊後送出新增。
#### Scenario: 新增課程成功
- **WHEN** 教練填入所有必填欄位並送出
- **THEN** 呼叫 `POST /api/provider/offers`,成功後導向 `/coach/dashboard` 並顯示成功提示
#### Scenario: 表單驗證失敗
- **WHEN** 必填欄位(title / location / price)為空
- **THEN** 前端顯示欄位錯誤提示,不送出 API
---
### Requirement: 編輯課程表單
前端 SHALL 提供 `/coach/offers/:id/edit` 頁面,預填現有課程資料供教練修改。
#### Scenario: 載入課程資料並編輯
- **WHEN** 教練訪問編輯頁
- **THEN** 從 Dashboard 傳入或呼叫 API 取得課程資料,預填表單,送出後呼叫 `PUT /api/provider/offers/{id}`,成功後返回 Dashboard
#### Scenario: 無權限編輯
- **WHEN** API 回傳 403
- **THEN** 頁面顯示「無權限修改此課程」並返回 Dashboard
---
### Requirement: 教練個人資料頁
前端 SHALL 提供 `/coach/profile` 頁面(需教練登入),顯示並允許更新教練基本資訊與專業資料。
#### Scenario: 讀取並更新資料
- **WHEN** 教練訪問個人資料頁
- **THEN** 呼叫 `GET /api/provider/profile`,顯示 name / email / bio / expertise / certification,儲存時呼叫 `PUT /api/provider/profile`
---
### Requirement: Coach 路由守衛
前端 SHALL 對所有 `/coach/*` 路由(login 除外)加上 navigation guard,未登入時導向 `/coach/login`。auth state 以 sessionStorage 為來源,API 請求支援 refresh-then-retry。
#### Scenario: 未登入訪問 Dashboard
- **WHEN** 未登入使用者直接訪問 `/coach/dashboard`
- **THEN** 自動導向 `/coach/login`
#### Scenario: 分頁關閉後重開需重新登入
- **WHEN** 教練關閉分頁後重新開啟 `/coach/dashboard`
- **THEN** sessionStorage 已清除,自動導向 `/coach/login`
#### Scenario: 登出
- **WHEN** 教練點擊登出
- **THEN** 呼叫 `POST /api/provider/logout`,清除 sessionStorage coach_token / coach_user,導向 `/coach/login`