veza/veza-backend-api/docs/DASHBOARD_ENDPOINT_CONTRACT.md
senke 34256056a3 data-flow: design dashboard aggregation endpoint contract
- Completed Action 2.1.1.1: Designed dashboard endpoint contract
- Created DASHBOARD_ENDPOINT_CONTRACT.md with complete specification
- Defined GET /api/v1/dashboard endpoint consolidating 4+ API calls
- Response structure: stats, recent_activity, library_preview
- Query parameters: activity_limit, library_limit, stats_period
- Documented data sources, error handling, performance considerations
- Migration strategy outlined for phased rollout
- Ready for backend implementation (Action 2.1.1.2)
2026-01-11 16:43:14 +01:00

6.3 KiB

Dashboard Aggregation Endpoint Contract

Date: 2025-01-27
Action: 2.1.1.1 - Design dashboard endpoint contract
Status: Complete

Overview

This document defines the contract for a new aggregated dashboard endpoint that consolidates multiple API calls into a single request, reducing over-fetching and improving performance.

Current Implementation

The dashboard currently makes 4+ separate API calls:

  1. GET /audit/stats - Dashboard statistics
  2. GET /audit/activity - Recent activity logs
  3. Social feed API - Recent posts/feed items
  4. GET /tracks (with limit: 5) - Library preview

Problems:

  • Multiple round trips increase latency
  • Over-fetching of data
  • Race conditions possible
  • No atomic data consistency

Proposed Endpoint

Endpoint Specification

Method: GET
Path: /api/v1/dashboard
Authentication: Required (Bearer token)
Response Format: Wrapped format { success: true, data: DashboardResponse }

Request Parameters

Query Parameters (all optional):

  • activity_limit (integer, default: 10) - Number of recent activity items to return
  • library_limit (integer, default: 5) - Number of library items to return in preview
  • stats_period (string, default: "30d") - Time period for statistics ("7d", "30d", "90d", "all")

Response Structure

interface DashboardResponse {
  stats: DashboardStats;
  recent_activity: RecentActivity[];
  library_preview: LibraryPreview;
}

interface DashboardStats {
  tracks_played: number;
  messages_sent: number;
  favorites: number;
  active_friends: number;
  tracks_played_change?: string;      // Percentage change (e.g., "+12%", "-5%")
  messages_sent_change?: string;
  favorites_change?: string;
  active_friends_change?: string;
  period: string;                      // "7d", "30d", "90d", "all"
}

interface RecentActivity {
  id: string;                         // UUID
  type: 'track_upload' | 'message_received' | 'favorite_added' | 
        'playlist_created' | 'comment_added' | 'post';
  title: string;                      // Human-readable title
  description?: string;                // Optional description/details
  timestamp: string;                  // ISO8601 timestamp
  icon?: string;                      // Optional icon URL or identifier
  metadata?: Record<string, any>;      // Additional context (track_id, user_id, etc.)
}

interface LibraryPreview {
  items: TrackPreview[];
  total_count: number;                // Total tracks in user's library
  has_more: boolean;                  // Whether there are more items beyond limit
}

interface TrackPreview {
  id: string;                         // UUID
  title: string;
  artist: string;
  duration: number;                   // Seconds
  cover_art_path?: string;
  play_count: number;
  like_count: number;
  created_at: string;                 // ISO8601 timestamp
}

Response Example

{
  "success": true,
  "data": {
    "stats": {
      "tracks_played": 1234,
      "messages_sent": 567,
      "favorites": 89,
      "active_friends": 45,
      "tracks_played_change": "+12%",
      "messages_sent_change": "+8%",
      "favorites_change": "+23%",
      "active_friends_change": "+5%",
      "period": "30d"
    },
    "recent_activity": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "type": "track_upload",
        "title": "Nouvelle piste ajoutée",
        "description": "My New Track.mp3",
        "timestamp": "2025-01-27T10:30:00Z",
        "metadata": {
          "track_id": "660e8400-e29b-41d4-a716-446655440001",
          "file_name": "My New Track.mp3"
        }
      },
      {
        "id": "550e8400-e29b-41d4-a716-446655440002",
        "type": "message_received",
        "title": "Message reçu de @username",
        "timestamp": "2025-01-27T09:15:00Z",
        "metadata": {
          "conversation_id": "770e8400-e29b-41d4-a716-446655440003",
          "from_user_id": "880e8400-e29b-41d4-a716-446655440004"
        }
      }
    ],
    "library_preview": {
      "items": [
        {
          "id": "990e8400-e29b-41d4-a716-446655440005",
          "title": "My Favorite Track",
          "artist": "Artist Name",
          "duration": 240,
          "cover_art_path": "/covers/track-123.jpg",
          "play_count": 42,
          "like_count": 7,
          "created_at": "2025-01-20T14:30:00Z"
        }
      ],
      "total_count": 156,
      "has_more": true
    }
  }
}

Data Sources

Stats Calculation

tracks_played: Sum of play actions from audit logs + track play counts
messages_sent: Count of message actions from audit logs
favorites: Count of favorite/like actions from audit logs
active_friends: Count of unique users interacted with in period

Change percentages: Compare current period to previous period (e.g., last 30d vs previous 30d)

Recent Activity

Combines:

  1. Audit logs (/audit/activity) - User actions (uploads, plays, favorites, etc.)
  2. Social feed - Recent posts from followed users
  3. Chat messages - Recent messages received
  4. Comments - Comments on user's tracks/playlists

Sorted by timestamp descending, limited by activity_limit.

Library Preview

Returns user's most recently added or most played tracks, limited by library_limit.

Error Handling

401 Unauthorized: User not authenticated
500 Internal Server Error: Backend error during aggregation

Error responses follow standard format:

{
  "success": false,
  "error": {
    "code": 500,
    "message": "Failed to fetch dashboard data",
    "timestamp": "2025-01-27T10:30:00Z"
  }
}

Performance Considerations

  • Caching: Response can be cached for 30-60 seconds (user-specific)
  • Database queries: Use efficient joins and indexes
  • Parallel fetching: Fetch stats, activity, and library in parallel
  • Timeouts: Aggregate endpoint should complete within 2 seconds

Migration Strategy

  1. Phase 1: Implement backend endpoint (Action 2.1.1.2)
  2. Phase 2: Update frontend to use new endpoint (Action 2.1.1.3)
  3. Phase 3: Remove old API calls (Actions 2.1.1.4-2.1.1.6)
  4. Phase 4: Add caching (Action 2.1.1.7)

Validation

Contract documented
Response structure defined
Data sources identified
Error handling specified
Performance considerations noted
⏭️ Next: Action 2.1.1.2 - Implement backend dashboard handler