feat(dashboard): use real API data and add 3 more demo projects

Dashboard changes:
- Update useDashboard hook to fetch real projects from API
- Calculate stats (active projects, agents, issues) from real data
- Keep pending approvals as mock (no backend endpoint yet)

Demo data additions:
- API Gateway Modernization project (active, complex)
- Customer Analytics Dashboard project (completed)
- DevOps Pipeline Automation project (active, complex)
- Added sprints, agent instances, and issues for each new project

Total demo data: 6 projects, 14 agents, 22 issues

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-06 03:10:10 +01:00
parent 7ef217be39
commit 5a4d93df26
2 changed files with 367 additions and 119 deletions

View File

@@ -403,6 +403,45 @@
"settings": {
"mcp_servers": ["gitea", "knowledge-base"]
}
},
{
"name": "API Gateway Modernization",
"slug": "api-gateway",
"description": "Migrate legacy REST API gateway to modern GraphQL-based architecture with improved caching and rate limiting.",
"owner_email": "__admin__",
"autonomy_level": "milestone",
"status": "active",
"complexity": "complex",
"client_mode": "technical",
"settings": {
"mcp_servers": ["gitea", "knowledge-base"]
}
},
{
"name": "Customer Analytics Dashboard",
"slug": "analytics-dashboard",
"description": "Real-time analytics dashboard for customer behavior insights, cohort analysis, and predictive modeling.",
"owner_email": "__admin__",
"autonomy_level": "autonomous",
"status": "completed",
"complexity": "medium",
"client_mode": "auto",
"settings": {
"mcp_servers": ["gitea", "knowledge-base"]
}
},
{
"name": "DevOps Pipeline Automation",
"slug": "devops-automation",
"description": "Automate CI/CD pipelines with AI-assisted deployments, rollback detection, and infrastructure as code.",
"owner_email": "__admin__",
"autonomy_level": "full_control",
"status": "active",
"complexity": "complex",
"client_mode": "technical",
"settings": {
"mcp_servers": ["gitea", "knowledge-base"]
}
}
],
"sprints": [
@@ -445,6 +484,56 @@
"end_date": "2026-01-20",
"status": "active",
"planned_points": 18
},
{
"project_slug": "api-gateway",
"name": "Sprint 1: GraphQL Schema",
"number": 1,
"goal": "Define GraphQL schema and implement core resolvers for existing REST endpoints.",
"start_date": "2025-12-23",
"end_date": "2026-01-06",
"status": "completed",
"planned_points": 21
},
{
"project_slug": "api-gateway",
"name": "Sprint 2: Caching Layer",
"number": 2,
"goal": "Implement Redis-based caching layer and query batching.",
"start_date": "2026-01-06",
"end_date": "2026-01-20",
"status": "active",
"planned_points": 26
},
{
"project_slug": "analytics-dashboard",
"name": "Sprint 1: Data Pipeline",
"number": 1,
"goal": "Set up data ingestion pipeline and real-time event processing.",
"start_date": "2025-11-15",
"end_date": "2025-11-29",
"status": "completed",
"planned_points": 18
},
{
"project_slug": "analytics-dashboard",
"name": "Sprint 2: Dashboard UI",
"number": 2,
"goal": "Build interactive dashboard with charts and filtering capabilities.",
"start_date": "2025-11-29",
"end_date": "2025-12-13",
"status": "completed",
"planned_points": 21
},
{
"project_slug": "devops-automation",
"name": "Sprint 1: Pipeline Templates",
"number": 1,
"goal": "Create reusable CI/CD pipeline templates for common deployment patterns.",
"start_date": "2026-01-06",
"end_date": "2026-01-20",
"status": "active",
"planned_points": 24
}
],
"agent_instances": [
@@ -500,6 +589,40 @@
"name": "Atlas",
"status": "working",
"current_task": "Building employee dashboard API"
},
{
"project_slug": "api-gateway",
"agent_type_slug": "solutions-architect",
"name": "Orion",
"status": "working",
"current_task": "Designing caching strategy for GraphQL queries"
},
{
"project_slug": "api-gateway",
"agent_type_slug": "senior-engineer",
"name": "Cleo",
"status": "working",
"current_task": "Implementing Redis cache invalidation"
},
{
"project_slug": "devops-automation",
"agent_type_slug": "devops-engineer",
"name": "Volt",
"status": "working",
"current_task": "Creating Terraform modules for AWS ECS"
},
{
"project_slug": "devops-automation",
"agent_type_slug": "senior-engineer",
"name": "Sage",
"status": "idle"
},
{
"project_slug": "devops-automation",
"agent_type_slug": "qa-engineer",
"name": "Echo",
"status": "waiting",
"current_task": "Waiting for pipeline templates to test"
}
],
"issues": [
@@ -638,6 +761,119 @@
"priority": "medium",
"labels": ["backend", "infrastructure", "storage"],
"story_points": 5
},
{
"project_slug": "api-gateway",
"sprint_number": 2,
"type": "story",
"title": "Implement Redis caching layer",
"body": "As an API consumer, I want responses to be cached for improved performance.\n\n## Requirements\n- Cache GraphQL query results\n- Configurable TTL per query type\n- Cache invalidation on mutations\n- Cache hit/miss metrics",
"status": "in_progress",
"priority": "critical",
"labels": ["backend", "performance", "redis"],
"story_points": 8,
"assigned_agent_name": "Cleo"
},
{
"project_slug": "api-gateway",
"sprint_number": 2,
"type": "task",
"title": "Set up query batching and deduplication",
"body": "Implement DataLoader pattern for:\n- Batching multiple queries into single database calls\n- Deduplicating identical queries within request scope\n- N+1 query prevention",
"status": "open",
"priority": "high",
"labels": ["backend", "performance", "graphql"],
"story_points": 5
},
{
"project_slug": "api-gateway",
"sprint_number": 2,
"type": "task",
"title": "Implement rate limiting middleware",
"body": "Add rate limiting to prevent API abuse:\n- Per-user rate limits\n- Per-IP fallback for anonymous requests\n- Sliding window algorithm\n- Custom limits per operation type",
"status": "open",
"priority": "high",
"labels": ["backend", "security", "middleware"],
"story_points": 5,
"assigned_agent_name": "Orion"
},
{
"project_slug": "api-gateway",
"sprint_number": 2,
"type": "bug",
"title": "Fix N+1 query in user resolver",
"body": "The user resolver is making separate database calls for each user's organization.\n\n## Steps to Reproduce\n1. Query users with organization field\n2. Check database logs\n3. Observe N+1 queries",
"status": "open",
"priority": "high",
"labels": ["bug", "performance", "graphql"],
"story_points": 3
},
{
"project_slug": "analytics-dashboard",
"sprint_number": 2,
"type": "story",
"title": "Build cohort analysis charts",
"body": "As a product manager, I want to analyze user cohorts over time.\n\n## Features\n- Weekly/monthly cohort grouping\n- Retention curve visualization\n- Cohort comparison view",
"status": "closed",
"priority": "high",
"labels": ["frontend", "charts", "analytics"],
"story_points": 8
},
{
"project_slug": "analytics-dashboard",
"sprint_number": 2,
"type": "task",
"title": "Implement real-time event streaming",
"body": "Set up WebSocket connection for live event updates:\n- Event type filtering\n- Buffering for high-volume periods\n- Reconnection handling",
"status": "closed",
"priority": "high",
"labels": ["backend", "websocket", "realtime"],
"story_points": 5
},
{
"project_slug": "devops-automation",
"sprint_number": 1,
"type": "epic",
"title": "CI/CD Pipeline Templates",
"body": "Create reusable pipeline templates for common deployment patterns.\n\n## Templates Needed\n- Node.js applications\n- Python applications\n- Docker-based deployments\n- Kubernetes deployments",
"status": "in_progress",
"priority": "critical",
"labels": ["infrastructure", "cicd", "templates"],
"story_points": null
},
{
"project_slug": "devops-automation",
"sprint_number": 1,
"type": "story",
"title": "Create Terraform modules for AWS ECS",
"body": "As a DevOps engineer, I want Terraform modules for ECS deployments.\n\n## Modules\n- ECS cluster configuration\n- Service and task definitions\n- Load balancer integration\n- Auto-scaling policies",
"status": "in_progress",
"priority": "high",
"labels": ["terraform", "aws", "ecs"],
"story_points": 8,
"assigned_agent_name": "Volt"
},
{
"project_slug": "devops-automation",
"sprint_number": 1,
"type": "task",
"title": "Set up Gitea Actions runners",
"body": "Configure self-hosted Gitea Actions runners:\n- Docker-in-Docker support\n- Caching for npm/pip\n- Secrets management\n- Resource limits",
"status": "open",
"priority": "high",
"labels": ["infrastructure", "gitea", "cicd"],
"story_points": 5
},
{
"project_slug": "devops-automation",
"sprint_number": 1,
"type": "task",
"title": "Implement rollback detection system",
"body": "AI-assisted rollback detection:\n- Monitor deployment health metrics\n- Automatic rollback triggers\n- Notification system\n- Post-rollback analysis",
"status": "open",
"priority": "medium",
"labels": ["ai", "monitoring", "automation"],
"story_points": 8
}
]
}

