Replace branch-push trigger with tag-push trigger (20* pattern). Version is extracted from the git tag itself instead of auto-generated. Docker images are tagged with the CalVer version + floating "production" tag. To release: git tag YYYY.M.BUILD && git push --tags Also updates CLAUDE.md to document the new workflow and removes all next-release branch references (branch retired). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4.2 KiB
Discord Bot v2.0
SBA fantasy league Discord bot. discord.py with async Python, Pydantic models, FastAPI backend.
Commands
- Run:
python bot.py - Test:
python -m pytest --tb=short -q - Test specific:
python -m pytest tests/test_services.py -v
IMPORTANT: Patterns That Prevent Real Bugs
Docker Hub Repository Name
manticorum67/major-domo-discordapp
There is NO DASH between "discord" and "app". Not discord-app, not discordapp-v2.
Git Workflow
NEVER commit directly to main. Always use feature branches.
git checkout -b feature/name origin/main # or fix/name, refactor/name
PRs go to main. CI builds the Docker image and creates a CalVer tag on merge.
Double Emoji in Embeds
EmbedTemplate.success/error/warning/info/loading() auto-add emoji prefixes.
- Do NOT put emoji in the
titleparameter of these methods (causes double emoji) - Use
EmbedTemplate.create_base_embed()when you want custom emoji in titles
Autocomplete Functions
Define autocomplete as standalone functions OUTSIDE the class, not as methods.
- See
commands/players/info.py:20-67for canonical example
Model Requirements
- Database entities require
idfields:Player(id=123, ...),Team(id=456, ...) - Use explicit None checks (
if obj is None:) notif not obj: - Use "Raise or Return" pattern - don't return Optional unless specifically required
New Commands Must Use
from utils.decorators import logged_command
from utils.logging import get_contextual_logger
class MyCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.logger = get_contextual_logger(f'{__name__}.MyCog') # Required
@discord.app_commands.command(name="example")
@logged_command("/example")
async def example(self, interaction, param: str):
# Business logic only - decorator handles logging, timing, errors
Deployment & Troubleshooting
Production
- Host:
ssh akamai→cd container-data/major-domo - Container:
major-domo-discord-app-1 - Image:
manticorum67/major-domo-discordapp(no dash between discord and app) - Health: Process liveness only (no HTTP endpoint)
- CI/CD: Gitea Actions — tag-triggered Docker builds (push a CalVer tag to release)
Release Workflow
- Create feature/fix branches off
main(e.g.,fix/scorebug-bugs) - Open a PR to
mainwhen ready — merging does NOT trigger a build - When ready to release:
git tag YYYY.M.BUILD && git push --tags - CI builds Docker image, tags it with the version +
production, notifies Discord - Deploy the new image to production (see
/deployskill)
- Other services on same host:
sba_db_api,sba_postgres,sba_redis,sba-website-sba-web-1,pd_api
Logs
- Container logs:
ssh akamai "docker logs --since 1h major-domo-discord-app-1" - Log file (in container):
/app/logs/discord_bot_v2.json(JSON structured, rotating, 10MB max) - Host mount:
./logs/discord_bot_v2.json
Key Env Vars
BOT_TOKEN, API_TOKEN, DB_URL, GUILD_ID, LOG_LEVEL, ENVIRONMENT, REDIS_URL (optional)
Common Issues
- Bot not responding → check
docker logs, verifyBOT_TOKENandGUILD_ID - API errors → verify
DB_URLpoints to correct database API andAPI_TOKENmatches - Redis errors are non-fatal (graceful fallback when
REDIS_URLis empty)
Dependencies
Pinning Policy
All dependencies are pinned to exact versions (==). This ensures every Docker build
produces an identical image — a git revert actually rolls back to the previous working state.
requirements.txt— production runtime deps only (used by Dockerfile)requirements-dev.txt— includes-r requirements.txtplus dev/test tools
When installing for local development or running tests:
pip install -r requirements-dev.txt
When upgrading a dependency, update BOTH the == pin and (if applicable) the comment in
the file. Test before committing. Never use >= or ~= constraints.
API Reference
- OpenAPI spec: https://sba.manticorum.com/api/openapi.json (use WebFetch for current endpoints)
Sub-directory Documentation
Each package has its own CLAUDE.md with detailed patterns:
commands/, services/, models/, views/, tasks/, tests/, utils/