Archived proposals:
- add-trigger-conditions-weekly-subscription: Trigger conditions and weekly subscription
- update-api-consistency: WebSocket auth, optimistic locking, workload defaults
All implementations were already complete in previous commits (f5f870d).
Updated tasks.md with implementation summary.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
11 KiB
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
Requirement: API Rate Limiting
The system SHALL implement rate limiting to protect against brute force attacks and DoS attempts.
Scenario: Login rate limit enforcement
- GIVEN a client IP has made 5 login attempts within 1 minute
- WHEN the client attempts another login
- THEN the system returns HTTP 429 Too Many Requests
- AND the response includes a Retry-After header
Scenario: Rate limit window reset
- GIVEN a client has exceeded the rate limit
- WHEN the rate limit window expires (1 minute)
- THEN the client can make new requests
Scenario: Rate limit per IP
- GIVEN rate limiting is IP-based
- WHEN different IPs make requests
- THEN each IP has its own rate limit counter
Requirement: Comprehensive API Rate Limiting
The system SHALL enforce rate limits on all sensitive API endpoints to prevent abuse and ensure service availability.
Scenario: Task creation rate limit exceeded
- WHEN user exceeds 60 task creation requests per minute
- THEN system returns 429 Too Many Requests
- THEN response includes Retry-After header
Scenario: Report generation rate limit exceeded
- WHEN user exceeds 5 report generation requests per minute
- THEN system returns 429 Too Many Requests
- THEN response includes rate limit headers
Scenario: Rate limit headers provided
- WHEN user makes any rate-limited API request
- THEN response includes X-RateLimit-Limit header
- THEN response includes X-RateLimit-Remaining header
- THEN response includes X-RateLimit-Reset header
Scenario: Rate limit window reset
- WHEN rate limit window expires
- THEN user can make requests again up to the limit
- THEN X-RateLimit-Remaining resets to maximum
Requirement: Input Length Validation
The system SHALL enforce maximum length limits on all user-provided string inputs to prevent DoS attacks and database overflow.
Scenario: Task title exceeds maximum length
- WHEN user submits a task with title longer than 500 characters
- THEN system returns 422 Validation Error with descriptive message
Scenario: Description field within limits
- WHEN user submits content with description under 10000 characters
- THEN system accepts the input and processes normally
Requirement: Secure WebSocket Authentication
The system SHALL authenticate WebSocket connections without exposing tokens in URL query parameters.
Scenario: WebSocket connection with token in first message
- WHEN client connects to WebSocket endpoint without a query token
- THEN server waits for authentication message containing JWT token
- THEN server validates token before accepting further messages
- THEN server sends an authentication acknowledgment message
Scenario: WebSocket connection with invalid token
- WHEN client sends an invalid or expired token
- THEN server sends an error message indicating invalid or expired token
- THEN server closes the connection with an authentication error code
Scenario: WebSocket connection timeout without authentication
- WHEN client connects but does not send authentication within 10 seconds
- THEN server closes the connection with appropriate error code
Requirement: Path Traversal Protection
The system SHALL prevent file path traversal attacks by validating all file paths resolve within the designated storage directory.
Scenario: Path traversal attempt detected
- WHEN request contains file path with "../" or absolute path outside storage
- THEN system rejects request and logs security warning
- THEN system returns 403 Forbidden error
Scenario: Valid file path within storage
- WHEN request contains valid relative file path
- THEN system resolves path and verifies it is within storage directory
- THEN system processes file operation normally
Requirement: JWT Secret Validation
The system SHALL validate JWT secret key strength on startup.
Scenario: Weak secret rejected
- WHEN the configured JWT secret is less than 32 characters
- THEN the system SHALL log a critical warning
- AND optionally refuse to start in production mode
Scenario: Low entropy secret warning
- WHEN the JWT secret has low entropy (repeating patterns, common words)
- THEN the system SHALL log a security warning
Requirement: CSRF Protection
The system SHALL protect sensitive state-changing operations with CSRF tokens.
Scenario: CSRF token required for password change
- WHEN a user attempts to change their password
- AND the request does not include a valid CSRF token
- THEN the request SHALL be rejected with 403 Forbidden
Scenario: CSRF token required for account deletion
- WHEN a user attempts to delete their account or resources
- AND the request does not include a valid CSRF token
- THEN the request SHALL be rejected with 403 Forbidden
Scenario: Valid CSRF token accepted
- WHEN a state-changing request includes a valid CSRF token
- THEN the request SHALL proceed normally
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)
-- 預設系統管理員角色
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)
└─────────────┘