Skip to main content

Local development

Set up all three services on one machine, backed by containers for Postgres, Redis and RabbitMQ. None of the test suites needs those containers or ESPN; you need them only to run the services.

Prerequisites
ToolVersionUsed by
Gitanyall
Docker with Compose v2any recentthe dependency stack in dev/compose.yaml
Python3.11. On 3.13 or later the pinned pydantic-core and psycopg2-binary fail to build.core
Node20 for the worker; 22.12 or later for the web UI (its jsdom needs 22.22.2 or later)worker, web UI
npmthe version bundled with Nodeworker, web UI

uv can install Python 3.11 next to your system Python (uv python install 3.11). nvm or fnm can switch Node versions per repo.

1. Clone the repositories side by side​

Keep all five checkouts in one folder. The paths on these pages assume this layout, and so does the docs site's local build.

mkdir fantasy && cd fantasy
for repo in fantasy-project fantasy-core-pipeline fantasy-browser-worker fantasy-web-ui fantasy-infra; do
git clone "https://github.com/cvillarr23/$repo.git"
done

2. Start Postgres, Redis and RabbitMQ​

docker compose -f fantasy-project/dev/compose.yaml up -d --wait
ServiceAddressCredentials
Postgres 16127.0.0.1:5432, database fantasy_footballbot_admin / fantasy-local-only
Redis 7127.0.0.1:6379none
RabbitMQ 3127.0.0.1:5672; management UI at http://127.0.0.1:15672fantasy / fantasy-local-only

RabbitMQ loads dev/rabbitmq/definitions.json at startup. That file declares the queues core publishes to, because core only checks that lineup_updates, waiver_actions, draft_targets and job_runs exist; it doesn't create them. The definitions mirror the broker ConfigMap in fantasy-infra.

The ports bind to 127.0.0.1 only, and the passwords are for local use. To start over with empty data, run docker compose -f fantasy-project/dev/compose.yaml down -v.

3. Load the shared environment​

fantasy-project/dev/local.env points every service at the containers and turns on dry run for every bot. Load it in each terminal you run a service from:

set -a; . fantasy-project/dev/local.env; set +a

Don't commit real values to it. Put your league IDs and ESPN cookies in your shell or in a copy outside the repository. Configuration describes every variable.

4. Install and test each repository​

cd fantasy-core-pipeline
python3.11 -m venv venv # or: uv venv -p 3.11 venv
source venv/bin/activate
pip install -r requirements.txt
ToRun
Run the tests (blocking in CI)DB_PASSWORD=test pytest tests/
Also run the Postgres-backed testsAdd ACTIVITY_TEST_DSN="host=127.0.0.1 port=5432 dbname=postgres user=bot_admin password=fantasy-local-only". Point it at postgres, not fantasy_football, so the tests don't touch your data.
Format and type-check (advisory in CI)black --check . and mypy src/
Start the APIuvicorn src.api.main:app --host 127.0.0.1 --port 8000. It runs the schema migrations on startup.
Run a jobpython -m <module>, such as python -m src.ingestion.sync_players --force. See First run.

The tests mock Postgres, Redis and RabbitMQ.

5. Verify​

With the API, worker and dev server running:

CheckExpect
curl http://127.0.0.1:8000/v1/health{"status":"healthy","database":"connected","broker":"connected"}
curl http://localhost:5173/v1/healthThe same, through the UI's proxy
Worker logReady to consume target queue for each queue, then Standing by...

Troubleshooting​

SymptomFix
pip install fails building pydantic-core or psycopg2-binaryYou're on Python 3.13 or later. Recreate the venv with 3.11.
Worker logs fantasy-broker.databases.svc.cluster.localAMQP_URL isn't set, so the worker fell back to the cluster default. Load local.env.
Core logs vhost not foundThe URL ends in / or //. End it with /%2f.
A job fails publishing with NOT_FOUND - no queueRabbitMQ started without the definitions. Run docker compose -f fantasy-project/dev/compose.yaml down -v and start it again.
A lineup, waiver or draft action in the UI shows "Session expired"The API answered 401 because TRIGGER_API_KEY differs between the API's shell and the dev server's. With no key on the API, it answers 500 instead.
UI tests fail to startNode is older than 22.22.2.