Files
PROJECT-CONTORL/openspec/specs/resource-management/spec.md
beabigegg 9b220523ff feat: complete issue fixes and implement remaining features
## Critical Issues (CRIT-001~003) - All Fixed
- JWT secret key validation with pydantic field_validator
- Login audit logging for success/failure attempts
- Frontend API path prefix removal

## High Priority Issues (HIGH-001~008) - All Fixed
- Project soft delete using is_active flag
- Redis session token bytes handling
- Rate limiting with slowapi (5 req/min for login)
- Attachment API permission checks
- Kanban view with drag-and-drop
- Workload heatmap UI (WorkloadPage, WorkloadHeatmap)
- TaskDetailModal integrating Comments/Attachments
- UserSelect component for task assignment

## Medium Priority Issues (MED-001~012) - All Fixed
- MED-001~005: DB commits, N+1 queries, datetime, error format, blocker flag
- MED-006: Project health dashboard (HealthService, ProjectHealthPage)
- MED-007: Capacity update API (PUT /api/users/{id}/capacity)
- MED-008: Schedule triggers (cron parsing, deadline reminders)
- MED-009: Watermark feature (image/PDF watermarking)
- MED-010~012: useEffect deps, DOM operations, PDF export

## New Files
- backend/app/api/health/ - Project health API
- backend/app/services/health_service.py
- backend/app/services/trigger_scheduler.py
- backend/app/services/watermark_service.py
- backend/app/core/rate_limiter.py
- frontend/src/pages/ProjectHealthPage.tsx
- frontend/src/components/ProjectHealthCard.tsx
- frontend/src/components/KanbanBoard.tsx
- frontend/src/components/WorkloadHeatmap.tsx

## Tests
- 113 new tests passing (health: 32, users: 14, triggers: 35, watermark: 32)

## OpenSpec Archives
- add-project-health-dashboard
- add-capacity-update-api
- add-schedule-triggers
- add-watermark-feature
- add-rate-limiting
- enhance-frontend-ux
- add-resource-management-ui

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 21:49:52 +08:00

182 lines
6.7 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.

