Backend: - Add dashboard API router with widget endpoints - Create dashboard schemas for widget data - Add dashboard tests Frontend: - Enhance Dashboard page with widget components - Add dashboard service for API calls - Create reusable dashboard components OpenSpec: - Archive add-dashboard-widgets change - Add dashboard capability specs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
4.8 KiB
4.8 KiB
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.
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
- Single API Call: Frontend makes one request instead of three
- Query Optimization: Task stats use COUNT queries, not full rows
- Caching: Health summary already cached in Redis (5 min TTL)
- 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