Work › nurun co.
- Role
- Owner of the race company, and the engineer behind its software.
- Built
- 2017 → now
- History
- Site 1.0 in 2017, 2.0 in 2018, 3.0 (current) in 2021. nurun-admin added in 2026.
- Stack
- Bun · Edge · MySQL · Tailwind · Mailgun
Story
nurun co. is my race company. It puts on the Black River Trail Classic. The public site carries the race details, race updates and results by year and distance.
Behind it is nurun-admin, where I actually run the race. It replaced the spreadsheets I used to juggle. Registrations come in as CSV exports. I assign bibs per race date, track shirt sizes, write thank-you notes by household and send race emails. Then I export the entrant list straight into Bibsee for timing.
Results
- The public site has run since 2017 and is in its third version: 1.0 in 2017, 2.0 in 2018, 3.0 in 2021.
- Runs the Black River Trail Classic: entrants, bibs, shirts, emails and results.
- nurun-admin (2026) replaced my race-week spreadsheets.
- Keeps race history across years: distance mix, repeat runners and the all-time top 5.
System, layer by layer
- [x] Interface
- Edge templates and Tailwind 4, server-rendered, in both apps.
- [x] API
- Bun.serve with hand-rolled routing, a CSRF-protected contact form, and an email one-time-code login for the admin.
- [x] Data
- MySQL through Bun.SQL. Both apps share one schema, with self-run migrations.
- [x] Infra
- Multi-arch Docker images on ghcr, deployed with boxx. GET /up health checks, and Mailgun for email.
- [x] Ops
- A data bundle for export and import, and CSV imports with saved column layouts.
Screens
- Site
- nurun.co
- Status
- Live
- Built
- 2017 → now
Private tool: nurun-admin
Private · Private tool, shown as illustrations · 2026-05 → now
The tool I run race week from. I'm its only user. It isn't public, so the screens here are drawn from its real templates with invented runners.
- Imports registrations, bibs and shirt answers from CSV, with a preview before anything is written
- Assigns bibs per race date and flags conflicts for me to settle
- Tracks shirt sizes: needed, ordered and printed, plus who hasn't answered
- Groups thank-you notes by household and tracks which are sent
- Writes and sends race emails, and publishes them as race updates
- Keeps race history: distance mix, repeat runners, all-time top 5
- Exports each race date's entrants straight into Bibsee
Decisions
- 01
Plan before writing
The import wizard works out every change “before anything is written” and shows a preview, so a bad file never touches the race.
- 02
Never invent a runner
A bib file “only numbers people already registered… a row that matches nobody is skipped, never added.” When a saved bib conflicts, I choose.
- 03
Keep the volunteers
A shirt answer that matches no registrant, like a volunteer or a friend, “is kept and counted.”
- 04
One schema, two apps
The public site reads races, results and published emails straight from the admin's database, so nothing is entered twice.
- 05
Ready for Bibsee
Each race date exports “Entrants for Bibsee” with exactly the columns Bibsee's importer expects.
In the box
- Public: race page, results by year and distance, race updates, race guide PDF
- Admin: races, distances and race dates
- Registrations, plus results import with unlinked-result matching
- Thank-you notes grouped by household
- Participant and race history
- Shirt sizes: needed, ordered and printed
- Marketing emails: test send, send, publish as a race update
- Import wizard for registrations, bibs and shirts, with saved layouts
- Data bundle export and import