# Resource Management
## Purpose
資源管理系統,提供負載熱圖與人員容量追蹤,協助主管進行資源分配決策。讓主管能即時掌握團隊成員的工作負載狀況,及早發現超載或閒置問題,優化資源分配。
## Requirements
### Requirement: Workload Heatmap
系統 SHALL 提供負載熱圖 API自動統計每人每週分配的任務總時數並以顏色等級表示負載狀態。
#### Scenario: 負載正常顯示
- **GIVEN** 某人員本週被指派的任務總時數低於其容量的 80%
- **WHEN** 主管查詢負載熱圖 API
- **THEN** 該人員的 `load_level``normal`
- **AND** 回傳包含 `load_percentage``allocated_hours``capacity_hours`
#### Scenario: 負載警告顯示
- **GIVEN** 某人員本週被指派的任務總時數達到其容量的 80%-99%
- **WHEN** 主管查詢負載熱圖 API
- **THEN** 該人員的 `load_level``warning`
#### Scenario: 負載超載顯示
- **GIVEN** 某人員本週被指派的任務總時數達到或超過其容量的 100%
- **WHEN** 主管查詢負載熱圖 API
- **THEN** 該人員的 `load_level``overloaded`
#### Scenario: 查詢特定週的負載
- **GIVEN** 主管需要查看非當週的負載
- **WHEN** 主管以 `week_start` 參數查詢負載熱圖 API
- **THEN** 系統回傳該週的負載資料
#### Scenario: 快取機制
- **GIVEN** 負載資料已被計算並快取
- **WHEN** 相同查詢在 1 小時內再次發生
- **THEN** 系統從 Redis 快取回傳結果
### Requirement: Capacity Planning
系統 SHALL 支援人員容量規劃,包含預設容量與臨時調整。
#### Scenario: 設定人員預設容量
- **GIVEN** 管理者需要設定人員的週工時上限
- **WHEN** 管理者更新使用者的 `capacity`
- **THEN** 系統儲存新的容量設定
- **AND** 後續負載計算使用新容量值
#### Scenario: 容量為零處理
- **GIVEN** 使用者的容量設為 0
- **WHEN** 系統計算該使用者的負載
- **THEN** `load_percentage` 顯示為 `null`
- **AND** `load_level` 顯示為 `unavailable`
#### Scenario: 容量更新 API
- **GIVEN** 管理者需要更新團隊成員的容量
- **WHEN** 管理者呼叫 `PUT /api/users/{user_id}/capacity` 並提供新容量值
- **THEN** 系統驗證容量值在有效範圍內 (0-168 小時)
- **AND** 更新使用者的 capacity 欄位
- **AND** 記錄變更至稽核日誌
#### Scenario: 容量更新權限控制
- **GIVEN** 一般使用者嘗試更新他人容量
- **WHEN** 使用者呼叫 `PUT /api/users/{other_id}/capacity`
- **THEN** 系統拒絕請求並回傳 403 Forbidden
### Requirement: Multi-Project Health Dashboard
系統 SHALL 提供多專案健康看板,讓主管一覽所有專案狀態。
#### Scenario: 專案健康總覽
- **GIVEN** 主管負責多個專案
- **WHEN** 主管開啟健康看板
- **THEN** 顯示所有專案的進度、風險指標、延遲任務數
- **AND** 可依風險程度排序
#### Scenario: 專案延遲警示
- **GIVEN** 專案有任務超過截止日期
- **WHEN** 主管查看健康看板
- **THEN** 該專案標示為延遲狀態
- **AND** 顯示延遲任務數量與影響
#### Scenario: 專案健康 API
- **GIVEN** 後端系統運行中
- **WHEN** 客戶端請求 `GET /api/projects/health`
- **THEN** 系統回傳所有可存取專案的健康數據
- **AND** 包含 `total_tasks`, `completed_tasks`, `overdue_tasks`, `blocked_tasks`, `risk_score`
#### Scenario: 單一專案健康詳情
- **GIVEN** 主管需要查看特定專案詳情
- **WHEN** 客戶端請求 `GET /api/projects/{id}/health`
- **THEN** 系統回傳該專案的詳細健康數據
- **AND** 包含任務分類統計與風險評估
### Requirement: Team Workload Distribution
系統 SHALL 提供團隊工作分配查詢功能。
#### Scenario: 部門負載總覽
- **GIVEN** 主管需要了解部門整體負載
- **WHEN** 主管以 `department_id` 參數查詢負載熱圖 API
- **THEN** 僅顯示該部門成員的負載狀況
#### Scenario: 使用者負載詳情
- **GIVEN** 主管需要了解某人的詳細任務分配
- **WHEN** 主管查詢使用者負載詳情 API
- **THEN** 回傳該週指派給該使用者的所有任務
- **AND** 包含每個任務的 `original_estimate``due_date`
### Requirement: Workload Data Access Control
系統 SHALL 限制負載資料的存取權限。
#### Scenario: 系統管理員查看所有人
- **GIVEN** 登入者為 `super_admin`
- **WHEN** 查詢負載熱圖 API
- **THEN** 可查看所有使用者的負載資料
#### Scenario: 一般使用者查看自己
- **GIVEN** 登入者為一般使用者
- **WHEN** 查詢負載熱圖 API 未指定 `user_ids`
- **THEN** 僅回傳自己的負載資料
#### Scenario: 跨部門存取拒絕
- **GIVEN** 登入者非系統管理員
- **WHEN** 查詢其他部門使用者的負載
- **THEN** 系統拒絕存取並回傳 403 Forbidden
### Requirement: Workload Heatmap UI
The system SHALL provide a visual workload heatmap interface for managers.
#### Scenario: View workload heatmap
- **GIVEN** user is logged in as manager or admin
- **WHEN** user navigates to /workload page
- **THEN** system displays a heatmap showing all accessible users' workload
- **AND** each user cell is color-coded by load level (green/yellow/red)
#### Scenario: Navigate between weeks
- **GIVEN** user is viewing the workload page
- **WHEN** user clicks previous/next week buttons
- **THEN** the heatmap updates to show that week's workload data
#### Scenario: View user workload details
- **GIVEN** user is viewing the workload heatmap
- **WHEN** user clicks on a specific user's cell
- **THEN** a modal/drawer opens showing that user's task breakdown
- **AND** tasks show title, project, time estimate, and due date
#### Scenario: Filter by department
- **GIVEN** user is a system admin
- **WHEN** user selects a department from the filter
- **THEN** the heatmap shows only users from that department
## Data Model
```
pjctrl_workload_snapshots
├── id: UUID (PK)
├── user_id: UUID (FK -> users)
├── week_start: DATE
├── allocated_hours: DECIMAL
├── capacity_hours: DECIMAL
├── load_percentage: DECIMAL
├── created_at: TIMESTAMP
└── updated_at: TIMESTAMP
pjctrl_project_health
├── id: UUID (PK)
├── project_id: UUID (FK -> projects)
├── snapshot_date: DATE
├── total_tasks: INT
├── completed_tasks: INT
├── overdue_tasks: INT
├── blocked_tasks: INT
├── risk_score: DECIMAL
├── created_at: TIMESTAMP
└── updated_at: TIMESTAMP
```
## Calculation Rules
- **負載百分比** = (allocated_hours / capacity_hours) × 100
- **風險評分** = f(overdue_tasks, blocked_tasks, timeline_remaining)
- 快取計算結果於 Redis每小時更新或任務變更時即時更新