Caleb Lanting
TrackR

A companion app for coaster and theme-park fans.

TrackR logs every ride you've been on and helps you plan a park day with live waits, hours, weather, menus and maps. Behind it is a data platform that knows where every fact came from and whether it's allowed to show it.

Role
Sole developer: product, design, app and data platform
Status
Beta on TestFlight. Android build in internal QA
When
November 2025 to now
Built with
React Native, Firebase, Python, PostgreSQL, Next.js
The app’s own screens, redrawn with a made-up park and ridesiPhone app · Android build in QA

The problem

Coaster fans keep count of every ride they've been on. I kept mine in a Word document for years. TrackR started as a better home for that count, then grew into the app I wanted in the park: what's open, how long the lines are, and what the weather is about to do.

The app turned out to be the easy half. The hard half was the data: parks and rides described differently by dozens of sources, each with its own terms for what you may show and for how long.

What I built

An iPhone app, the platform that feeds it, and the tools to run both.

  • A ride log that keeps score

    Log a ride in a couple of taps, rate it, and watch your count and rankings grow. A daily coaster puzzle, Coastle, is there for the days between trips.

  • Everything for a park day

    Live wait times, hours, weather, menus and maps for the park you're standing in.

  • A data platform with a memory

    41 ingesters written in Python pull from 35 licensed sources into PostgreSQL with PostGIS. A Fastify API serves the app, and every fact keeps its source.

  • An admin app

    A 69-page Next.js admin that reads and edits both back ends.

The hard part

Knowing where every fact came from, and what its license allows.

A ride's height, its opening year and today's park hours can come from open data, a park's own feed or a weather service. Some sources allow commercial use, some require credit, and some only allow a short window of data.

So every fact is stored as its own row: the value, the source, the link, the license, a confidence and when it was fetched. A merge step picks exactly one canonical value for each field, and the database enforces that with a unique index, so two "true" answers can't exist at once.

Each source's terms are written into code. Sources carry a commercial-safe flag and their attribution text. One feed's park hours are kept only from yesterday to two weeks out, its wait times only as the latest value, and its name is masked in the public API.

8 of 8 fields served.

GET /v1/attractions/millennium-force/provenance

Millennium Force

Cedar Point · Sandusky, Ohio

Illustrative record
    • CoasterpediaCC BY-SA 4.0Canonical310 ftconfidence 0.95Fetched Sep 30
    • WikidataCC0Canonical94.5 mconfidence 0.90Fetched Sep 28
    • WikipediaCC BY-SA 4.0Canonical310 ftconfidence 0.85Fetched Sep 21
    • CoasterpediaCC BY-SA 4.0Canonical93 mphconfidence 0.95Fetched Sep 30
    • WikidataCC0Canonical150 km/hconfidence 0.90Fetched Sep 28
    • Fan stats siteCC BY-NC 4.0Canonical92 mphconfidence 0.60Fetched Aug 14
    • WikidataCC0Canonical2000confidence 0.97Fetched Sep 28
    • CoasterpediaCC BY-SA 4.0Canonical2000confidence 0.95Fetched Sep 30
    • OpenStreetMapODbLCanonical41.48° N, 82.69° Wconfidence 0.98Fetched Sep 26
    • WikidataCC0Canonical41.49° N, 82.68° Wconfidence 0.85Fetched Sep 28
    • Park feedFact, creditedCanonical45 minconfidence 0.993 min ago
    • Wait aggregatorFact, creditedCanonical40 minconfidence 0.9012 min ago
    • Park feedFact, creditedCanonical10 AM – 10 PMconfidence 0.99Today
    • Wait aggregatorFact, creditedCanonical10 AM – 10 PMconfidence 0.90Today
    • Open-MeteoNon-commercial termsCanonical64°F, cloudyconfidence 0.9320 min ago
    • MET NorwayCC BY 4.0Canonical63°F, cloudyconfidence 0.9025 min ago
    • Fan galleryCC BY-NC 4.0Canonical1 photoconfidence 0.80Fetched Aug 2
Attribution shown with it

Data from Coasterpedia contributors, CC BY-SA 4.0 · Data from Wikidata, CC0 · Map data © OpenStreetMap contributors, ODbL · Waits and hours from the park’s public feed · Weather data by Open-Meteo.com · Photo from a fan gallery, CC BY-NC 4.0

A real ride with example values. Open any field to see every source it came from. Each one is a row with its source, license, confidence and fetch time, and Postgres allows one canonical row per field (UNIQUE … WHERE is_canonical).

How it fits together

Two back ends, each doing what it's good at.

Park and ride data lives in PostgreSQL, where provenance, licenses and places on a map are easy to query. People's own data, their logs, ratings and profiles, lives in Firebase, which handles sign-in and syncs to the phone.

When it broke

In October I found the API had been down for about two weeks. The server's disk had filled with wait-time history and the database had stopped.

Restarting it would have bought a few weeks. Instead the history now goes to cloud storage, a daily job keeps the live table to 14 days, the database restarts itself, the nightly backup works again, and the admin shows the server's health so a stall can't hide.

By the numbers

35licensed data sources, fed by 41 ingesters
~331Klines of hand-written TypeScript across the app, admin and API
111Cloud Functions
78database migrations
1,209commits to the app

Counted from the TrackR repositories on October 9, 2026. Lines exclude tests and generated files.

Stack and role

I'm the only developer. I designed the app and the data model and made every product call. AI coding agents wrote the code from my tickets: a lead agent planned and reviewed, worker agents built, and I decided what shipped. 718 of the app's 1,209 commits credit Claude as co-author.

React NativeExpoTypeScriptFirebase AuthFirestoreCloud FunctionsPythonPostgreSQL 16PostGISFastifyNext.jsCloudflare R2

Want to build something together?

I'm looking for a team to build with full time. Email is the fastest way to reach me.