This is a django site that lists cheaters in CS2 on the site.
The project is completely hand-coded (README.md and fixes to make it work in 2026 do not count)
- Python 3.10 (production runs 3.10.12, see
Dockerfile/runtime.txt) - uv (or plain
pip) - Redis, only for background jobs (Celery)
requirements.txt is the real dependency list. pyproject.toml and uv.lock are
out of date, so don't use uv sync.
uv venv --python 3.10 .venv
grep -v '^psycopg2==' requirements.txt | uv pip install --python .venv/bin/python -r -psycopg2 is skipped because it builds from source and needs Postgres headers
(pg_config). psycopg2-binary provides the same module, and locally the app uses
SQLite anyway. To install the list unchanged, run brew install libpq first.
Activate the environment:
source .venv/bin/activate # bash / zsh
source .venv/bin/activate.fish # fishSettings are read from .env in the project root (it's in .gitignore). Every
variable below without a default must be present or Django won't start
(ImproperlyConfigured: Set the X environment variable). Many only need a
placeholder locally.
Template for local development:
DEBUG=True
SECRET_KEY=
SECRET_KEYS=
STEAM_WEB_API_KEY=
DONATELLO_API_KEY=changeme
DONATELLO_GOAL_URL=https://donatello.to/
DONATELLO_GOAL_ID=changeme
EMAIL_CONFIRMATION_ENABLED=False
SENDGRID_API_KEY=
EMAIL_HOST=smtp.sendgrid.net
EMAIL_HOST_USER=dev@example.com
EMAIL_HOST_PASSWORD=changeme
EMAIL_PORT=587
EMAIL_SUBJECT_PREFIX=[ReportCheats dev]
EMAIL_USE_TLS=True
CELERY_RESULT_BACKEND=django-db
CELERY_BEAT_SCHEDULER=django_celery_beat.schedulers:DatabaseSchedulerGenerate values for SECRET_KEY and SECRET_KEYS with:
python -c 'import secrets; print(secrets.token_urlsafe(50))'| Variable | Needs a real value locally? | What it's for |
|---|---|---|
DEBUG |
yes | True locally, False in production |
SECRET_KEY |
yes | Django secret key |
SECRET_KEYS |
yes | Comma-separated list. The first key signs email-confirmation links and is the X-Report-Key header for /approve/, /deny/, /unsure/ |
STEAM_WEB_API_KEY |
yes | Steam profile lookups on the home and player pages. Get one at https://steamcommunity.com/dev/apikey. With a placeholder, the home page returns 503 |
DONATELLO_API_KEY |
no | Checked against the X-Key header on /postdonate/ (Donatello donation callback). Key: https://donatello.to/panel/doc-api |
DONATELLO_GOAL_URL, DONATELLO_GOAL_ID |
no | Goal-widget link and the ID inside it (https://donatello.to/widget/<ID>/token/<TOKEN>). Currently unused |
EMAIL_CONFIRMATION_ENABLED |
no | Default False. When True, new users must confirm their email via SendGrid before using the site |
SENDGRID_API_KEY |
no | Only used when EMAIL_CONFIRMATION_ENABLED=True |
EMAIL_HOST, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, EMAIL_PORT, EMAIL_SUBJECT_PREFIX, EMAIL_USE_TLS |
no | SMTP settings. EMAIL_HOST_USER is the sender address shown on the confirm page |
CELERY_RESULT_BACKEND |
no | django-db stores task results in the database |
CELERY_BEAT_SCHEDULER |
no | django_celery_beat.schedulers:DatabaseScheduler |
CELERY_RESULT_EXTENDED, CELERY_TASK_TRACK_STARTED |
no | Optional, default True |
CELERY_WORKER_PREFETCH_MULTIPLIER |
no | Optional, default 1 |
Set IS_PRODUCTION=True to switch to Postgres, S3 media storage and secure cookies.
These are then also required:
| Variable | What it's for |
|---|---|
ALLOWED_HOSTS |
Extra hostnames, comma-separated (added to the built-in list) |
DB_URL |
Postgres connection URL |
CELERY_BROKER_URL |
Redis URL (locally it's always redis://localhost:6379/0) |
AWS_S3_ACCESS_KEY_ID, AWS_S3_SECRET_ACCESS_KEY |
Backblaze B2 bucket reportcheats-storage for uploaded media |
Locally the app uses db.sqlite3 (committed, with dev data). Bring it up to date
and create an admin:
python manage.py migrate
python manage.py createsuperuser # asks for username, email, passwordpython manage.py runserver- Site: http://127.0.0.1:8000/
- Admin: http://127.0.0.1:8000/admin/
- Login / register:
/user/login/,/user/register/
Celery runs a task every minute that marks users as verified once their donation
is found, and sends confirmation emails when EMAIL_CONFIRMATION_ENABLED=True.
It needs Redis on localhost:6379:
docker run -d --name redis -p 6379:6379 redis # or: brew install redis && brew services start redis
celery -A project worker -l info # in a second terminal
celery -A project beat -l info # in a third terminalThe site works without them.
Production runs on Railway with gunicorn project.wsgi (see Procfile and
Dockerfile), with IS_PRODUCTION=True and the production variables above.
Static files are served by WhiteNoise from staticfiles/.
| Symptom | Cause / fix |
|---|---|
ImproperlyConfigured: Set the X environment variable |
X is missing from .env. Add it (a placeholder is fine unless the table says otherwise) |
| Home page returns 503 | STEAM_WEB_API_KEY is missing or invalid |
| Player search shows "Steam is limiting searches right now" | Steam rate-limits community search per IP (HTTP 429). Wait a minute |
pg_config executable not found during install |
Skip psycopg2 as in Setup, or brew install libpq |
