Skip to main content

Case Study

Johnson Power Rankings: A World Ranking for the 200+ Mile Ultra

There is no Michigan index for the 200-mile ultra. So we built one.

In ProgressMay 2026 - PresentBuilder (with Paul James Johnson, domain expert)

Updated May 12, 2026

Currently BuildingPure-TS Ranking EngineBuilt With My DadLive in Preview

Johnson Power Rankings

200+ Mile · Week of May 12, 2026

Preview
#RunnerRating
1Rachel Entrican948.2
2Harvey Lewis931.7
3Courtney Dauwalter924.1
4Karel Sabbe918.6
5Aleksandr Sorokin912.3
6Camille Herron907.8
7Laz (Lazarus Lake)894.5

Placeholder data for illustration

johnson-power-rankings.vercel.app

There{'’'}s no Michigan index for the 200

There is no credible, data-driven ranking for 200+ mile ultrarunners. The ITRA Performance Index caps at a generic Endurance bucket. The UTMB World Series index stops at 100 miles. UltraSignups per-race score is trivial. The IAU does not recognize the 200-mile distance. UltraRunning Magazines Ultrarunner of the Year is a subjective panel vote, not a quantitative system.

Johnson Power Rankings fills that void. Modeled in spirit after the ITRA Performance Index, the UTMB Index, and the University of Michigan Consumer Sentiment Index: a recurring, cited number. The kind of number a podcaster can reference, a race director can validate against, and a runner can point to and say thats my standing.

Built with my dad

The Johnson is Paul James Johnson: ultramarathon runner, pacer, crew member, and Jeffs dad. JPR was born from recorded kitchen-table conversations. Paul is the domain expert. He knows the runners by name, the culture of backyard ultras, which podcasters matter, the economics of race photography, which courses are genuinely harder. Jeff is the technical execution: Next.js, Supabase, React Native, Claude-powered development.

The PRD literally names the roles: Owner, Jeff Michael Johnson. Domain expert, Paul James Johnson. The vision is personal. Paul wants to be able to say Rachel Entrican is number one in the Johnson Power Rankings and have it carry weight. They want podcasters to reference JPR the way economists reference the Michigan index. The family name is the brand, on purpose.

Paul James Johnson, in trail running gear and a hydration vest, sitting in the back of a crew van at an ultramarathon
Paul James Johnson — out at an ultra, 2026

~2 days

36 Commits to Deploy

11

Supabase Migrations

4+3

Data Sources + Scrapers

20+

Tables, RLS Everywhere

The engine

The ranking engine lives in @jpr/core, a pure TypeScript package with full Vitest coverage. No runtime dependencies beyond the math.

Course difficulty model: elevation gain and loss per mile, surface factors (track 0.96, road 1.0, trail 1.1, technical 1.22, sand 1.18, snow 1.2), terrain factors (high-altitude 1.12, mountain 1.06, desert 1.05, arctic 1.15), a weather index, and a historical-slow factor derived from past editions.

Field strength: iterative computation with damping, outlier capping at 4× median, and a convergence loop. Stronger fields amplify the signal of a fast time.

Backyard ultras: yards converted to effective miles, with dedicated scoring for assists and co-champion handling. A separate scorer for the formats unique structure.

The rating itself: a time-decayed weighted mean of best-N performance scores over a 36-month rolling window. Linear decay between months 1236, a cold-start prior for athletes with fewer results, and an uncertainty score that widens with sparse data.

How a result becomes a rating

Step 01

Result ingested

Race result pulled from UltraSignup, DUV, RunSignup, or OpenSplitTime. Time, distance, format, DNF status recorded.

Step 02

Difficulty + field strength scored

Course difficulty model (elevation, surface, terrain, weather, historical slow factor) and iterative field-strength computation applied.

Step 03

Rating computed

Time-decayed weighted mean of best-N performance scores over a 36-month rolling window. Linear decay months 12–36, cold-start prior, uncertainty score.

Four surfaces

JPR ships across four coordinated surfaces, all sharing a design system re-themed from PrayerMaps Vesper Twilight palette.

Web

Next.js 15, server-rendered. Public rankings, athlete profiles, weekly snapshots. Live on Vercel.

