Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

166 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BallKnowledge ⚽ — World Cup 2026 Reputation Arena

Build Next.js PostgreSQL Live

"Build your football reputation, one match at a time."

BallKnowledge is a premium World Cup 2026 prediction and debate platform. Fans lock in match predictions, submit bold hot takes, and earn collectible FIFA-style Verdict Cards — all tracked against a persistent Football IQ reputation score.

🔗 Live: ballknowledge.live


Product Flow

Locker Room → World Cup Hub → Match Room → VAR Tribunal → Verdict Card → My Card → Share
  1. Locker Room (/profile) — Manage manager profile settings in a widescreen 3-column cockpit (Identity, FUT Card Spotlight, Telemetry & Operations) with secure credentials authentication.
  2. World Cup Hub (/world-cup-hub) — Browse all 104 fixtures across Groups A–L with live standings
  3. Match Room (/match/[id]) — Before kickoff: lock score prediction, MOTM, goalscorer, hot takes, and Best XI squad. Once the match starts, a shared database live banter chat opens.
  4. VAR Tribunal — After a match completes, the AI grades your hot takes and checks your score prediction against actual results
  5. Verdict Card — A custom FIFA-style collectible card is generated based on your performance score
  6. My Card (/football-iq) — View your Football IQ card and collected card album
  7. Share — Viral share links for individual cards (/card/[id]) and full profile decks (/u/[username])

Tech Stack

Layer Technology
Framework Next.js 16.2.9 (App Router, Turbopack)
Language TypeScript, React 19
Database PostgreSQL via Prisma Client v6
State localStorage-first with secure credentials login & database-backed live chat
AI OpenRouter → Groq → Nvidia NIM → Deterministic fallback
Styling Tailwind CSS v4, Dark Glassmorphism, custom CSS
Animation Framer Motion, GSAP + ScrollTrigger, Lenis
Icons Lucide React
Fonts Space Grotesk (display), Outfit (body), Oswald (cards)
Deployment Cloudflare Pages (Serverless)

Scoring & Formulas

Match Status

Status Condition Predictions
UPCOMING Before kickoff ✅ Editable
LIVE Kickoff → +2 hrs 🔒 Locked
COMPLETED Kickoff +2 hrs 🔒 Locked & Graded

Football IQ Rating Formula

$$\text{Overall Rating} = (0.35 \times \text{PRD}) + (0.25 \times \text{MGR}) + (0.25 \times \text{HOT}) + (0.15 \times \text{RST})$$

Metrics Breakdown

1. Predictor Score (PRD) — 0-100 Points

Points are earned across Match Outcome, Scoreline Accuracy, Man of the Match, and First Goalscorer. Max capped at 100.

  • Match Outcome (35 Points): Correct Draw (35 pts), Correct Winner (30 pts), Wrong Outcome (15 pts)
  • Scoreline Accuracy (30 Points): Home/Away goals (each exact: 15 pts, off by 1: 10 pts, off by 2: 5 pts, off by 3+: 0 pts)
  • Man of the Match (20 Points): Correct MOTM name match (20 pts), Partial name match/same team (12 pts), Wrong (4 pts)
  • First Goalscorer (15 Points): Correct first goalscorer (15 pts), Scored later in the match (10 pts), Wrong/no contribution (3 pts)

2. Manager Score (MGR) — 10-99 Points

  • Formula: $\text{Round}(\text{Average Match Performance Rating of Selected XI} \times 10)$
  • Player ratings are based on official FIFA match-specific performance scores (ranging from 4.5 to 9.9) for completed/resolved matches, rather than static card OVRs.

3. Hot Take Score (HOT) — 0-100 Points

  • Formula: Average of graded take base scores multiplied by confidence level.
  • Base Scores: CORRECT (100 pts), PARTIALLY_CORRECT (75 pts), INCORRECT (50 pts)
  • Confidence Multiplier: 1 (0.8x), 2 (0.9x), 3 (1.0x), 4 (1.1x), 5 (1.2x)
    • Free users: 3 takes graded per match; Premium/Admin users: up to 5.

