Skip to content

KennethCLA/ScoutLens

Repository files navigation

⚽ ScoutLens

A backend-first football data & analytics platform


ScoutLens is a portfolio-level backend project demonstrating Python backend engineering, API-first architecture, PostgreSQL relational modeling, and clean service-layer design.

Table of Contents


Tech Stack

Layer Technology
Language Python 3.11
Framework FastAPI
ORM SQLAlchemy 2.x
Validation Pydantic v2
Database PostgreSQL 15
Migrations Alembic
Testing pytest + httpx
Containers Docker / Docker Compose

Project Structure

ScoutLens/
├── app/
│   ├── main.py                  # App factory, lifespan, router registration
│   ├── database.py              # Engine, session factory, Base, get_db
│   ├── models/                  # SQLAlchemy ORM models
│   │   ├── team.py
│   │   ├── player.py
│   │   ├── match.py
│   │   └── player_match_stat.py
│   ├── schemas/                 # Pydantic v2 schemas (Create / Update / Response)
│   │   ├── team.py
│   │   ├── player.py
│   │   ├── match.py
│   │   └── player_match_stat.py
│   ├── routers/                 # Thin route handlers
│   │   ├── teams.py
│   │   ├── players.py
│   │   ├── matches.py
│   │   └── stats.py
│   └── services/                # Business logic & database queries
│       ├── team_service.py
│       ├── player_service.py
│       ├── match_service.py
│       ├── stat_service.py
│       └── metrics_service.py   # Analytics: per-90s, rating, performance index
├── alembic/                     # Database migration scripts
│   └── versions/
├── tests/                       # pytest suite
│   ├── conftest.py              # Shared fixtures (SQLite in-memory)
│   ├── test_teams.py
│   ├── test_players.py
│   ├── test_matches.py
│   ├── test_stats.py
│   └── test_metrics.py
├── scripts/
│   └── seed.py                  # Demo data loader
├── Dockerfile
├── docker-compose.yml
├── alembic.ini
├── requirements.txt
└── .env.example

Getting Started

Prerequisites

1. Configure environment

cp .env.example .env

2. Start all services

docker compose up --build
Service URL
API http://localhost:8000
Swagger UI http://localhost:8000/docs
ReDoc http://localhost:8000/redoc
PostgreSQL localhost:5432

3. Seed demo data

docker compose exec web python scripts/seed.py

Inserts 3 teams, 6 players, 4 matches, and 12 player match stats.


API Reference

All endpoints are prefixed with /api/v1.

Teams

Method Endpoint Description
GET /api/v1/teams List all teams
GET /api/v1/teams/{id} Get team by ID
POST /api/v1/teams Create a team
PATCH /api/v1/teams/{id} Partial update
DELETE /api/v1/teams/{id} Delete a team

Players

Method Endpoint Description
GET /api/v1/players List all players (?team_id= filter)
GET /api/v1/players/{id} Get player by ID
POST /api/v1/players Create a player
PATCH /api/v1/players/{id} Partial update
DELETE /api/v1/players/{id} Delete a player
GET /api/v1/players/{id}/metrics Analytics metrics

Matches

Method Endpoint Description
GET /api/v1/matches List all matches (?team_id= filter)
GET /api/v1/matches/{id} Get match by ID
POST /api/v1/matches Create a match
PATCH /api/v1/matches/{id} Partial update
DELETE /api/v1/matches/{id} Delete a match

Stats

Method Endpoint Description
GET /api/v1/stats List all player match stats
GET /api/v1/stats/{id} Get stat record by ID
POST /api/v1/stats Create a stat record
PATCH /api/v1/stats/{id} Partial update
DELETE /api/v1/stats/{id} Delete a stat record

Analytics Metrics

GET /api/v1/players/{id}/metrics

Aggregates performance data across all recorded appearances:

Metric Formula
goals_per_90 SUM(goals) / SUM(minutes_played) × 90
assists_per_90 SUM(assists) / SUM(minutes_played) × 90
avg_rating AVG(rating) — rated appearances only
performance_index (g90 × 0.4) + (a90 × 0.3) + (avg_rating / 10 × 0.3)

Example response:

{
  "player_id": 1,
  "goals_per_90": 1.20,
  "assists_per_90": 0.60,
  "avg_rating": 8.50,
  "performance_index": 0.99
}

Data Model

┌──────────┐         ┌──────────┐
│   Team   │◄────────│  Player  │
└──────────┘         └──────────┘
     │                    │
     │  (home/away)        │
     ▼                    ▼
┌──────────┐       ┌──────────────────┐
│  Match   │◄──────│ PlayerMatchStat  │
└──────────┘       └──────────────────┘

Architecture

ScoutLens follows a strict layered architecture:

Request → Router → Service → ORM Model → PostgreSQL
                      ↑
                  Schema (Pydantic)
Layer Responsibility
Routers HTTP routing, input validation, response shaping — no ORM logic
Services All business logic, CRUD, and aggregate queries
Models SQLAlchemy ORM table definitions with indexes
Schemas Pydantic v2 request/response contracts (Create / Update / Response)
Database Engine, session factory, get_db dependency

Key conventions:

  • All Update schemas use fully optional fields (PATCH semantics)
  • Services use model_dump(exclude_unset=True) for partial updates
  • 404s are raised in routers, not services
  • Database sessions injected via Depends(get_db)

Testing

Tests run against an in-memory SQLite database — no Postgres required.

# Install dev dependencies
pip install -r requirements.txt

# Run the full test suite
pytest

# With coverage
pytest --cov=app --cov-report=term-missing

Test structure mirrors the service/router split:

File Coverage
tests/test_teams.py Team CRUD endpoints
tests/test_players.py Player CRUD + team filter
tests/test_matches.py Match CRUD + team filter
tests/test_stats.py Stat CRUD endpoints
tests/test_metrics.py Analytics metric calculations

Database Migrations

ScoutLens uses Alembic for schema versioning.

# Apply all migrations
alembic upgrade head

# Create a new migration after model changes
alembic revision --autogenerate -m "describe the change"

# Downgrade one step
alembic downgrade -1

# View migration history
alembic history --verbose

Note: The DATABASE_URL environment variable must be set before running Alembic commands. See .env.example.


Non-Goals

This project intentionally excludes: frontend, authentication, data scraping, machine learning, payments, and multi-tenancy.

See ROADMAP.md for planned future phases.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors