Skip to content

Latest commit

 

History

447 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Clippers Command Center

Live: clippers.lukeghanna.com

A desktop analytics dashboard for avid LA Clippers fans. Three modes that blend into one continuous experience:

  • Live Game Mode — dense box score, rotating "provable" insights, league-context side panels, Vegas odds, polling every ~12s during Clippers games.
  • Between-Games Mode — team snapshot, upcoming schedule, player trend summaries, macro insights.
  • Historical Explorer — every season since 2010-11, game by game, with drill-through to box scores and trend charts.

What makes it different

Provable insights, not vibe stats. Every headline on the dashboard is generated by a deterministic engine that must verify the claim against stored data before displaying it. If it can't prove "first time in franchise history a Clipper has scored 50+ in a quarter" from the DB, it doesn't show it. Each insight stores the query that produced it, and that stored query is the one that ran — npm run verify-insights re-executes every active proof and fails if a claim is no longer backed by the data. League-wide box scores (every NBA game, not just the Clippers') power ranks, percentiles and scouting reports.

Real-time without flicker. The live page uses SWR over a Next.js API that merges a short-lived cache with snapshots written by a background poller. Stale reads surface a banner instead of silently serving old numbers.

One operator, full pipeline. Schedule sync, odds sync, live polling, finalization, league ingest, stat computation, and insight generation all run as separate scripts, all scheduled by GitHub Actions (live polling is a game-night runner that polls every 12s during Clippers games) — no hosted workflow engine, no queue, no magic.

Stack

  • Next.js 16 (App Router, Turbopack) + React 19 + TypeScript
  • Neon Postgres via postgres
  • Tailwind v4 with a small in-house component set (Geist type, Clippers palette), Recharts, cmdk
  • SWR for client data, tsx for ops scripts
  • Vitest for unit tests
  • Served at clippers.lukeghanna.com (Vercel project clippers-command-center; the *.vercel.app and ccc. hosts redirect there); every data job runs on GitHub Actions

Data sources

  • balldontlie.io — NBA schedule, games, box scores (historical + finalization)
  • stats.nba.com / NBA CDN — live in-game polling and schedule backfill
  • the-odds-api.com — Vegas odds (display + insight annotation; no betting)

Repo layout

app/                  — Next.js App Router: /live, /home, /schedule, /history, /players
components/           — UI: ui/ primitives, shell/ (top bar, ⌘K), game/, live/, home/, players/, schedule/, history/
hooks/                — useLiveData, useInsightRotation
src/lib/              — DB client, insight engine, domain utils + tests
scripts/              — pipeline scripts (sync, ingest, compute-stats, insights); scripts/lib/insights = batch insight engine
scripts/dev/          — seed-fixture-league.ts: synthetic league for local/CI pipeline tests
Docs/                 — ARCHITECTURE.md, API_SPEC.md, DB_SCHEMA.sql, DATA_DICTIONARY.md, migrations/

Running locally

cp .env.example .env.local   # fill DATABASE_URL, BALLDONTLIE_API_KEY, ODDS_API_KEY, CRON_SECRET
npm install
npm run db:schema            # applies Docs/DB_SCHEMA.sql to Neon
npm run sync-schedule        # seed a season
npm run compute-stats
npm run dev                  # http://localhost:3000

Tests:

npm test                     # vitest (unit)
npm run lint

# End-to-end pipeline test against a throwaway LOCAL Postgres (wiped):
FIXTURE_DATABASE_URL=postgres://postgres@127.0.0.1:5432/fixture npm test

Data-pipeline scripts:

npm run sync-schedule        # schedule from BDL
npm run sync-odds            # Vegas odds
npm run poll-live            # game-night live poller (GitHub Actions: game-night.yml)
npm run backfill-schedule-nba          # attach official NBA game ids to Clippers games
npm run sync-league-games              # every NBA game from the last 3 days (nightly)
npm run sync-league-games -- --season=2025-26   # load a whole past season, league-wide
# Seasons before 2019-20 aren't in the cdn.nba.com archive and load from stats.nba.com,
# which blocks cloud IPs — run them from a home network, e.g.:
DB_POOL_MAX=10 npm run sync-league-games -- --season=2012-13
npm run finalize-games                 # lock Clippers box scores after each game
npm run compute-stats                  # advanced stats + rolling windows (incremental; --all to rebuild)
npm run generate-insights -- --verbose # run the insight engine, print every headline
npm run verify-insights                # re-run every active insight's proof query

Status

  • 18 routes deployed to production
  • 266 commits, 16 phases shipped
  • Tests cover the domain layer: insight engine, odds math, history, home, live, players, schedule
  • Responsive down to phone width; installable to the home screen (web app manifest)
  • /dev/live renders the Live view from a fixture payload in development (404 in production)

Product definition, architecture, and the live API contract are in docs/.

About

Live analytics dashboard for LA Clippers fans. Next.js 16 + Neon Postgres + NBA live data. Provable-insights engine.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages