Update registration metrics

Note

Canonical source: guides/UPDATE_REGISTRATION_METRICS.md. Transcluded here for the docs site. Edit the source file if anything is wrong.

with a New Convention Year

Run this at the end of each convention year (after the event is over and registration is final) so the year-over-year comparison charts in register-metrics2 include the just-finished event as a historical line.

The metrics dashboard compares the current (live) year against previous years of static reference data. Adding a finished year is a two-part change: (1) generate the reference JSON, and (2) tell the frontend to render it.

Prerequisites

  • A shell on a machine that can reach the database for the event you’re exporting (typically the server, or a local dev checkout pointed at the right DB).

  • The Python virtualenv active: commands below use ./.venv/bin/python.

1. Identify the event slug

The export is keyed by the Event.slug (its primary key).

./.venv/bin/python manage.py shell -c "from event.models import Event; print([e.slug for e in Event.objects.all()])"

Pick the slug of the event that just finished.

2. Export the year’s timeline

This regenerates the reference data in the exact format the charts consume:

  • {year}.json -> [[dayIndexSinceOpened, perDayCount, cumulativeCount], ...]

  • {year}-d.json -> [["MM-DD", perDayCount, cumulativeCount], ...]

./.venv/bin/python manage.py register__export_reg_timeline \
  --event <slug> \
  --year <YYYY> \
  --output-dir .examples/previous-years-reg-data \
  --rebuild-combined
  • --year defaults to the year of the first registration; set it explicitly to label by the convention year (e.g. --year 2025).

  • --rebuild-combined regenerates allPreviousYears.json and allPreviousYears-date.json (the files the app actually reads), ordered by year.

  • Defaults to all registrations (matches the live unfiltered chart). Add --paid-only if you only want paid registrations.

3. Put the files where the app reads them

The combined files must live on disk at ui/public/data/previous-years/. The app serves that folder at the URL /static/ui/data/previous-years/ (that’s the path the frontend requests), so don’t change where the files are placed.

Either copy them over from the template dir:

cp .examples/previous-years-reg-data/allPreviousYears.json      ui/public/data/previous-years/
cp .examples/previous-years-reg-data/allPreviousYears-date.json ui/public/data/previous-years/

…or skip step 2’s copy entirely by exporting straight into the app assets:

./.venv/bin/python manage.py register__export_reg_timeline \
  --event <slug> --year <YYYY> \
  --output-dir ui/public/data/previous-years --rebuild-combined

4. Register the new year in the component

Open ui/src/app/apps/register/register-metrics2/register-metrics2.component.ts and append the new year to the previousYears array, keeping it ascending:

private readonly previousYears: number[] = [2021, 2022, 2023, 2024, 2025];

This array’s order must match the combined file’s year order. Since --rebuild-combined writes years sorted ascending, just keep the array ascending too.

5. Rebuild the frontend

The JSON lives under ui/public/, so it’s only picked up after a frontend build.

# Dev
export MIDSUMMER_PROD=false && ./render-ui-elements.sh && ./render-tenant-ui-elements.sh && ./entrypoint.sh

# Production
export MIDSUMMER_PROD=true && ./render-ui-elements.sh && ./render-tenant-ui-elements.sh && ./entrypoint.sh

6. Verify

Open Register → System → Metrics2 (route /app/register/system/metrics). The newly added year should appear as a line on both:

  • Year-over-Year: Cumulative by Days Since Registration Opened

  • Year-over-Year: Cumulative by Calendar Date

The current (in-progress) year is always pulled live from the backend and rendered in blue.

Gotchas

  • Array order matters. The combined file’s outer array is ordered by year (index 0 = the earliest year). The component maps index -> previousYears[index]. If the two fall out of sync, years will be mislabeled. Keep both ascending.

  • The current year is never in these files. Only completed years belong in the reference data. The current cycle is read live; once it’s done, export it and it becomes a historical line for next year.

  • Timezone. The export groups days using Django’s default timezone, the same way the live metrics view does, so current-year and previous-year lines stay aligned. Don’t “fix” this by switching the export to the event timezone — it would desynchronize the two.

  • Rebuild is required. Updating the JSON without rebuilding the frontend will not show the new year.

  • No database changes. The command is read-only against registrations and only writes JSON files — safe to re-run any time.