Repo: https://github.com/timothyfroehlich/DisPinMap
A Discord bot that monitors pinballmap.com for pinball machine changes and posts updates to Discord channels. Deployed on GCP Cloud Run with Terraform.
Read the relevant CLAUDE.md before working in any directory:
| Directory | Scope |
|---|---|
src/CLAUDE.md |
Core application: models, API, database, commands, notifications |
tests/CLAUDE.md |
Test framework, mock patterns, fixtures, test organization |
terraform/CLAUDE.md |
Infrastructure as Code, GCP resources |
alembic/CLAUDE.md |
Database migrations, schema changes |
scripts/CLAUDE.md |
Utility scripts, validation tools |
docs/CLAUDE.md |
Documentation standards |
docs/issues/CLAUDE.md |
Issue tracking and bug documentation |
Discord User
│
▼
CommandHandler (src/cogs/command_handler.py)
│ validates args → calls Database → triggers Notifier
▼
Database (src/database.py) ← SQLAlchemy ORM, SQLite
│ CRUD for channels, targets, seen submissions
▼
Runner (src/cogs/runner.py) ← background task loop (1-min interval)
│ polls active channels → fetches API → filters new → notifies
▼
Notifier (src/notifier.py) ← formats and sends Discord messages
│ uses Messages (src/messages.py) for templates
▼
API (src/api.py) ← pinballmap.com + geocoding
rate-limited HTTP requests
Core flow: User adds a monitoring target via !add command. The Runner's
background loop polls the PinballMap API on each channel's configured interval,
filters out already-seen submissions via the database, and sends new ones to the
Discord channel through the Notifier.
Key models (src/models.py): ChannelConfig (per-channel settings),
MonitoringTarget (what to monitor), SeenSubmission (deduplication).
Python virtual environment is in venv/ (not .venv).
# Setup (if venv/ doesn't exist)
python -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -e .[dev]
# Activate (every session)
source venv/bin/activateRuff is the only Python quality tool. We do not use mypy, black, flake8, or isort.
source venv/bin/activate
ruff format . # format
ruff check --fix . # lint + auto-fix
pytest tests/ --ignore=tests/simulation -v # testPre-commit hooks enforce: trailing whitespace, EOF, YAML, ruff, prettier (markdown/YAML), actionlint.
Always run pre-commit before committing:
pre-commit run --all-files- Never commit directly to main. All work in feature branches.
- Branch naming:
feature/descriptionorfix/description. - All changes require PR review. Branch protection requires passing CI.
- Commit attribution for AI agents:
git commit --author="Claude Code <claude-code@anthropic.com>" -m "$(cat <<'EOF'
commit message here
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <claude-code@anthropic.com>
EOF
)"Never modify git config. Use --author flag instead.
Tests follow a pyramid: unit → integration → simulation.
pytest tests/ --ignore=tests/simulation -v # standard run
pytest tests/unit/ -v # unit only
pytest tests/integration/ -v # integration only
pytest -n auto # parallel execution
pytest --cov=src --cov-report=html # with coverageKey rules:
- All mocks must use spec-based factories from
tests/utils/mock_factories.py. Never use rawMock()orMagicMock()without specs. - Each test worker gets an isolated SQLite database.
- API mocking uses
api_mockerfixture with JSON fixtures intests/fixtures/api_responses/. - See
tests/CLAUDE.mdfor full testing guide.
When presented with a production bug:
- Add a failing test that reproduces the bug
- Only fix the bug once the test fails
- Verify the fix makes the test pass
source venv/bin/activate
python scripts/download_production_db.py # one-time: get prod data
python local_dev.py # start local dev session- Console interface simulates Discord (
!add,!list,!check,!help) - Dot commands for control (
.quit,.health,.status,.trigger) - File watcher:
echo "!list" >> commands.txtfrom another terminal - Logs:
tail -f logs/bot.log
gcloud run services logs read dispinmap-bot --region=us-central1 --limit=50- GCP, Docker, Terraform already installed and authenticated
- Environment variables and secrets already configured
- Working directory is project root unless specified
| Audience | File |
|---|---|
| Users | README.md, USER_DOCUMENTATION.md |
| Developers | docs/LOCAL_DEVELOPMENT.md, docs/DATABASE.md |
| AI Agents | This file + directory-specific CLAUDE.md files |
| Historical context | project-lessons.md |
- Never use
sys.path.appendfor imports - Never use
--no-verifyon git commands unless explicitly asked - Don't use GitHub issue labels
- When solving tricky problems, update
project-lessons.mdwith new lessons