4. Roast Score (RST) — 50-100 Points

  • Formula: $50 + \text{messages sent} + \text{positive reactions (upvotes)}$, capped at 100.

Card Rarity

OVR Rating Rarity
90–99 🟡 LEGENDARY
75–89 🟣 EPIC
60–74 🔵 RARE
1–59 ⚪ COMMON

Getting Started

Prerequisites

  • Node.js ≥ 18
  • PostgreSQL database (local or hosted — Supabase, Railway, Neon)
  • At least one AI key (OpenRouter recommended; Groq as fallback)

1. Install

npm install

2. Environment Variables

Copy .env.example and fill in your values:

cp .env.example .env
# Required
DATABASE_URL="postgresql://<user>:<password>@<host>:<port>/<db>?schema=public"

# AI grading — at least one required
OPENROUTER_API_KEY="sk-or-..."   # Primary (AI grading + image gen)
GROQ_API_KEY="gsk_..."            # Fallback
NVIDIA_API_KEY="nvapi-..."        # Second fallback

# Required for production (OG image, sitemap)
NEXT_PUBLIC_SITE_URL="https://ballknowledge.live"

# Optional: Google SSO Auth
NEXT_PUBLIC_GOOGLE_CLIENT_ID="your_google_client_id.apps.googleusercontent.com"

# Optional: Discord OAuth2 Authentication
NEXT_PUBLIC_DISCORD_CLIENT_ID="your_discord_client_id"
DISCORD_CLIENT_SECRET="your_discord_client_secret"

# Optional: Facebook OAuth2 Authentication
NEXT_PUBLIC_FACEBOOK_APP_ID="your_facebook_app_id"
FACEBOOK_CLIENT_SECRET="your_facebook_client_secret"

3. Database Setup

# Push schema to DB (creates all tables)
npx prisma db push

# Or run migrations
npx prisma migrate dev

# Generate Prisma client
npx prisma generate

4. Run Dev Server

npm run dev
# → http://localhost:3000

5. Production Build

npm run build
npm run start

Project Structure

