Garrett Holmes Denver · replies within one business day

Case file № 006 · Data pipeline · Automated publishing

The best data in town was a spreadsheet

System

303.show

Client

Community dataset, made usable


3,200+
shows published
39
venues, every morning
96%
with a real ticket link

The most complete list of Denver concerts lived in a community-maintained spreadsheet — twelve monthly grid tabs, venues as columns, unreadable on a phone. I built a pipeline that reads it every morning and republishes it as a fast, shareable site: 3,200-plus shows across 39 venues, 96% carrying a real ticket link. No database, no server, no accounts.

In
Community spreadsheet 12 grid tabs · XLSX, links intact
The system
Morning pipeline systemd timer · fail-safe contract
Git as change log commits only when something changed
Out
Static site 3,200+ shows · 30 KB homepage
Feeds & calendars RSS · per-venue subscriptions
Fig. 1 — The maintainer keeps their spreadsheet. The city gets a website.

Before

  • The best listings in the city were a Google Sheet: twelve monthly grid tabs, venue names across the top, dates down the side, and more than one show crammed into a single cell.
  • The sheet stores no year at all, and the dates embedded in it are a year stale — every date has to be inferred.
  • The obvious way to read it, the CSV export, silently drops every ticket hyperlink — the single most valuable thing in the file.
  • Every alternative wanted a login, an app install, or a scroll past sponsored posts first.

After

  • A timer on a small Linux box reads the workbook every morning in the format that preserves the links, normalizes it, and commits the result only if something actually changed. That commit rebuilds everything downstream — show pages, venue pages, sitemap, RSS, and every calendar feed — with nothing else to trigger.
  • Dates are assigned on a rolling forward calendar, guarded by an archive of what each month used to contain, so a tab the maintainer hasn’t refreshed yet can’t ship a phantom month of shows.
  • A fail-safe contract: if a column disappears or nothing parses, the job exits and writes nothing, and the last known-good file keeps serving. Unparseable rows are logged, never quietly dropped.
  • Because the data is committed to version control, “what changed today” is free — it powers the Just Added page, the feed, and per-venue calendar subscriptions, with no database anywhere.
  • The homepage went from 3.1 MB of HTML to 30 KB by keeping the dataset out of the browser entirely.

The verdict

Somebody was already doing the unglamorous work of keeping that sheet current. The job was to leave them alone and make their spreadsheet legible to a whole city — every morning, without anyone touching it.

Nodethe data pipeline
XLSX parsingthe format that keeps the hyperlinks
SvelteKitstatic build — pages, feeds, sitemaps
systemd timerthe morning refresh, on a box I run
gitthe change log; “what’s new” for free
Cloudflare Pageshosting

Garrett Holmes — The Operations Ledger

Composed by hand in Denver. Replies within one business day.