Dugout Value
Baseball research on pitching, hitting, and projections, plus tools for comparing players, contracts, and trade value.
Stats, ratings, brackets, and events for the SEC billiards group
Sports & fitnessTypeScript · PLpgSQLGitHub @Dimas-100OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Loading comments.
Checking sign-in status.
SEC Billiards League: a mobile-first PWA for a college pool league — Fargo-style ratings, live match scoreboard with races and spots, cups with seeded brackets, events, chat, push notifications. Next.js 16 + Supabase.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
A mobile-first web app for a college billiards league across five schools. Members log games from
the table, confirm each other's results, climb a Fargo-style rating ladder and an XP ladder with
title badges, run cups with seeded brackets, keep a calendar with RSVPs, and chat in league, school
and direct rooms, with push notifications they control. Installs to the home screen as a PWA.Read the full README ↗A mobile-first web app for a college billiards league across five schools. Members log games from the table, confirm each other's results, climb a Fargo-style rating ladder and an XP ladder with title badges, run cups with seeded brackets, keep a calendar with RSVPs, and chat in league, school and direct rooms, with push notifications they control. Installs to the home screen as a PWA.
Live: https://secbl.vercel.app · Stack: Next.js 16 (App Router, Server Actions) · React 19 · TypeScript · Tailwind 4 · Supabase (Postgres, Row Level Security, Realtime, Storage, Auth) · Web Push (VAPID) · Vitest · Playwright · Vercel
lib/*.ts with no I/O, covered
by Vitest. Integration tests exercise RLS and the SQL functions against a real project; Playwright
drives the flows end to end (signup, logging and confirming a race, a cup to a champion, DMs with
live delivery, password reset, logout).SECURITY DEFINER functions in supabase/migrations/; the app never updates
those tables directly. Levels and achievements are computed from match history, never stored.cp .env.example .env.local # Supabase URL + anon + service keys, and the VAPID push keys (`npx web-push generate-vapid-keys`)
npm install
npm run dev # http://localhost:3000
Database changes are SQL files in supabase/migrations/, applied in order to a Supabase project.
npm run lint
npx tsc --noEmit
npx vitest run --exclude "tests/*.integration.test.ts" # pure logic, no network
npx vitest run # + RLS/messaging/push tests against the live project
npx playwright test --workers=1 # e2e; parallel runs are flaky from cold compiles, not bugs
npm run build
The integration and e2e suites create and delete real rows in the configured Supabase project.
Teardown lives in afterEach (e2e/cleanup.ts).
Vercel is not git-connected. From this directory: npx vercel deploy --prod --yes. vercel.json
schedules a daily health check that keeps a free-tier database from pausing, and a daily event sync.
| Path | What |
|---|---|
app/(public) | login, signup (tap-your-school picker), password reset, install guide and invitation card |
app/(member) | everything behind login: home, log a game, events (+ cups), leaderboard, players, chat, settings, admin |
lib/rating.ts, lib/bracket.ts, lib/seeding.ts, lib/race.ts, lib/levels.ts, lib/season.ts, lib/activity.ts, lib/feed.ts, lib/live.ts, lib/chat.ts, lib/inbox.ts, lib/push.ts, lib/events.ts | pure, test-first logic |
lib/activity-write.ts, lib/season-data.ts, lib/season-tick.ts | server-side feed moments, season loaders, the daily season reminder (runs from /api/health) |
lib/push-send.ts, public/sw.js | Web Push: server-side send (VAPID, service role) and the service worker that shows it |
supabase/migrations | schema, RLS, SECURITY DEFINER functions (the only write path for ratings, brackets, membership) |
docs/superpowers/specs | design specs per feature; plans/ the implementation plans |
apply_match_confirmation / the tournament functions under one advisory lock, and current
ratings always equal a replay of confirmed matches.winner_id is always the higher score. race_to null means open
play. Spots never change rating or XP..range() asks for.
Whole-table scans page through lib/paging.ts.played_at; nothing is stamped
on it. Only open_season / close_season write the seasons table, and only one can be open.matches, tournaments, tournament_matches and
profiles, by the season functions, and by the service role after a confirmation (badge, streak,
pass). Every derived row carries its match_id, so leaving confirmed deletes them all.messages.notified_at first, so it can only fire once.lib/events.ts (America/New_York); the server runs in UTC.MIT — see LICENSE.