# Design: Dashboard Widgets ## Architecture Overview ``` ┌─────────────────────────────────────────────────────────────┐ │ Dashboard Page │ ├─────────────────────────────────────────────────────────────┤ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌────────┐ │ │ │ My Tasks │ │ Due This │ │ Overdue │ │ Done % │ │ │ │ 12 │ │ Week: 5 │ │ 2 │ │ 78% │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ ┌──────────────────────────┐ ┌───────────────────────────┐ │ │ │ My Workload │ │ Project Health │ │ │ │ ┌────────────────────┐ │ │ ┌───────────────────────┐ │ │ │ │ │ 32h / 40h (80%) │ │ │ │ 8 Healthy | 2 At Risk │ │ │ │ │ │ ████████░░ │ │ │ │ Avg Score: 76% │ │ │ │ │ └────────────────────┘ │ │ └───────────────────────┘ │ │ │ └──────────────────────────┘ └───────────────────────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ Quick Actions: [Spaces] [Workload] [Health] [Audit*] │ └─────────────────────────────────────────────────────────────┘ ``` ## API Design ### GET /api/dashboard Single endpoint aggregates all dashboard data to minimize frontend requests. ```typescript interface DashboardResponse { task_stats: { assigned_count: number // Total tasks assigned to user due_this_week: number // Tasks with due_date in current week overdue_count: number // Tasks past due_date, not completed completion_rate: number // Percentage (0-100) } workload: { allocated_hours: number capacity_hours: number load_percentage: number load_level: 'normal' | 'warning' | 'overloaded' } health_summary: { total_projects: number healthy_count: number at_risk_count: number critical_count: number average_health_score: number } } ``` ## Data Sources | Widget | Source | Notes | |--------|--------|-------| | Task Statistics | `pjctrl_tasks` table | Filter by assignee_id = current user | | Workload | Existing `WorkloadService` | Reuse get_user_workload_detail() | | Health Summary | Existing `HealthService` | Reuse get_dashboard() summary | ## Performance Considerations 1. **Single API Call**: Frontend makes one request instead of three 2. **Query Optimization**: Task stats use COUNT queries, not full rows 3. **Caching**: Health summary already cached in Redis (5 min TTL) 4. **No N+1**: Avoid loading related entities for counts ## Component Structure ``` frontend/src/ ├── pages/ │ └── Dashboard.tsx # Main page (modified) ├── components/ │ ├── dashboard/ │ │ ├── StatisticsCard.tsx # Single stat card │ │ ├── WorkloadWidget.tsx # Workload progress bar │ │ ├── HealthWidget.tsx # Health summary │ │ └── QuickActions.tsx # Navigation links └── services/ └── dashboard.ts # API service (new) ``` ## Trade-offs ### Decision: Single vs Multiple API Endpoints **Chosen**: Single `/api/dashboard` endpoint **Rationale**: - Reduces network round-trips (1 vs 3) - Simpler frontend loading state management - Data is always consistent (same timestamp) **Rejected Alternative**: Use existing endpoints directly - Would require 3 parallel requests - More complex error handling - Harder to ensure data consistency