Part of the Multi-Year Conferences refactor. See docs/architecture/multi-year-conferences.md for full context.
Scope
Make all stats year-aware. Add a year-switcher dropdown to existing stats pages.
Includes
- Refactor every aggregation function in
portal/common.py to accept a conference parameter (about 20 functions)
- Namespace stats cache keys by year (e.g.
volunteer_signups_count_2025)
- Update
portal/views.py::stats and stats_json to read ?year= query param; default to Conference.get_active()
- Add year-switcher dropdown to:
templates/portal/stats.html
templates/volunteer/volunteer_stats.html
templates/sponsorship/sponsorship_stats.html
templates/attendee/attendee_stats.html
- When the selected year predates the portal (no live data exists), render
historical_snapshot values with a banner: "Limited data — this conference predates the portal."
Out of scope
- The year-over-year comparison page (Issue #N — extracted to its own page)
- Removing the existing hardcoded
HISTORICAL_STATS/PROPOSALS_2025_COUNT constants (deferred to Issue #N when comparison page is extracted)
Related PRs that may conflict
Dependencies
Acceptance criteria
Part of the Multi-Year Conferences refactor. See
docs/architecture/multi-year-conferences.mdfor full context.Scope
Make all stats year-aware. Add a year-switcher dropdown to existing stats pages.
Includes
portal/common.pyto accept aconferenceparameter (about 20 functions)volunteer_signups_count_2025)portal/views.py::statsandstats_jsonto read?year=query param; default toConference.get_active()templates/portal/stats.htmltemplates/volunteer/volunteer_stats.htmltemplates/sponsorship/sponsorship_stats.htmltemplates/attendee/attendee_stats.htmlhistorical_snapshotvalues with a banner: "Limited data — this conference predates the portal."Out of scope
HISTORICAL_STATS/PROPOSALS_2025_COUNTconstants (deferred to Issue #N when comparison page is extracted)Related PRs that may conflict
portal/common.py; rebase plan: addconferenceparameter to the new functionDependencies
Acceptance criteria
conference?year=2025shows live 2025 data;?year=2023shows snapshot with bannerstats.json?year=YYYYreturns year-scoped data