Off the clock, still in production

A race club, run like a platform.

Polder Goats is a loose crew of friends who run, ride and swim below sea level and travel for the hills. I built the club its home: a shared race calendar, a leaderboard rebuilt every day from our training history, and a badge system worth arguing about. Then I kept running it the way I'd run a client's platform.

The Polder Goats Races view on a desktop: sport, distance and intensity filters, race cards with photos, dates, distances and who is in by initials, and side panels for the next race, races on the calendar and races done.
The same Races view on a phone: a top bar with the next race, the next race as a full card, the others as compact rows, and a tab bar along the bottom.
16
races on the shared calendar
273
record boards, rebuilt every day
80
badges, from Kid to The GOAT
9
seasons of history, back to 2018
12K+
activities behind the boards
~€0
a month to host — free tier, own hardware

Counted from the live feed and the repo, not estimated. Names stay on the club's own site — this page is about how it's built.

How it's built

Small site, production habits.

Everything I'd insist on for a client — as code, gated on the way in, cheap to run — applied to a hobby that has nine very opinionated users.

A static front with nothing to steal

One hand-written page: no framework, no accounts, no cookies, no analytics. Course maps run on a vendored MapLibre and plain GPX tracks, fonts are self-hosted, and a strict Content Security Policy pins the one inline script by hash — the build fails if the two ever drift. Hosted on Azure Static Web Apps' free tier, custom domains and all in Terraform.

A daily pipeline on my own hardware

A collector on my on-prem fleet reads each goat's training history once a day, keeps the raw data locally so nothing is fetched twice, builds every board and publishes one compressed JSON feed to blob storage. It ships through Ansible and a Semaphore deploy pipeline, runs in a locked-down systemd sandbox, and an off-host check raises the alarm when the feed goes stale.

Records you can trust — or a grade that says why not

Watches lie. Every record is graded for GPS reliability, and the worst never make the board. Broken tracks get their climbing re-measured against the Copernicus elevation model; official IRONMAN results replace a watch's estimate; descents, mislabelled rides and pool-length glitches don't get to set records.

Private by design

Everyone on the site said yes first. The public feed carries first names and numbers only — no activity links, no routes, no GPS. The site is unlisted and asks search engines to stay away, and any goat can keep their races off the feed. Detailed data stays on my own hardware.

The fun part

What the herd actually opens.

  • Races — the calendar we sign up from: dates, distances, who's in, fees, registration status, and a course map where we have the route.
  • Feed — the herd's latest PRs, club records, race results and badges, newest first.
  • Leaderboard — the classics from 5K to marathon, longest ride, most climbing and fastest swim, next to side quests like brick days, early birds and 4,000-metre summits.
  • Seasons — every year keeps its own records, ladder and Goat of the Year, so a great season still counts after someone beats it.
  • Badges — 80 of them, each with its own illustration, some for a season and some for life.
Same discipline, smaller stakes.

It's built the way everything else here is built — AI-augmented, reviewed, everything as code — and it's held to the same bar: tests and a contract check between the collector and the page, a deploy that waits for approval, and a red build on main that means production is stale, never flaky.