Skip to content

Latest commit

Β 

History

History
101 lines (75 loc) Β· 4.97 KB

File metadata and controls

101 lines (75 loc) Β· 4.97 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

TriTimes is a Next.js web application that lets athletes view their historical IronMan and IronMan 70.3 triathlon results. For each result, it shows statistical distributions for each discipline (swim, bike, run) and total time, comparing performance against the athlete's age group and overall field.

Data is collected from https://www.ironman.com/races/im703-new-york/results. Inspired by https://www.hyresult.com/.

Architecture

  • app/ β€” Next.js 16 app with React 19, TypeScript, Tailwind CSS v4, Recharts, Vercel Analytics
  • scripts/ β€” Node.js data pipeline scripts (zero dependencies, requires Node 18+)
  • data/ β€” Race result CSVs and races.json manifest

Pages & Routes

  • / β€” Landing page with hero section and global athlete search
  • /races β€” Browse all races with distance (70.3/140.6) and year filters
  • /race/[slug] β€” Single race with in-page athlete search
  • /race/[slug]/result/[id] β€” Individual result with discipline histograms (age group & overall field toggle)
  • /athlete/[slug] β€” Athlete profile showing cross-race history
  • /api/search β€” API endpoint for global athlete search (used by GlobalSearchBar)

Performance

  • Result and race pages use on-demand generation (empty generateStaticParams) to avoid pre-rendering 75K+ pages at build time
  • Athlete search uses a pre-built JSON index (data/athlete-index.json) generated at build time, avoiding CSV parsing on first request
  • Athlete search uses debounced input (300ms) with a cached deduplicated index
  • CSV parse results are cached in memory

Data Strategy

  • CSVs (data/*.csv) are committed to git (~400 KB per race)
  • Raw JSON (data/raw/) is gitignored (~10 MB per race)
  • Athlete index (data/athlete-index.json) is gitignored; generated at build time by scripts/build-search-index.js
  • Athlete profiles (data/athlete-profiles.json) is gitignored; compact slugβ†’race mapping generated at build time
  • Manifest (data/races.json) lists all races; auto-generated by scraper, read by app at build time
  • The app reads races from data/races.json β€” adding a new race only requires running the scraper, no code changes

Key File Paths

  • app/src/lib/data.ts β€” Server-side data access (reads CSVs, computes histograms, athlete deduplication & profiles)
  • app/src/lib/types.ts β€” TypeScript interfaces (AthleteSearchEntry, AthleteProfile, AthleteRaceEntry, etc.)
  • app/src/lib/colors.ts β€” Canonical discipline color constants (swim, bike, run, overall, T1, T2)
  • app/src/lib/flags.ts β€” Country ISO to flag emoji mapping
  • app/src/components/GlobalSearchBar.tsx β€” Cross-race athlete search with debounce, caching, and keyboard nav
  • app/src/components/SearchBar.tsx β€” Single-race in-page athlete search
  • app/src/components/DisciplineSections.tsx β€” Discipline histograms with age group / overall field toggle
  • app/src/components/Header.tsx β€” Sticky header with navigation
  • app/src/app/page.tsx β€” Landing page with hero section and global search
  • app/src/app/races/page.tsx β€” Race listing with distance and year filters
  • app/src/app/athlete/[slug]/page.tsx β€” Athlete profile page
  • app/src/app/race/[slug]/result/[id]/page.tsx β€” Individual athlete result page
  • app/src/app/api/search/route.ts β€” Athlete search API endpoint
  • scripts/build-search-index.js β€” Pre-builds deduplicated athlete search index from CSVs (runs automatically during npm run build)
  • scripts/scrape.js β€” Single-race scraper (also exports reusable functions)
  • scripts/discover.js β€” Discovers event IDs from ironman.com or competitor.com URLs
  • scripts/scrape-all.js β€” Batch scraper using race-registry.json
  • scripts/race-registry.json β€” Registry of known races with group URLs
  • data/races.json β€” Race manifest consumed by the app

Commands

# Development
cd app && npm run dev

# Build
cd app && npm run build

# Scrape a single race
node scripts/scrape.js <slug> [event-id] [--no-raw]

# Discover event IDs
node scripts/discover.js <url>

# Batch scrape
node scripts/scrape-all.js [--slug=<slug>] [--year=2025] [--dry-run] [--save-raw]

# Build search index (runs automatically during npm run build)
node scripts/build-search-index.js

Design: Discipline Colors

Canonical colors for triathlon disciplines. Defined in app/src/lib/colors.ts β€” always import from there, never hardcode.

Discipline Hex Tailwind
Swim #3b82f6 blue-400
Bike #ef4444 red-400
Run #f59e0b amber-400
Overall #9ca3af gray-400
T1 #8b5cf6 purple-400
T2 #ec4899 pink-400

Conventions

  • Use Conventional Commits for commit messages and PR titles (e.g. feat:, fix:, docs:, chore:, refactor:)