No description
  • Rust 92.7%
  • Nix 5.4%
  • Shell 1.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Claude 086ad73ebe sync: import all visible activities in parallel
The bulk import loop awaited importActivity() one row at a time, so
with N visible activities the browser paid N sequential round trips
(plus each activity's own processing time) back to back. Requests
now fire concurrently via Promise.allSettled, with the button label
updating live as each one finishes. The backend already handles
concurrent activity imports fine -- each goes through its own DB
transaction and its own geo::crossings_for_track query -- so this is
purely a client-side change.
2026-08-13 11:47:23 +02:00
migrations add map and clicks 2026-08-12 17:57:25 +02:00
scripts state 2026-08-12 17:49:27 +02:00
src sync: import all visible activities in parallel 2026-08-13 11:47:23 +02:00
.env.example chatgpt 2026-08-12 13:24:01 +02:00
.gitignore extend .gitignore 2026-08-13 05:15:43 +02:00
Cargo.toml web: use Form and Query from axum_extra 2026-08-13 05:07:38 +02:00
flake.lock fixup! fix nix develop psql setup 2026-08-12 13:37:37 +02:00
flake.nix dev api key 2026-08-12 14:02:12 +02:00
README.md add map and clicks 2026-08-12 17:57:25 +02:00
rust-toolchain.toml chatgpt 2026-08-12 13:24:01 +02:00

County Sprints frontend/leaderboard update

Replace these files in the project:

  • src/main.rs
  • src/model.rs
  • src/db.rs
  • src/leaderboard.rs
  • src/web.rs
  • migrations/0001_initial.sql

No change is required to the working src/intervals.rs.

The existing src/webhook.rs can keep calling:

crate::process_activity(state_clone, athlete_id, activity_id.clone()).await

process_activity() now loads the athlete's OAuth access token itself. The development sync uses the explicit API-key client, so the personal development key is not written to the database.

Database

The migration is intentionally a complete replacement because the database can be reset during development.

The new schema adds:

  • leaderboard_groups
  • leaderboard_group_members
  • indexes for activity/crossing queries

Leaderboard location matching

Leaderboard rows are grouped by:

  • 10-minute time bucket
  • source county
  • destination county
  • spatial cluster with a 10 metre DBSCAN radius

The crossing geometry is transformed to EPSG:3857 before the 10 metre clustering calculation so the distance is measured in metres rather than degrees.

Frontend

The frontend now provides:

  • Leaflet map for each leaderboard group
  • small map for every individual crossing
  • activity detail page at /activity/{activity_id}
  • activity map containing all crossings
  • browser-local timestamp formatting using Intl.DateTimeFormat
  • leaderboard group management at /groups
  • group selection on the main leaderboard

The map uses Leaflet and OpenStreetMap tiles. Leaflet's current stable 1.x documentation describes the same map/tile-layer APIs used here. citeturn0search2turn0search9