feat: implement workload heatmap module
- Backend (FastAPI):
- Workload heatmap API with load level calculation
- User workload detail endpoint with task breakdown
- Redis caching for workload calculations (1hr TTL)
- Department isolation and access control
- WorkloadSnapshot model for historical data
- Alembic migration for workload_snapshots table
- API Endpoints:
- GET /api/workload/heatmap - Team workload overview
- GET /api/workload/user/{id} - User workload detail
- GET /api/workload/me - Current user workload
- Load Levels:
- normal: <80%, warning: 80-99%, overloaded: >=100%
- Tests:
- 26 unit/API tests
- 15 E2E automated tests
- 77 total tests passing
- OpenSpec:
- add-resource-workload change archived
- resource-management spec updated
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
78
backend/app/schemas/workload.py
Normal file
78
backend/app/schemas/workload.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional, List
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class LoadLevel(str, Enum):
|
||||
"""Workload level classification."""
|
||||
NORMAL = "normal"
|
||||
WARNING = "warning"
|
||||
OVERLOADED = "overloaded"
|
||||
UNAVAILABLE = "unavailable"
|
||||
|
||||
|
||||
class TaskWorkloadInfo(BaseModel):
|
||||
"""Task information for workload detail view."""
|
||||
task_id: str
|
||||
title: str
|
||||
project_id: str
|
||||
project_name: str
|
||||
due_date: Optional[datetime] = None
|
||||
original_estimate: Optional[Decimal] = None
|
||||
status: Optional[str] = None
|
||||
|
||||
|
||||
class UserWorkloadSummary(BaseModel):
|
||||
"""Summary of a user's workload for heatmap display."""
|
||||
user_id: str
|
||||
user_name: str
|
||||
department_id: Optional[str] = None
|
||||
department_name: Optional[str] = None
|
||||
capacity_hours: Decimal
|
||||
allocated_hours: Decimal
|
||||
load_percentage: Optional[Decimal] = None
|
||||
load_level: LoadLevel
|
||||
task_count: int
|
||||
|
||||
|
||||
class WorkloadHeatmapResponse(BaseModel):
|
||||
"""Response for workload heatmap API."""
|
||||
week_start: date
|
||||
week_end: date
|
||||
users: List[UserWorkloadSummary]
|
||||
|
||||
|
||||
class UserWorkloadDetail(BaseModel):
|
||||
"""Detailed workload for a specific user."""
|
||||
user_id: str
|
||||
user_name: str
|
||||
week_start: date
|
||||
week_end: date
|
||||
capacity_hours: Decimal
|
||||
allocated_hours: Decimal
|
||||
load_percentage: Optional[Decimal] = None
|
||||
load_level: LoadLevel
|
||||
tasks: List[TaskWorkloadInfo]
|
||||
|
||||
|
||||
class WorkloadSnapshotResponse(BaseModel):
|
||||
"""Response for workload snapshot."""
|
||||
id: str
|
||||
user_id: str
|
||||
week_start: date
|
||||
allocated_hours: Decimal
|
||||
capacity_hours: Decimal
|
||||
load_percentage: Decimal
|
||||
task_count: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class CapacityUpdate(BaseModel):
|
||||
"""Request to update user capacity."""
|
||||
capacity: Decimal
|
||||
Reference in New Issue
Block a user