Skip to content

feat: TournamentSummary schema #39

Description

@ethnjs

Tournament List — Add TournamentSummary Schema

Overview

The dashboard's tournament list endpoints (GET /tournaments/ and GET /tournaments/me/) currently return the full TournamentRead schema, which includes volunteer_schema, time_blocks, and categories — none of which are needed to render a tournament card. This issue introduces a lightweight TournamentSummary schema for use on list endpoints, replacing the heavy full schema with only the fields the card view actually consumes.


Motivation

TournamentRead includes VolunteerSchema (containing custom_fields and positions), time_blocks, and categories. For a dashboard card that shows only name, dates, location, event count, and volunteer count, this is significant unnecessary payload. As tournament data grows, this overhead will compound across every dashboard load. A dedicated summary schema keeps list responses fast and the API contract explicit about what each endpoint is meant to support.


Backend Changes

1. Add TournamentSummary schema

File: backend/app/schemas/tournament.py

class TournamentSummary(BaseModel):
    id: int
    name: str
    start_date: datetime | None
    end_date: datetime | None
    location: str | None
    event_count: int
    volunteer_count: int
    created_at: datetime
    updated_at: datetime
 
    model_config = {"from_attributes": True}

2. Compute counts in the list routes

event_count and volunteer_count are not columns — they must be derived from relationships. Use the existing .events and .memberships relationships already loaded on the Tournament model:

TournamentSummary(
    **tournament.__dict__,
    event_count=len(tournament.events),
    volunteer_count=len(tournament.memberships),
)

If relationship loading becomes a performance concern at scale, this can be revisited with SQL subqueries — but the relationship approach is the correct starting point given the current data volumes.

3. Update list routes

File: backend/app/api/routes/tournaments.py

  • GET /tournaments/response_model=list[TournamentSummary]
  • GET /tournaments/me/response_model=list[TournamentSummary]
    The detail route GET /tournaments/{tournament_id}/ continues to return the full TournamentRead — the tournament settings and events pages need everything.

Frontend Changes

Wherever the tournament list response is consumed (dashboard page, tournament card component), update the TypeScript type to match the new summary shape:

  • Remove: volunteer_schema, time_blocks, categories
  • Add: event_count: number, volunteer_count: number
    The dashboard card should surface event_count and volunteer_count as secondary metadata (e.g. "12 events · 47 volunteers").

Tests

File: backend/tests/api/test_tournaments.py

Update list endpoint tests to assert against the TournamentSummary shape:

  • volunteer_schema, time_blocks, and categories should not be present in list responses
  • event_count and volunteer_count should be present and correct
  • The detail endpoint (GET /tournaments/{id}/) should still return the full schema

Relevant Files

File Change
backend/app/schemas/tournament.py Add TournamentSummary
backend/app/api/routes/tournaments.py Update response_model on list routes
backend/app/models/models.py Reference only — .events and .memberships relationships used for counts
backend/tests/api/test_tournaments.py Update list response assertions
frontend/ (dashboard page + tournament card component) Update TypeScript type for list responses

Out of Scope

  • Pagination on list endpoints — a separate concern; this issue only changes the response shape
  • SQL subquery optimization for count fields — can be done later if relationship loading proves slow
  • Detail routeGET /tournaments/{id}/ continues to return TournamentRead unchanged

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions