依 autoflow-agent workspace v2 設計把 PRD / 設計 / 架構 / 交付類 共享文件從個人層 .autoflow/(ignored)搬到 docs/autoflow/(進 git), 讓團隊可共享產品與架構文件,個人層只留 progress / review / testing 等 per-branch 筆記。 - 02-prd/ 21 個檔(PRD、features、market-analysis 等) - 03-design/ 18 個檔(design-spec、wireframes、flows 等) - 04-architecture/ 31 個檔(TDD、design-doc、ADR×14、API 規格等) - 07-delivery/ 3 個檔(project-summary、phase-0.6-handover、stage-deployment-setup) 合計 73 檔。原檔已從 .autoflow/ 移除(migration 工具執行 git mv, 但因 .autoflow/ 在 .gitignore 中、git 將此操作視為新增、無 rename history)。
201 lines
5.9 KiB
Markdown
201 lines
5.9 KiB
Markdown
# Feature:會員系統(P0 介面;實作 TODO → Phase 1)
|
||
|
||
> 父文件:[PRD.md](../PRD.md) | 對應 User Stories:US-01、US-02、US-13、US-22、US-TODO-01、US-TODO-02、US-TODO-03
|
||
>
|
||
> **⚠️ 重要**:本功能**只在 Phase 0 定義介面**,**不實作真實 Auth**。
|
||
> Phase 0 的目標是讓雛形「看起來像有 Auth」:前端頁面有、後端 API 有、存個假的 session cookie,但 token 不驗簽、user 不落 DB。
|
||
> Phase 1 再換成真實 Auth(JWT / OAuth + DB)。
|
||
|
||
---
|
||
|
||
## 範圍說明
|
||
|
||
| Phase 0 做 | Phase 1 做 |
|
||
|-----------|-----------|
|
||
| 登入頁 / 註冊頁 UI | 真實 Auth 後端 |
|
||
| POST /api/auth/login / register 的 stub handler | JWT 簽發 / 驗證 |
|
||
| 簡易 session cookie(in-memory) | Refresh token rotation |
|
||
| 個人設定頁 UI 骨架 | 密碼重設流程 |
|
||
| 登出功能(清 cookie) | Email 驗證 |
|
||
| — | OAuth(Google / GitHub) |
|
||
| — | 2FA |
|
||
| — | 權限 / Role 系統 |
|
||
|
||
---
|
||
|
||
## 使用者行為(Phase 0)
|
||
|
||
### 登入頁(`/login`)
|
||
|
||
- Email + 密碼輸入
|
||
- 「登入」按鈕
|
||
- 「還沒有帳號?註冊」連結
|
||
- (Phase 1):忘記密碼連結、OAuth 按鈕
|
||
|
||
### 註冊頁(`/register`)
|
||
|
||
- Email + 密碼 + 確認密碼
|
||
- 「建立帳號」按鈕
|
||
- Phase 0:submit 後直接登入(in-memory 記一個 user)
|
||
- Phase 1:寄 email 驗證 + 存 DB
|
||
|
||
### 個人設定頁(`/account`)
|
||
|
||
Phase 0:只做 UI 骨架,顯示 user email + 登出按鈕。
|
||
|
||
Phase 1 加:
|
||
- 密碼變更
|
||
- Email 變更
|
||
- 頭像上傳
|
||
- 刪除帳號
|
||
- 2FA 設定
|
||
- 已連結的 OAuth 提供者
|
||
- API Key 管理
|
||
|
||
### 登出
|
||
|
||
- 清除前端 token / cookie
|
||
- 導回 `/login`
|
||
|
||
---
|
||
|
||
## 技術細節(給 Architect 參考)
|
||
|
||
### AuthProvider 介面
|
||
|
||
Phase 0 要定義清楚介面,Phase 1 直接換實作。
|
||
|
||
```go
|
||
// internal/auth/provider.go
|
||
type AuthProvider interface {
|
||
Register(ctx context.Context, email, password string) (*User, error)
|
||
Login(ctx context.Context, email, password string) (*Session, error)
|
||
ValidateToken(ctx context.Context, token string) (*User, error)
|
||
Logout(ctx context.Context, token string) error
|
||
// Phase 1:
|
||
// RefreshToken(ctx context.Context, refreshToken string) (*Session, error)
|
||
// RequestPasswordReset(ctx context.Context, email string) error
|
||
// ConfirmPasswordReset(ctx context.Context, token, newPassword string) error
|
||
}
|
||
|
||
type User struct {
|
||
ID string
|
||
Email string
|
||
// Phase 1:更多欄位(Name、Avatar、Created、...)
|
||
}
|
||
|
||
type Session struct {
|
||
Token string
|
||
UserID string
|
||
ExpiresAt time.Time
|
||
// Phase 1:RefreshToken string
|
||
}
|
||
```
|
||
|
||
**Phase 0 實作:`StubAuthProvider`**
|
||
- 記憶體 `map[string]*User`(email → user)
|
||
- Session token = 隨機 32 字元(不簽、不驗)
|
||
- 註冊與登入不做任何安全檢查(接受任何密碼)
|
||
- 目的只是**讓前端能測整個流程**,不是真安全
|
||
|
||
**Phase 1 實作:`JWTAuthProvider`**
|
||
- bcrypt 存密碼
|
||
- JWT 簽發(有 secret)
|
||
- User 存 PostgreSQL
|
||
- Refresh Token rotation
|
||
- Rate limiting
|
||
|
||
### Auth Middleware
|
||
|
||
api-server 的所有需要登入的 endpoint 都過 middleware:
|
||
|
||
```go
|
||
func RequireAuth(provider AuthProvider) gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
token := extractToken(c) // from cookie or Authorization header
|
||
user, err := provider.ValidateToken(c.Request.Context(), token)
|
||
if err != nil {
|
||
c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
|
||
return
|
||
}
|
||
c.Set("user", user)
|
||
c.Next()
|
||
}
|
||
}
|
||
```
|
||
|
||
Phase 0 的 middleware 一樣跑,只是 `provider` 是 stub。
|
||
|
||
---
|
||
|
||
## API 端點(Phase 0)
|
||
|
||
| Method | Path | 說明 |
|
||
|--------|------|------|
|
||
| POST | `/api/auth/register` | 註冊(stub)|
|
||
| POST | `/api/auth/login` | 登入(stub)|
|
||
| POST | `/api/auth/logout` | 登出 |
|
||
| GET | `/api/auth/me` | 取得當前 user 資訊 |
|
||
|
||
Phase 1 加:
|
||
|
||
| Method | Path | 說明 |
|
||
|--------|------|------|
|
||
| POST | `/api/auth/refresh` | Refresh token |
|
||
| POST | `/api/auth/password/reset` | 請求密碼重設 |
|
||
| POST | `/api/auth/password/confirm` | 確認密碼重設 |
|
||
| POST | `/api/auth/oauth/{provider}` | OAuth callback |
|
||
| DELETE | `/api/account` | 刪除帳號 |
|
||
|
||
---
|
||
|
||
## 驗收條件(Phase 0)
|
||
|
||
- [ ] `/login`、`/register`、`/account` 三個頁面可打開
|
||
- [ ] 註冊 → 自動登入 → 跳轉到 `/`
|
||
- [ ] 已登入狀態下訪問 `/login` → 自動跳 `/`
|
||
- [ ] 未登入狀態下訪問需登入頁面(`/`、`/devices` 等)→ 跳 `/login`
|
||
- [ ] 登出後 cookie 清除
|
||
- [ ] 兩個不同 user 的資料互相隔離(裝置列表、模型等)
|
||
- [ ] AuthProvider 介面定義完整
|
||
- [ ] StubAuthProvider 實作能通過基本 flow
|
||
- [ ] `/account` 頁面顯示當前 email + 登出按鈕(其他欄位灰掉或 TODO 標記)
|
||
|
||
---
|
||
|
||
## Phase 0 的 TODO 清單(明確追蹤)
|
||
|
||
- **TODO-AUTH-01**:換 JWTAuthProvider(Phase 1 核心)
|
||
- **TODO-AUTH-02**:DB 層(PostgreSQL schema for users、sessions)
|
||
- **TODO-AUTH-03**:Email 驗證流程(需 email 服務,SendGrid / SES)
|
||
- **TODO-AUTH-04**:密碼重設流程
|
||
- **TODO-AUTH-05**:OAuth(Google、GitHub)
|
||
- **TODO-AUTH-06**:2FA(TOTP)
|
||
- **TODO-AUTH-07**:密碼強度規則
|
||
- **TODO-AUTH-08**:Rate limiting(防暴力)
|
||
- **TODO-AUTH-09**:Account 刪除(含所有裝置、模型、叢集清理)
|
||
- **TODO-AUTH-10**:個人設定頁完整功能
|
||
- **TODO-AUTH-11**:Role / Permission 系統(Phase 2,for 企業版)
|
||
- **TODO-AUTH-12**:API Key 管理(Phase 2)
|
||
|
||
---
|
||
|
||
## 安全警示(Phase 0 限制)
|
||
|
||
⚠️ **Phase 0 的 Auth 不是真的 Auth。絕對不能上線給真用戶。**
|
||
|
||
限制:
|
||
- 密碼明文比對(in-memory)
|
||
- Token 不簽、任何人偽造任何 token 都能通過
|
||
- 無 rate limiting
|
||
- 無 HTTPS 強制(Phase 0 dev 環境可能 http://)
|
||
|
||
**Phase 0 的 visionA Cloud 只給內部 FAE 測試**,不開放給外部。
|
||
|
||
---
|
||
|
||
## 連結
|
||
|
||
- 回:[PRD 索引](../PRD.md)
|
||
- 相關:[介面契約 — AuthProvider](../interface-contracts.md)
|