DEV Community

Cover image for Bringing Local Slalom Races Online with Canoe Slalom Live
Karlis
Karlis

Posted on Edited on

Bringing Local Slalom Races Online with Canoe Slalom Live

DEV Weekend Challenge: Community

This is a submission for the DEV Weekend Challenge: Community.
​

The Community

Canoe and kayak slalom has a strong grassroots scene: small clubs, volunteer judges, parents on the riverbank, and athletes who travel long distances for a single race run. Yet many local events still run on paper start lists, handwritten penalties, and spreadsheets that never leave the timing laptop.
​

I built Canoe Slalom Live for that community: local organizers who want something lightweight they can run on a single laptop at the course, judges who need a simple way to record runs, commentators who want quick access to athlete stories, and spectators who just want to understand what is happening on the water in real time.
​

What I Built

Canoe Slalom Live is a tiny live-timing and results web app for canoe/water slalom competitions. It runs as a Go web server with an embedded SQLite database and server-rendered HTML, so an organizer can start it on a laptop at the riverside and let everyone else follow the event from their phones.
​

The app provides a public event page with a start list grouped by category, a live leaderboard with penalties, a photo gallery, dedicated commentator and athlete profile views, plus a mobile-friendly judge panel for entering runs and penalties. It focuses on making results understandable for spectators while giving judges and commentators tools that fit how small events actually work.
​
It’s a single Go + SQLite binary that can run on a small VPS or services like Google Cloud Run.

Demo

GitHub repository (code + README + screenshots):

GitHub logo AcaciaMan / canoe-slalom-live

Weekend-built sports app for canoe/water slalom meets. Supports creating events, managing start lists and athlete bios, recording runs and penalties, and showing a live leaderboard for the whole community.

🛶 Canoe Slalom Live

Live timing and results for canoe/water slalom competitions. Built for grassroots events — run it on a laptop at the riverside, let spectators follow on their phones.

Short introduction video https://github.com/user-attachments/assets/90fe481d-032e-493f-acd4-5c0e1be7cca1

Quick Start

# Prerequisites: Go 1.22+, GCC (for SQLite CGo driver)
go mod tidy
go run main.go -seed

# Opens at http://localhost:8080
# Judge panel at http://localhost:8080/judge/events/demo-slalom-2026
Enter fullscreen mode Exit fullscreen mode

To enable authentication for judge routes:

# Windows
set ADMIN_TOKEN=secret123
go run main.go -seed

# Linux/macOS
ADMIN_TOKEN=secret123 go run main.go -seed

# Judge panel: http://localhost:8080/judge/events/demo-slalom-2026?token=secret123
Enter fullscreen mode Exit fullscreen mode

Stack

  • Go — net/http with Go 1.22+ pattern routing, html/template for server-rendered HTML
  • SQLite — embedded via github.com/mattn/go-sqlite3 (CGo), WAL mode, single data.db file
  • Vanilla HTML/CSS/JS — no build step, no framework, no bundler

It’s a single Go + SQLite binary that can run on a small VPS or services like Google Cloud Run.

Pages

Route Page Description
/events/{slug} Event Start list grouped
…

Short intro video (live walk-through of the seeded demo event):
https://github.com/user-attachments/assets/90fe481d-032e-493f-acd4-5c0e1be7cca1
​

To try it locally:

bash
go mod tidy
go run main.go -seed
# Opens at http://localhost:8080
# Judge panel at http://localhost:8080/judge/events/demo-slalom-2026
Enter fullscreen mode Exit fullscreen mode

Code

The full source code is available here:

GitHub logo AcaciaMan / canoe-slalom-live

Weekend-built sports app for canoe/water slalom meets. Supports creating events, managing start lists and athlete bios, recording runs and penalties, and showing a live leaderboard for the whole community.

🛶 Canoe Slalom Live

Live timing and results for canoe/water slalom competitions. Built for grassroots events — run it on a laptop at the riverside, let spectators follow on their phones.

Short introduction video https://github.com/user-attachments/assets/90fe481d-032e-493f-acd4-5c0e1be7cca1

Quick Start

# Prerequisites: Go 1.22+, GCC (for SQLite CGo driver)
go mod tidy
go run main.go -seed

# Opens at http://localhost:8080
# Judge panel at http://localhost:8080/judge/events/demo-slalom-2026
Enter fullscreen mode Exit fullscreen mode

To enable authentication for judge routes:

# Windows
set ADMIN_TOKEN=secret123
go run main.go -seed

# Linux/macOS
ADMIN_TOKEN=secret123 go run main.go -seed

# Judge panel: http://localhost:8080/judge/events/demo-slalom-2026?token=secret123
Enter fullscreen mode Exit fullscreen mode

Stack

  • Go — net/http with Go 1.22+ pattern routing, html/template for server-rendered HTML
  • SQLite — embedded via github.com/mattn/go-sqlite3 (CGo), WAL mode, single data.db file
  • Vanilla HTML/CSS/JS — no build step, no framework, no bundler

It’s a single Go + SQLite binary that can run on a small VPS or services like Google Cloud Run.

Pages
















Route Page Description
/events/{slug} Event Start list grouped
…






​

Key routes:

  • /events/{slug} – event overview with start list and athlete bios
  • /events/{slug}/leaderboard – live leaderboard with auto-refresh and penalty sparklines
  • /events/{slug}/photos – photo gallery with photographer credits
  • /events/{slug}/commentator – big-screen commentator view
  • /events/{slug}/athletes/{id} – athlete profile with run history and linked photos
  • /judge/events/{slug} – judge panel for recording runs (auth-protected via admin token) ​

How I Built It

Stack and architecture
I used Go 1.22 with net/http pattern routing and html/template for fully server-rendered pages, backed by a single SQLite database file accessed through github.com/mattn/go-sqlite3. There is no build pipeline or frontend framework: just vanilla HTML, CSS, and a tiny bit of JavaScript for auto-refresh.
​

The project is split into small packages: domain for core types (events, athletes, runs, sponsors, photos), store for SQLite queries, and handler for public and judge HTTP handlers plus authentication and logging middleware. Templates live in templates/ and are composed around a shared layout with a simple nav bar linking Event, Leaderboard, Photos, and Judge.
​

Data model and scoring

The SQLite schema has seven tables: events, categories, athletes, entries, runs, sponsors, and photos. Entries link athletes to an event and category with a bib number; runs store raw time, touches, missed gates, and computed total time, and a UNIQUE(entry_id, run_number) constraint prevents duplicate runs. Scoring follows standard ICF rules: +2 seconds per gate touch, +50 seconds per missed gate, ranking athletes by their best single-run total time.
​

UX for each role

For spectators, the leaderboard auto-refreshes every 10 seconds and highlights medals, “NEW” runs, time-behind-leader, and tiny CSS sparklines that compare raw time vs penalties. Commentators get a dedicated view that shows the latest result in huge type with bio and penalties plus current top three for each category, optimized for projection. Judges use a mobile-friendly panel with large tap targets, penalty steppers, confirmation before saving, recent runs, and run-status indicators so they can work quickly in a noisy outdoor environment.
​

Safety and polish

To keep things safe without overbuilding auth, judge routes are protected with an ADMIN_TOKEN environment variable and a simple session cookie once the token is used. There is server-side validation for time ranges and maximum penalties, basic security headers, and structured request logging with method, path, status, and duration. I also seeded a complete demo event (Demo Slalom 2026) so anyone cloning the repo can see realistic data, categories, and sponsors immediately

Top comments (0)