feat: implement user authentication module
- Backend (FastAPI): - External API authentication (pj-auth-api.vercel.app) - JWT token validation with Redis session storage - RBAC with department isolation - User, Role, Department models with pjctrl_ prefix - Alembic migrations with project-specific version table - Complete test coverage (13 tests) - Frontend (React + Vite): - AuthContext for state management - Login page with error handling - Protected route component - Dashboard with user info display - OpenSpec: - 7 capability specs defined - add-user-auth change archived 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
154
openspec/specs/user-auth/spec.md
Normal file
154
openspec/specs/user-auth/spec.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# User Authentication & Authorization
|
||||
|
||||
## Purpose
|
||||
|
||||
使用者認證與授權系統,透過外部認證 API 進行身份驗證,提供細部權限控制。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: API-Based Authentication
|
||||
系統 SHALL 限定使用外部認證 API (https://pj-auth-api.vercel.app) 進行登入認證,不支援其他認證方式。
|
||||
|
||||
#### Scenario: API 登入成功
|
||||
- **GIVEN** 使用者擁有有效的企業帳號
|
||||
- **WHEN** 使用者透過前端提交憑證
|
||||
- **THEN** 系統呼叫 https://pj-auth-api.vercel.app 驗證憑證
|
||||
- **AND** 驗證成功後建立 session 並回傳 JWT token
|
||||
|
||||
#### Scenario: API 登入失敗
|
||||
- **GIVEN** 使用者提供無效的憑證
|
||||
- **WHEN** 使用者嘗試登入
|
||||
- **THEN** 認證 API 回傳錯誤
|
||||
- **AND** 系統拒絕登入並顯示錯誤訊息
|
||||
- **AND** 記錄失敗的登入嘗試
|
||||
|
||||
#### Scenario: 認證 API 無法連線
|
||||
- **GIVEN** 認證 API 服務無法連線
|
||||
- **WHEN** 使用者嘗試登入
|
||||
- **THEN** 系統顯示服務暫時無法使用的訊息
|
||||
- **AND** 記錄連線失敗事件
|
||||
|
||||
### Requirement: System Administrator
|
||||
系統 SHALL 預設一個系統管理員帳號,擁有所有權限。系統管理員帳號必須存在於外部認證系統,且登入流程仍需透過外部認證 API;不允許本地繞過認證。
|
||||
|
||||
#### Scenario: 預設管理員帳號
|
||||
- **GIVEN** 系統初始化完成
|
||||
- **WHEN** 系統啟動
|
||||
- **THEN** 存在預設管理員帳號 `ymirliu@panjit.com.tw`
|
||||
- **AND** 該帳號擁有 `super_admin` 角色
|
||||
- **AND** 該帳號不可被刪除或降級
|
||||
|
||||
#### Scenario: 管理員登入流程
|
||||
- **GIVEN** 管理員帳號 `ymirliu@panjit.com.tw` 需要登入
|
||||
- **WHEN** 管理員提交憑證
|
||||
- **THEN** 系統仍需呼叫 https://pj-auth-api.vercel.app 驗證
|
||||
- **AND** 不存在任何本地繞過認證的機制
|
||||
- **AND** 驗證成功後才授予 `super_admin` 權限
|
||||
|
||||
#### Scenario: 管理員全域權限
|
||||
- **GIVEN** 管理員帳號 `ymirliu@panjit.com.tw` 已通過 API 認證並登入
|
||||
- **WHEN** 管理員存取任何資源
|
||||
- **THEN** 系統允許存取,無視部門隔離限制
|
||||
|
||||
### Requirement: Role-Based Access Control
|
||||
系統 SHALL 支援基於角色的存取控制 (RBAC)。
|
||||
|
||||
#### Scenario: 角色權限檢查
|
||||
- **GIVEN** 使用者被指派特定角色 (如:工程師、主管、PMO)
|
||||
- **WHEN** 使用者嘗試存取受保護的資源
|
||||
- **THEN** 系統根據角色權限決定是否允許存取
|
||||
|
||||
#### Scenario: 角色指派
|
||||
- **GIVEN** 管理員擁有使用者管理權限
|
||||
- **WHEN** 管理員為使用者指派角色
|
||||
- **THEN** 系統更新使用者的角色設定
|
||||
- **AND** 新權限立即生效
|
||||
|
||||
### Requirement: Department Isolation
|
||||
系統 SHALL 實施部門級別的資料隔離,確保跨部門資料安全。
|
||||
|
||||
#### Scenario: 部門資料隔離
|
||||
- **GIVEN** 使用者屬於研發部門
|
||||
- **WHEN** 使用者嘗試存取廠務部門的專案
|
||||
- **THEN** 系統拒絕存取並顯示無權限訊息
|
||||
|
||||
#### Scenario: 跨部門專案存取
|
||||
- **GIVEN** 專案被設定為跨部門可見
|
||||
- **WHEN** 不同部門的使用者嘗試存取該專案
|
||||
- **THEN** 系統根據專案的 Security_Level 設定決定是否允許存取
|
||||
|
||||
### Requirement: Session Management
|
||||
系統 SHALL 管理使用者 session,包含過期與登出機制。
|
||||
|
||||
#### Scenario: Session 過期
|
||||
- **GIVEN** 使用者已登入系統
|
||||
- **WHEN** Session 超過設定的有效期限
|
||||
- **THEN** 系統自動使 session 失效
|
||||
- **AND** 使用者需重新登入
|
||||
|
||||
#### Scenario: 主動登出
|
||||
- **GIVEN** 使用者已登入系統
|
||||
- **WHEN** 使用者執行登出操作
|
||||
- **THEN** 系統銷毀 session 並清除 token
|
||||
|
||||
## Data Model
|
||||
|
||||
```
|
||||
pjctrl_users
|
||||
├── id: UUID (PK)
|
||||
├── email: VARCHAR(200) UNIQUE
|
||||
├── name: VARCHAR(200)
|
||||
├── department_id: UUID (FK)
|
||||
├── role_id: UUID (FK)
|
||||
├── skills: JSON
|
||||
├── capacity: DECIMAL (週工時上限)
|
||||
├── is_active: BOOLEAN
|
||||
├── is_system_admin: BOOLEAN DEFAULT false (不可修改的系統管理員標記)
|
||||
├── created_at: TIMESTAMP
|
||||
└── updated_at: TIMESTAMP
|
||||
|
||||
pjctrl_departments
|
||||
├── id: UUID (PK)
|
||||
├── name: VARCHAR(100)
|
||||
├── parent_id: UUID (FK, self-reference)
|
||||
└── created_at: TIMESTAMP
|
||||
|
||||
pjctrl_roles
|
||||
├── id: UUID (PK)
|
||||
├── name: VARCHAR(50)
|
||||
├── permissions: JSON
|
||||
├── is_system_role: BOOLEAN DEFAULT false
|
||||
└── created_at: TIMESTAMP
|
||||
```
|
||||
|
||||
## Default Data (Seed)
|
||||
|
||||
```sql
|
||||
-- 預設系統管理員角色
|
||||
INSERT INTO pjctrl_roles (id, name, permissions, is_system_role) VALUES
|
||||
('00000000-0000-0000-0000-000000000001', 'super_admin', '{"all": true}', true);
|
||||
|
||||
-- 預設系統管理員帳號
|
||||
INSERT INTO pjctrl_users (id, email, name, role_id, is_active, is_system_admin) VALUES
|
||||
('00000000-0000-0000-0000-000000000001', 'ymirliu@panjit.com.tw', 'System Administrator',
|
||||
'00000000-0000-0000-0000-000000000001', true, true);
|
||||
```
|
||||
|
||||
## External Dependencies
|
||||
|
||||
- **Authentication API**: https://pj-auth-api.vercel.app (唯一認證方式)
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
```
|
||||
┌─────────┐ ┌─────────────┐ ┌──────────────────────────┐
|
||||
│ User │────▶│ Frontend │────▶│ pj-auth-api.vercel.app │
|
||||
└─────────┘ └─────────────┘ └──────────────────────────┘
|
||||
│ │
|
||||
│◀────── JWT Token ───────│
|
||||
│
|
||||
▼
|
||||
┌─────────────┐
|
||||
│ Backend │ (驗證 JWT, 建立 Session)
|
||||
└─────────────┘
|
||||
```
|
||||
Reference in New Issue
Block a user