Admin

11 functional sections: dashboard, data ops, identity resolution, difficulty data, formula explorer, publications, style, flags, cron, dev tools, audit log.

Mobile

Expo SDK 52 / React Native. Tabs for rankings, lookup, archive, about. Push notifications for weekly publishes.

Design System

Shared @jpr/design-system: CSS-variable tokens, Tailwind preset, shadcn-style primitives, RN theme, interactive StyleGuide.

Under the hood

packages/ingest handles connectors for UltraSignup, RunSignup, DUV, and OpenSplitTime, plus three bespoke scrapers for Vol State, Backyard Ultra, and the Self-Transcendence 3100. A normalizer parses time formats, converts distances, and classifies race formats. Identity resolution uses fuzzy name matching with diacritics and script folding, outputting confidence scores for human review.

Supabase backs the entire system: 11 migrations, RLS on all 20+ tables, SECURITY DEFINER RPCs for the admin surface, Auth with TOTP + WebAuthn passkeys, and 6 Deno edge functions (poll-ultrasignup, poll-duv, backfill, resolve-identities, recompute-rankings, generate-digest). A Monday-morning cron recomputes the rankings and publishes an immutable weekly snapshot with movement arrows.

The admin panel covers 11 sections: dashboard with stat cards, data operations, identity resolution queue, difficulty and course data, a rating-formula explorer, publications archive, style management, feature flags, cron and jobs, dev tools, and a full audit log with removal request handling. Built with TanStack Query + Table, react-hook-form + zod, and Supabase Auth + admin_users role + MFA.

CI runs GitHub Actions: typecheck, lint, test. TypeScript strict throughout with noUncheckedIndexedAccess and zero any.

Honest, by design

DNFs count. Every runner who has competed in a qualifying 200+ mile event is ranked, including those who did not finish. The ranking reflects participation in the distance, not just completion.

Immutable weekly snapshots. Rankings publish every Monday as a permanent record. No retroactive edits. The history is the history.

Source-cited data. Every result traces back to its ingestion source: UltraSignup, DUV, RunSignup, or OpenSplitTime. No manual entry without a verifiable origin.

Removal requests respected. Athletes can request removal. The system logs and honors it. Rankings exist to serve runners, not to trap them.

The whole system: an npm-workspace monorepo, a Next.js web app, a separate Next.js admin panel, an Expo mobile app, a pure-TypeScript ranking engine, a Supabase backend with 11 migrations + RLS + 6 edge functions, real data ingestion from four sources with three bespoke scrapers, and two live Vercel deployments.

Scaffolded, built, and deployed in roughly two days across 36 commits. Not a sprint for its own sake. Evidence of what focused, Claude-powered development looks like when the domain expert is sitting across the kitchen table.

Where it{'’'}s headed

JPR is live in preview now. The public site is running at johnson-power-rankings.vercel.app. The admin panel is deployed. Data backfill and tuning are ongoing: international race sources across the US, Europe, Asia, Africa, and Oceania; DUV + UltraSignup event-ID mappings for 200+ mile events from 20212026; field-strength saturation fixes; marquee-race difficulty overrides; a combined All world ranking merging men and women.

Next: public launch, the mobile app on TestFlight, weekly email digests via Substack, and the push-notification pipeline for Monday-morning publishes. The goal is the same one Paul described at that kitchen table: a number people reference, a ranking that earns trust by being transparent about its methodology and honest about its data.

May 2026 · In progress · -JJ

Tech Stack

Frontend

Next.js 15 (Web + Admin)TypeScript (strict)TanStack Query + Tablereact-hook-form + zod

Mobile

Expo SDK 52 (Mobile)Expo Router

Backend

@jpr/core (rating engine)@jpr/ingest (connectors + scrapers)Supabase (Postgres + RLS)Deno Edge Functionspg_cron (weekly recompute)WebAuthn + TOTP (Passkeys + MFA)

Tooling

VitestGitHub Actions

Infrastructure

Vercel

Want to discuss the architecture?

Get in Touch
Johnson Power Rankings: A World Ranking for the 200+ Mile Ultra — Jeff Michael Johnson