A multi-tenant tournament bracket-pool platform. Create a pool, invite friends, make bracket picks, and watch a live leaderboard update as real results come in. It began life as a World Cup 2026 prediction game for a friend group and is generalizing into a platform where anyone can run a pool.
Note: the npm package is still named
hessfest(the original pool); the product name is Bracketeer.
- Full-bracket and knockout pools — predict the whole tournament, or just the knockout rounds once the field is set.
- Live scoring & leaderboards — entries are scored against an official answer key with a cached, ranked leaderboard; live/provisional points update as group and knockout matches play out.
- Home group-stage overlay — see your bracket picks overlaid on the live group standings, with a per-group breakdown of the points each pick is earning.
- Solo brackets + a global master tournament — build a bracket without a pool and opt into a shared global leaderboard.
- Real-time updates — Server-Sent Events via Postgres
LISTEN/NOTIFY, with polling fallback. - Optional integrations, all behind env gates — Google / magic-link auth, live scores & odds, Stripe billing, native push, GIPHY. Everything degrades gracefully and the app builds and runs with no keys configured.
- CSV import/export of picks, sharing one encoding with DB storage.
Next.js (App Router) · TypeScript · Prisma + PostgreSQL · Auth.js v5 · TailwindCSS ·
Vitest · Playwright · Capacitor (iOS wrap). External integrations are implemented SDK-free
(fetch / node:crypto) to keep installs light and the build green without keys.
Prerequisites: Node 22.x and a PostgreSQL database. No API keys are required — every integration is optional and the app runs fully keyless.
No Postgres handy? Start one with Docker:
docker run -d --name bracketeer-db -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:16
# → DATABASE_URL=postgresql://postgres:postgres@localhost:5432/bracketeer# 1. Install
npm install
# 2. Configure env
cp .env.example .env # set DATABASE_URL, CRON_SECRET, APP_BASE_URL
npx auth secret # generates AUTH_SECRET and writes it into .env
# 3. Set up the database (these npm scripts load .env for you)
npm run db:deploy # apply migrations
npm run db:generate # generate the Prisma client
npm run db:seed # seed the World Cup 2026 tournament (48 teams, 104 matches)
# 4. (optional) Load a demo pool — synthetic entries + a live leaderboard
npm run db:demo
# 5. Run
npm run dev # http://localhost:3000Required env vars: DATABASE_URL, AUTH_SECRET (16+ chars — npx auth secret generates one),
CRON_SECRET, APP_BASE_URL. Every third-party integration is optional — see
.env.example and lib/env.ts for the full list and the
boolean flag each one exposes.
npm run dev # dev server
npm run build # production build (compiles/validates every route)
npm run typecheck # tsc --noEmit
npm run lint # eslint
npx vitest run # unit tests (no DB needed)
npm run test:e2e # Playwright E2EThe codebase is organized around one invariant: scoring stays byte-for-byte identical to the
original pick tool, so existing standings never change. lib/scoring/ holds the ported,
load-bearing engine (with a golden oracle test running 2000 randomized parity checks), and the
schema is multi-tenant by construction. See CLAUDE.md for a detailed tour of the
architecture and conventions.