src/
├── app/
│   ├── page.tsx                  # Landing page (light-themed intentionally for marketing)
│   ├── layout.tsx                # Root layout + metadata (OG, Twitter)
│   ├── globals.css               # Design system, keyframes, glassmorphism
│   ├── error.tsx                 # Global error boundary
│   ├── not-found.tsx             # Branded 404 page
│   ├── sitemap.ts                # Auto-generates /sitemap.xml
│   ├── world-cup-hub/            # Tournament schedule + standings (dark theme)
│   ├── match/[id]/               # Match prediction cockpit (dark theme)
│   ├── football-iq/              # My Card + collected cards album (dark theme)
│   ├── profile/                  # Profile settings + avatar (dark theme)
│   ├── card/[id]/                # Viral card share page (dark theme)
│   ├── u/[username]/             # Public profile share page
│   ├── leaderboard/              # Global manager leaderboard (dark theme)
│   └── api/
│       ├── matches/              # GET all World Cup fixtures
│       ├── teams/                # GET all World Cup teams
│       ├── resolve-match/        # POST: AI-grade and save predictions
│       ├── profile/[username]/   # GET public profile
│       ├── card/[id]/            # GET shared card data
│       ├── leaderboard/          # GET ranked leaderboard entries
│       ├── auth/                 # POST: Secure manager sign-in/sign-up
│       ├── chat/[matchId]/       # GET/POST: Database-backed room banter chat
│       └── stats/                # GET community counter stats
├── components/
│   ├── TacticalPitch.tsx         # Interactive 4-3-3 squad builder grid
│   ├── PredictionModal.tsx       # Predictions + hot takes form
│   ├── MatchLiveChat.tsx         # Database-backed banter chat (live matches)
│   ├── SportsCenterCard.tsx      # FIFA-style card renderer (canvas + SVG)
│   ├── FlagImage.tsx             # flagcdn.com flag images w/ emoji fallback
│   ├── Navbar.tsx                # Solid top header (bg-[#0B0F19], no transparency)
│   ├── Footer.tsx                # Footer
│   ├── Providers.tsx             # React Query + client providers
│   ├── PageTransition.tsx        # Framer Motion page transition wrapper
│   └── SmoothScroll.tsx          # Lenis smooth scroll init
├── lib/
│   ├── matchUtils.ts             # Shared: parseLocalDate, getDeterministicMatchResult, getFlagEmoji
│   ├── countries.ts              # Country name → ISO code map (+ flagcdn URL helper)
│   ├── worldcupData.ts           # Server-side match/team fetcher (local JSON, 5-min TTL cache)
│   ├── worldcup2026/
│   │   ├── football.matches.json # 104 World Cup 2026 fixtures (authoritative data source)
│   │   └── football.teams.json   # 32 World Cup teams
│   ├── profileSync.ts            # Client-side localStorage ↔ DB sync helpers
│   ├── roster.ts                 # 32-team player roster data
│   ├── landingData.ts            # Static data for landing page tickers
│   ├── db.ts                     # Prisma singleton client
│   └── tribunalDB.ts             # Static tribunal/verdict data types
prisma/
│   └── schema.prisma             # DB models: FootballIQProfile, MatchPrediction, HotTake, ChatMessage, MatchCard
public/
│   ├── images/
│   │   ├── og-preview.png        # 1200×630 social share image
│   │   ├── ball_knowledge_logo.png # Logo used in Navbar
│   │   └── *.webp                # Background images (stadium, VIP box, etc.)
│   └── robots.txt

Architecture Decisions

Offline-First Data Strategy

All critical user state (predictions, profile, chat) is saved to localStorage first. DB sync is opportunistic — if the database is unreachable, the app remains fully functional. This hybrid pattern means:

  • ✅ Works without a DB connection (zero crash)
  • ✅ Fast reads (no DB roundtrip for common actions)
  • ✅ DB syncs when the resolution endpoint is called

Match Status is Real-Time

Match status (UPCOMING/LIVE/COMPLETED) is computed from new Date() vs. the fixture's local_date. All pages use the shared parseLocalDate() utility from src/lib/matchUtils.ts.

AI Grading Fallback Chain

OpenRouter (llama-3.3-70b-instruct)
  → Groq (llama-3.3-70b-specdec)
    → Nvidia NIM (meta/llama-3.1-70b-instruct)
      → Deterministic local tribunal fallback

Security Headers (Production)

All routes serve: X-Frame-Options: SAMEORIGIN, X-Content-Type-Options: nosniff, Strict-Transport-Security, Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy.


User Roles

Role Hot Takes Privileges
FREE 3 max Standard predictions
PREMIUM 5 max Roast styling, user tagging
ADMIN 5 max Bypass kickoff lock (dev/testing)

Roles are stored in localStorage and synced to PostgreSQL on upgrade. Change tier at /pricing.


Deployment (Cloudflare Pages)

  1. Push to GitHub
  2. Connect repo on dash.cloudflare.com
  3. Add environment variables in Cloudflare Pages dashboard settings:
    • DATABASE_URL
    • OPENROUTER_API_KEY (recommended primary)
    • GROQ_API_KEY
    • NVIDIA_API_KEY (optional)
    • NEXT_PUBLIC_SITE_URL (e.g. https://ballknowledge.live)
  4. Deploy. Cloudflare will automatically build and deploy your app.

Self-Hosting (Raspberry Pi / VPS)

See README-raspi.md for the full PM2 + Nginx reverse proxy setup guide.


License

MIT — see LICENSE.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages