Skip to content

Latest commit

 

History

History
216 lines (172 loc) · 5.03 KB

File metadata and controls

216 lines (172 loc) · 5.03 KB

API Documentation

Endpoints

POST /api/speeches/submit

Submit a new speech with a YouTube URL or audio file upload.

Authentication: Required (Bearer token via Supabase Auth)

Option 1: Submit YouTube URL

Content-Type: application/json

Request Body:

{
  "speech_url": "https://youtube.com/watch?v=..."
}

Success Response (201):

{
  "success": true,
  "data": {
    "id": "uuid",
    "user_id": "uuid",
    "speech_url": "https://youtube.com/watch?v=...",
    "submitted_at": "2025-10-30T12:00:00Z",
    "week_start_date": "2025-10-27"
  }
}

Validation Rules:

  • URL must be a valid YouTube URL (youtube.com/watch?v= or youtu.be/)
  • URL must not have been previously submitted by the same user
  • User must be authenticated

Option 2: Upload Audio File

Content-Type: multipart/form-data

Request Body:

  • audio_file: Audio file (File object)

Success Response (201):

{
  "success": true,
  "data": {
    "id": "uuid",
    "user_id": "uuid",
    "speech_url": "https://[project-id].supabase.co/storage/v1/object/public/speech-audio/...",
    "submitted_at": "2025-10-30T12:00:00Z",
    "week_start_date": "2025-10-27"
  }
}

Validation Rules:

  • File must be an audio file (audio/*)
  • File size must be less than 50 MB
  • File is uploaded to Supabase Storage bucket speech-audio
  • User must be authenticated

Error Responses

  • 401 Unauthorized: User not logged in
{
  "error": "Unauthorized"
}
  • 400 Bad Request: Invalid YouTube URL or audio file
{
  "error": "Invalid YouTube URL format. Please provide a valid YouTube link."
}
{
  "error": "Audio file must be less than 50 MB"
}
{
  "error": "Invalid file type. Please upload an audio file."
}
  • 409 Conflict: Duplicate recording
{
  "error": "You have already submitted this recording"
}
  • 500 Internal Server Error: Failed to upload
{
  "error": "Failed to upload audio file"
}

GET /api/leaderboard

Fetch the current leaderboard with weekly and all-time statistics.

Authentication: Not required (public endpoint)

Success Response (200):

{
  "data": [
    {
      "name": "John Doe",
      "place": 1,
      "all_time_speeches": 15,
      "weekly_speeches": 3,
      "avatar_url": "https://..."
    },
    {
      "name": "Jane Smith",
      "place": 2,
      "all_time_speeches": 12,
      "weekly_speeches": 2,
      "avatar_url": "https://..."
    }
  ]
}

Response Fields:

  • name: User's display name
  • place: Current ranking (based on all_time_speeches)
  • all_time_speeches: Total number of speeches ever submitted
  • weekly_speeches: Number of speeches submitted this week (Monday-Sunday)
  • avatar_url: User's profile picture from Google OAuth (optional)
  • speech_urls: Array of URLs to speech recordings (YouTube or Supabase Storage)

Notes:

  • Results are sorted by all_time_speeches in descending order
  • Weekly count is based on the current week (starts Monday at 00:00:00)
  • Users with no speeches are included with counts of 0

Real-time Updates

The leaderboard supports real-time updates using Supabase Realtime:

const supabase = createClient();

const channel = supabase
  .channel('speeches-changes')
  .on('postgres_changes', 
    { event: '*', schema: 'public', table: 'speeches' }, 
    () => {
      // Refetch leaderboard data
    }
  )
  .subscribe();

Events triggered on:

  • New speech submission (INSERT)
  • Speech update (UPDATE)
  • Speech deletion (DELETE)

Authentication

Login Flow

  1. User clicks "Log In" button
  2. Redirected to Google OAuth consent screen
  3. After approval, redirected to /auth/callback
  4. Callback handler:
    • Exchanges code for session
    • Creates/updates user profile in users table
    • Redirects to home page
  5. Session persisted via HTTP-only cookies

Session Management

  • Sessions automatically refreshed by middleware
  • Session duration: as configured in Supabase (default 1 hour with 24h refresh)
  • Logout clears session cookies

Error Handling

All endpoints follow consistent error response format:

{
  "error": "Error message description"
}

Common HTTP status codes:

  • 200: Success (GET)
  • 201: Created (POST)
  • 400: Bad Request (validation error)
  • 401: Unauthorized (authentication required)
  • 409: Conflict (duplicate resource)
  • 500: Internal Server Error (server-side issue)