Prode is a Next.js App Router project for World Cup prediction rooms. It uses Prisma + Postgres, Auth.js OAuth, and a seeded WC 2026 dataset.
- Node.js 20+
- Docker (recommended for local Postgres)
- npm
Follow these steps to set up the project from zero:
docker compose up -dThis starts both the main dev database (port 5434) and test database (port 5433).
Copy the example and configure it:
cp .env.example .envEdit .env and set at minimum:
DATABASE_URL=postgresql://leniolabs:leniolabs@localhost:5434/prode
AUTH_SECRET=<generate-with-command-below>
GOOGLE_ID=<your-google-oauth-client-id>
GOOGLE_SECRET=<your-google-oauth-client-secret>Generate AUTH_SECRET:
openssl rand -hex 32npm installnpx prisma migrate deploynpx prisma db seedThis creates 48 countries, 72 group-stage matches, and 32 knockout matches.
npm run devThe app will be available at http://localhost:3000
If port 5432 is already in use, you can run a standalone container on a different port:
docker run -d --name prode-db-local \
-e POSTGRES_DB=prode \
-e POSTGRES_USER=leniolabs \
-e POSTGRES_PASSWORD=leniolabs \
-p 5434:5432 postgres:15.1Then update your .env:
DATABASE_URL=postgresql://leniolabs:leniolabs@localhost:5434/prodeIf you need to wipe and recreate the database:
npx prisma migrate reset --force --skip-seed
npx prisma db seedAUTH_SECRETis required by Auth.js. Missing it causes a server configuration error.- OAuth providers are conditionally registered from env vars.
- For Google sign-in,
GOOGLE_IDandGOOGLE_SECRETare enough. - Google callback URI for local development:
http://localhost:3000/api/auth/callback/google
If the app runs on another port (for example 3001), add that callback URI too.
- Main schema lives in
prisma/schema.prisma. - "Teams" are represented by the
Countrymodel. - Matches are represented by the
Matchmodel. - Migration SQL history is in
prisma/migrations/.
Useful checks:
PGPASSWORD=leniolabs psql "postgresql://leniolabs:leniolabs@localhost:5434/prode" -c "\dt"
PGPASSWORD=leniolabs psql "postgresql://leniolabs:leniolabs@localhost:5434/prode" -c "show search_path;"If a DB client (for example DBeaver) shows empty tables but psql does not:
- confirm host/port/database/user match your
DATABASE_URL - set active schema to
public - refresh schemas and clear object filters
npm run dev
npm run build
npm test
npm run test:coverage
npm run test:db:up
npm run test:db:reset
npm run harness:checkUse idempotent seed scripts, not ad-hoc SQL inserts.
- Countries seed:
prisma/seed/countries.ts - Group matches seed:
prisma/seed/fixture.ts - Knockout bracket seed:
prisma/seed/bracket.ts - Entry point:
prisma/seed/index.ts
npx prisma db seedThis creates 48 countries, 72 group-stage matches, and 32 knockout matches.
For testing the /groups and /finals pages with all results filled in:
npx tsx prisma/seed/demo-results.ts [email@example.com]This:
- Populates all group and knockout matches with final results
- Flips the prode to FINALS phase
- Seeds template predictions for the specified user (or all users if no email provided)
Example:
npx tsx prisma/seed/demo-results.ts you@example.comRe-running is safe; it overwrites the template predictions each time.