Your Club. Every Number. A personalized football intelligence platform. Dive deep into 16 seasons of top-flight statistics, simulate World Cup predictions, and chat with an AI analyst grounded strictly in real database records.
BallerZ HQ is a full-stack football analytics platform covering Europe's top five leagues from 2010-11 to 2025-26. It combines a historical match database, computed league standings, player statistics, and an AI-powered club analyst — all running at zero cost on free-tier infrastructure.
The platform is designed around personalisation: you pick a club at onboarding, and the entire experience — dashboard stats, AI context, form tracking — reorients around that club. The AI analyst (Club IQ) is grounded in real data from the database and will only discuss facts it can verify, never hallucinating stats.
Built as a data-engineering and full-stack portfolio project to demonstrate end-to-end skills: data pipelines, SQL schema design, REST API architecture, auth flows, RAG-based AI, and responsive frontend development.
| Dataset | Count | Source |
|---|---|---|
| Matches | 28,892 | football-data.co.uk CSVs |
| Player stats | 25,257 | FBref via soccerdata |
| Standings | 1,562 rows | Computed in-house from match results |
| Clubs | 186 | Auto-created during ingestion |
| Leagues | 5 | Premier League, La Liga, Serie A, Bundesliga, Ligue 1 |
| Seasons | 16 | 2010-11 to 2025-26 |
Full per-match stats: scores, half-time scores, shots, shots on target, fouls, corners, yellow/red cards, referee.
| Layer | Technology | Hosted on | Cost |
|---|---|---|---|
| Frontend | Next.js 14 + TypeScript + Tailwind | Vercel | $0 |
| Backend | FastAPI (Python 3.13) | Render | $0 |
| Database | Supabase (PostgreSQL 17 + Auth + RLS) | Supabase | $0 |
| AI / LLM | Groq (LLaMA 3.3 70B) | Groq Cloud | $0 |
| Data | football-data.co.uk + FBref CSVs | Local ingest | $0 |
Total runtime cost: $0/month. No paid APIs. No subscriptions.
- Match Browser — every result since 2010-11 with full per-match detail. Filter by league, season, or club.
- League Standings — complete tables for every season across all five leagues, computed from real match results.
- Head-to-Head — select any two clubs and see their full historical league record with rivalry breakdown.
- Club Deep-Dive — season-by-season form, goals, cards and fouls for any club in the dataset.
- Club IQ — AI analyst grounded in the match corpus. Analyst mode (data-driven) or Hype mode (fan energy). Only talks about your tracked club using real numbers.
- Personalised Dashboard — pick your club at onboarding; the entire platform reorients around it with stats, form, recent matches, and season comparison.
- Advanced AI analysis modes
- Bookmaker odds overlays
- Enhanced player scouting views
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Frontend │───>│ Backend │───>│ Supabase │
│ Next.js │ │ FastAPI │ │ PostgreSQL │
│ (Vercel) │ │ (Render) │ │ + Auth │
└────────────┘ └────────────┘ └────────────┘
│
v
┌────────────┐
│ Groq │
│ LLaMA 3.3 │
└────────────┘
- Frontend handles auth (Supabase JS client), routing, and renders all dashboards and data pages.
- Backend is a FastAPI service exposing read endpoints for matches/standings/H2H/club stats/players, plus the RAG chat endpoint that fuses Groq with database context.
- Supabase stores all domain data with Row Level Security on user-scoped tables. Two clients:
anonfor public reads,service_rolefor auth-gated operations. - Groq powers Club IQ with LLaMA 3.3 70B (free tier, ~280 tokens/sec).
- Node.js 18+
- Python 3.10+
- Supabase project (free tier)
- Groq API key (free at console.groq.com)
-- In your Supabase SQL editor:
-- 1) Run database/schema.sql (creates all tables, RLS policies, and functions)
-- 2) Optionally run database/seed.sql for starter club datacd backend
python -m venv venv
source venv/bin/activate # macOS / Linux
venv\Scripts\activate # Windows
pip install -r requirements.txt
cp .env.example .env # fill in SUPABASE_URL, SUPABASE_KEY, SUPABASE_ANON_KEY, GROQ_API_KEY
uvicorn main:app --reload --port 8001cd frontend
npm install
cp .env.example .env.local # fill in NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, NEXT_PUBLIC_API_URL
npm run dev # http://localhost:3000Download CSV files from football-data.co.uk into backend/data/matches/, then:
export INGEST_TOKEN=any-long-random-string
# add the same INGEST_TOKEN to backend/.env
curl -X POST http://localhost:8001/api/data/ingest/all \
-H "X-Ingest-Token: $INGEST_TOKEN"This loads all matches, computes standings, and ingests player stats. Takes ~2 minutes.
ballerz-hq/
├── frontend/ Next.js 14 (App Router)
│ └── src/
│ ├── app/ Pages: landing, login, signup, onboarding,
│ │ dashboard, matches, standings, head-to-head,
│ │ clubs, players, premium
│ ├── components/ Sidebar, AnalystPanel, CustomCursor,
│ │ InteractiveParticles, FormChart, Skeleton, etc.
│ └── lib/ Supabase client, utilities, club color mappings
├── backend/ FastAPI service
│ ├── app/
│ │ ├── api/ matches, players, chat, data (ingest)
│ │ ├── ai/ Chatbot (RAG: Groq + OpenAI fallback + template)
│ │ └── services/ CSV ingestion, standings computation, rate limiting
│ └── scripts/ Download helpers for match/player CSVs
├── database/
│ ├── schema.sql Full Supabase schema (8 tables, 3 RPC functions, RLS)
│ └── seed.sql Starter club data for development
└── README.md
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/matches |
Browse matches — filter by league, season, club_id |
| GET | /api/matches/stats?match_id= |
Full stats for a single match |
| GET | /api/matches/standings?league=&season= |
League table for a season |
| GET | /api/matches/standings/seasons |
Available league+season pairs |
| GET | /api/matches/head-to-head?club_a_id=&club_b_id= |
H2H history |
| GET | /api/matches/clubs |
All clubs (optional league filter) |
| GET | /api/matches/clubs/{id}/season-stats |
Aggregated season stats |
| GET | /api/matches/clubs/{id}/goals-history |
Goals for/against per season |
| GET | /api/players |
Browse player stats — filter by league, season, club_id |
| GET | /api/players/top |
Top N players by stat |
| GET | /api/players/seasons |
Available player data league+season pairs |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/chat |
RAG chat — { message, mode, user_id } |
| POST | /api/chat/season-story |
1-2 sentence season narrative |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/data/ingest/all |
Full pipeline: matches + standings + players |
| POST | /api/data/ingest/matches |
Matches only |
| POST | /api/data/ingest/players |
Players only |
- Row Level Security on
user_preferencesandchat_messages(user-scoped read/write) - Dual Supabase clients:
anonkey for public data reads,service_rolefor auth-gated operations - Ingest token gate on all
/api/data/ingest/*endpoints - Rate limiting on
/api/chat(30 messages/hour per user) - CORS allowlisted to
FRONTEND_URL
- Phase A — Data architecture: CSV ingestion, match database, standings computation
- Phase B — Frontend overhaul: dashboard, browse pages, Club IQ, player stats, design system
- Phase C — Deployment: Vercel + Render + production config
- Phase D — Live season updates, gamification features
MIT
Built by Rishi