View File

@@ -6,13 +6,15 @@
* - Recent projects
* - Pending approvals
*
* Uses mock data until backend endpoints are available.
* Fetches real data from the API.
*
* @see Issue #53
*/
import { useQuery } from '@tanstack/react-query';
import type { Project, ProjectStatus } from '@/components/projects/types';
import { listProjects as listProjectsApi } from '@/lib/api/generated';
import type { ProjectResponse } from '@/lib/api/generated';
import type { AutonomyLevel, Project, ProjectStatus } from '@/components/projects/types';
// ============================================================================
// Types
@@ -52,118 +54,70 @@ export interface DashboardData {
}
// ============================================================================
// Mock Data
// Helpers
// ============================================================================
const mockStats: DashboardStats = {
activeProjects: 3,
runningAgents: 8,
openIssues: 24,
pendingApprovals: 2,
};
/**
* Format a date string as relative time (e.g., "2 minutes ago")
*/
function formatRelativeTime(dateStr: string): string {
const date = new Date(dateStr);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffMins = Math.floor(diffMs / 60000);
const diffHours = Math.floor(diffMins / 60);
const diffDays = Math.floor(diffHours / 24);
const diffWeeks = Math.floor(diffDays / 7);
const diffMonths = Math.floor(diffDays / 30);
const mockProjects: DashboardProject[] = [
{
id: 'proj-001',
name: 'E-Commerce Platform Redesign',
description: 'Complete redesign of the e-commerce platform with modern UI/UX',
status: 'active' as ProjectStatus,
autonomy_level: 'milestone',
created_at: '2025-11-15T10:00:00Z',
updated_at: '2025-12-30T14:30:00Z',
owner_id: 'user-001',
progress: 67,
openIssues: 12,
activeAgents: 4,
currentSprint: 'Sprint 3',
lastActivity: '2 minutes ago',
},
{
id: 'proj-002',
name: 'Mobile Banking App',
description: 'Native mobile app for banking services with biometric authentication',
status: 'active' as ProjectStatus,
autonomy_level: 'autonomous',
created_at: '2025-11-20T09:00:00Z',
updated_at: '2025-12-30T12:00:00Z',
owner_id: 'user-001',
progress: 45,
openIssues: 8,
activeAgents: 5,
currentSprint: 'Sprint 2',
lastActivity: '15 minutes ago',
},
{
id: 'proj-003',
name: 'Internal HR Portal',
description: 'Employee self-service portal for HR operations',
status: 'paused' as ProjectStatus,
autonomy_level: 'full_control',
created_at: '2025-10-01T08:00:00Z',
updated_at: '2025-12-28T16:00:00Z',
owner_id: 'user-001',
progress: 23,
openIssues: 5,
activeAgents: 0,
currentSprint: 'Sprint 1',
lastActivity: '2 days ago',
},
{
id: 'proj-004',
name: 'API Gateway Modernization',
description: 'Migrate legacy API gateway to cloud-native architecture',
status: 'active' as ProjectStatus,
autonomy_level: 'milestone',
created_at: '2025-12-01T11:00:00Z',
updated_at: '2025-12-30T10:00:00Z',
owner_id: 'user-001',
progress: 82,
openIssues: 3,
activeAgents: 2,
currentSprint: 'Sprint 4',
lastActivity: '1 hour ago',
},
{
id: 'proj-005',
name: 'Customer Analytics Dashboard',
description: 'Real-time analytics dashboard for customer behavior insights',
status: 'completed' as ProjectStatus,
autonomy_level: 'autonomous',
created_at: '2025-09-01T10:00:00Z',
updated_at: '2025-12-15T17:00:00Z',
owner_id: 'user-001',
progress: 100,
openIssues: 0,
activeAgents: 0,
lastActivity: '2 weeks ago',
},
{
id: 'proj-006',
name: 'DevOps Pipeline Automation',
description: 'Automate CI/CD pipelines with AI-assisted deployments',
status: 'active' as ProjectStatus,
autonomy_level: 'milestone',
created_at: '2025-12-10T14:00:00Z',
updated_at: '2025-12-30T09:00:00Z',
owner_id: 'user-001',
progress: 35,
openIssues: 6,
activeAgents: 3,
currentSprint: 'Sprint 1',
lastActivity: '30 minutes ago',
},
];
if (diffMins < 1) return 'Just now';
if (diffMins < 60) return `${diffMins} minute${diffMins > 1 ? 's' : ''} ago`;
if (diffHours < 24) return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`;
if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`;
if (diffWeeks < 4) return `${diffWeeks} week${diffWeeks > 1 ? 's' : ''} ago`;
return `${diffMonths} month${diffMonths > 1 ? 's' : ''} ago`;
}
/**
* Maps API ProjectResponse to DashboardProject format
*/
function mapToDashboardProject(
project: ProjectResponse & Record<string, unknown>
): DashboardProject {
const updatedAt = project.updated_at || project.created_at || new Date().toISOString();
const createdAt = project.created_at || new Date().toISOString();
return {
id: project.id,
name: project.name,
description: project.description || undefined,
status: project.status as ProjectStatus,
autonomy_level: (project.autonomy_level || 'milestone') as AutonomyLevel,
created_at: createdAt,
updated_at: updatedAt,
owner_id: project.owner_id || 'unknown',
progress: (project.progress as number) || 0,
openIssues: (project.openIssues as number) || project.issue_count || 0,
activeAgents: (project.activeAgents as number) || project.agent_count || 0,
currentSprint: project.active_sprint_name || undefined,
lastActivity: formatRelativeTime(updatedAt),
};
}
// ============================================================================
// Mock Data (for pending approvals - no backend endpoint yet)
// ============================================================================
const mockApprovals: PendingApproval[] = [
{
id: 'approval-001',
type: 'sprint_boundary',
title: 'Sprint 3 Completion Review',
description: 'Review sprint deliverables and approve transition to Sprint 4',
title: 'Sprint 1 Completion Review',
description: 'Review sprint deliverables and approve transition to Sprint 2',
projectId: 'proj-001',
projectName: 'E-Commerce Platform Redesign',
requestedBy: 'Product Owner Agent',
requestedAt: '2025-12-30T14:00:00Z',
requestedAt: new Date().toISOString(),
priority: 'high',
},
{
@@ -171,10 +125,10 @@ const mockApprovals: PendingApproval[] = [
type: 'architecture_decision',
title: 'Database Migration Strategy',
description: 'Approve PostgreSQL to CockroachDB migration plan',
projectId: 'proj-004',
projectName: 'API Gateway Modernization',
projectId: 'proj-002',
projectName: 'Mobile Banking App',
requestedBy: 'Architect Agent',
requestedAt: '2025-12-30T10:30:00Z',
requestedAt: new Date(Date.now() - 3600000).toISOString(),
priority: 'medium',
},
];
@@ -192,17 +146,41 @@ export function useDashboard() {
return useQuery<DashboardData>({
queryKey: ['dashboard'],
queryFn: async () => {
// Simulate network delay
await new Promise((resolve) => setTimeout(resolve, 500));
// Fetch real projects from API
const response = await listProjectsApi({
query: {
limit: 6,
},
});
// Return mock data
// TODO: Replace with actual API call when backend is ready
// const response = await apiClient.get('/api/v1/dashboard');
// return response.data;
if (response.error) {
throw new Error('Failed to fetch dashboard data');
}
const projects = response.data.data.map((p) =>
mapToDashboardProject(p as ProjectResponse & Record<string, unknown>)
);
// Sort by updated_at (most recent first)
projects.sort(
(a, b) =>
new Date(b.updated_at || b.created_at).getTime() -
new Date(a.updated_at || a.created_at).getTime()
);
// Calculate stats from real data
const activeProjects = projects.filter((p) => p.status === 'active').length;
const runningAgents = projects.reduce((sum, p) => sum + p.activeAgents, 0);
const openIssues = projects.reduce((sum, p) => sum + p.openIssues, 0);
return {
stats: mockStats,
recentProjects: mockProjects,
stats: {
activeProjects,
runningAgents,
openIssues,
pendingApprovals: mockApprovals.length,
},
recentProjects: projects,
pendingApprovals: mockApprovals,
};
},
@@ -218,8 +196,24 @@ export function useDashboardStats() {
return useQuery<DashboardStats>({
queryKey: ['dashboard', 'stats'],
queryFn: async () => {
await new Promise((resolve) => setTimeout(resolve, 300));
return mockStats;
const response = await listProjectsApi({
query: { limit: 100 },
});
if (response.error) {
throw new Error('Failed to fetch stats');
}
const projects = response.data.data.map((p) =>
mapToDashboardProject(p as ProjectResponse & Record<string, unknown>)
);
return {
activeProjects: projects.filter((p) => p.status === 'active').length,
runningAgents: projects.reduce((sum, p) => sum + p.activeAgents, 0),
openIssues: projects.reduce((sum, p) => sum + p.openIssues, 0),
pendingApprovals: mockApprovals.length,
};
},
staleTime: 30000,
refetchInterval: 60000,
@@ -235,8 +229,26 @@ export function useRecentProjects(limit: number = 6) {
return useQuery<DashboardProject[]>({
queryKey: ['dashboard', 'recentProjects', limit],
queryFn: async () => {
await new Promise((resolve) => setTimeout(resolve, 400));
return mockProjects.slice(0, limit);
const response = await listProjectsApi({
query: { limit },
});
if (response.error) {
throw new Error('Failed to fetch recent projects');
}
const projects = response.data.data.map((p) =>
mapToDashboardProject(p as ProjectResponse & Record<string, unknown>)
);
// Sort by updated_at (most recent first)
projects.sort(
(a, b) =>
new Date(b.updated_at || b.created_at).getTime() -
new Date(a.updated_at || a.created_at).getTime()
);
return projects;
},
staleTime: 30000,
});
@@ -249,7 +261,7 @@ export function usePendingApprovals() {
return useQuery<PendingApproval[]>({
queryKey: ['dashboard', 'pendingApprovals'],
queryFn: async () => {
await new Promise((resolve) => setTimeout(resolve, 300));
// TODO: Fetch from real API when endpoint exists
return mockApprovals;
},
staleTime: 30000,