Development Setup
This guide covers setting up EchoStats for local development with hot-reload for both the API and frontend.
Prerequisites
- Python 3.12+ with uv (fast Python package manager)
- Node.js 22+ with pnpm (enable via
corepack enable) - Docker & Docker Compose (for MongoDB and Redis)
- A Spotify Developer App with redirect URI set to
http://localhost:8000/api/v1/auth/callback
Quick Start
The fastest way to get everything running with hot-reload:
# Clone and configuregit clone https://github.com/spotify-devs/echostats.gitcd echostatscp .env.example .env# Edit .env with your Spotify credentials and secrets
# Start everything with hot-reloadmake devThis uses docker-compose.dev.yml which:
- Exposes MongoDB (27017) and Redis (6379) ports for direct access
- Mounts source code as volumes for live reloading
- Runs the API with
uvicorn --reloadand the web app withpnpm dev - Sets
LOG_LEVEL=debugfor verbose output
Manual Setup (Without Docker Dev Compose)
If you prefer to run services individually:
1. Start Infrastructure
# Start only MongoDB and Redisdocker compose up -d mongodb redis2. API (FastAPI)
cd api
# Install dependenciesuv sync
# Run with hot-reloaduv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000The API will be available at http://localhost:8000 with auto-reload on file changes.
3. Web (Next.js)
cd web
# Install dependenciespnpm install
# Run dev serverpnpm devThe frontend will be available at http://localhost:3000 with hot module replacement.
4. Worker (optional)
cd api
# Run the ARQ background workeruv run arq app.tasks.worker.WorkerSettingsSeed Data
Generate realistic demo data for development without connecting a Spotify account:
cd api && uv run python seed.pyThis creates:
| Data | Count | Details |
|---|---|---|
| 🎤 Artists | 15 | Taylor Swift, Drake, The Weeknd, Ariana Grande, and more |
| 🎵 Tracks | 25 | With full audio features (danceability, energy, valence, etc.) |
| 📜 History | ~2,000 | Plays distributed across 90 days with realistic patterns |
| 📁 Playlists | 5 | Chill Vibes, Workout Bangers, Late Night Drive, etc. |
| 📊 Snapshots | 4 | Analytics for week, month, year, all-time |
| 🔄 Sync Jobs | 6 | Including 1 failed job for realism |
| 📋 API Logs | ~300 | Entries across 30 days with 5% error rate |
| 👤 User | 1 | demo@echostats.local |
After seeding, use the dev-login endpoint to authenticate without Spotify:
curl http://localhost:8000/api/v1/auth/dev-loginRunning Tests
API Tests (pytest)
cd api
# Run all testsuv run pytest -v
# Run with coverageuv run pytest -v --cov=app --cov-report=html
# Run a specific test fileuv run pytest tests/test_health.py -vTests use pytest-asyncio with asyncio_mode = "auto". The CI pipeline runs tests against real MongoDB and Redis services.
Web Tests (vitest)
cd web
# Run testspnpm test
# Run in watch modepnpm test --watchAll Tests
make test # Runs test-api + test-webLinting & Formatting
Python (ruff + mypy)
cd api
# Lintuv run ruff check .
# Auto-fix lint issuesuv run ruff check . --fix
# Type checkinguv run mypy .
# Formatuv run ruff format .TypeScript (biome)
cd web
# Lintpnpm lint
# Formatpnpm formatAll at Once
make lint # Lint API + Webmake format # Format API + WebMakefile Commands
The project Makefile provides shortcuts for common tasks:
| Command | Description |
|---|---|
make dev | Start all services with hot-reload (Docker Compose dev) |
make dev-api | Start API only with hot-reload |
make dev-web | Start Next.js dev server only |
make dev-docs | Start Astro docs dev server |
make build | Build all Docker images |
make test | Run all tests (API + Web) |
make lint | Run all linters (ruff + biome) |
make format | Auto-format all code |
make db-seed | Seed the database with demo data |
make db-shell | Open MongoDB shell |
make docker-up | Start services (production) |
make docker-down | Stop services |
make docker-logs | Tail service logs |
make docker-clean | Remove all containers, volumes, and images |
make clean | Remove build artifacts, caches, and node_modules |
Project Structure
echostats/├── api/ # FastAPI backend│ ├── app/│ │ ├── main.py # FastAPI app entry point│ │ ├── routers/ # API route handlers (14 files)│ │ ├── models/ # Beanie ODM models│ │ ├── services/ # Business logic│ │ └── tasks/ # ARQ worker tasks│ ├── tests/ # pytest test suite│ ├── seed.py # Demo data generator│ ├── Dockerfile # Multi-stage build│ └── pyproject.toml # Python dependencies (uv)├── web/ # Next.js frontend│ ├── src/│ │ ├── app/ # Next.js pages (42+ routes)│ │ ├── components/ # React components│ │ └── lib/ # Utilities and API client│ ├── Dockerfile # Multi-stage build│ └── package.json # Node dependencies (pnpm)├── docs/ # Astro Starlight documentation├── helm/echostats/ # Helm chart for Kubernetes├── docker-compose.yml # Production compose├── docker-compose.dev.yml # Development compose (hot-reload)├── Makefile # Task runner└── .env.example # Environment variable templateCode Style
- Python: ruff for linting and formatting, mypy for type checking
- TypeScript: Biome for linting and formatting
- Commits: Conventional Commits format (
feat:,fix:,docs:, etc.) — used for automated versioning
CI/CD Pipeline
The GitHub Actions CI pipeline runs on every push and PR to main:
- lint-api — ruff check
- lint-web — biome lint
- typecheck-web — TypeScript type checking
- test-api — pytest with coverage (against MongoDB + Redis services)
- build-api — Docker image build verification
- build-web — Next.js production build
On merge to main, the release workflow:
- Creates a semantic version tag based on commit messages
- Builds and pushes Docker images to GHCR (
ghcr.io/spotify-devs/echostats-api,ghcr.io/spotify-devs/echostats-web) - Packages and pushes the Helm chart to
oci://ghcr.io/spotify-devs/charts/echostats - Creates a GitHub Release with changelog