- Set timeout=5 so pool exhaustion surfaces as an error instead of hanging forever
- Set autoconnect=False to require explicit connection acquisition
- Add HTTP middleware in main.py to open/close connections per request
Closes#80
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes#78
Change CharField(max_length=20) to BigIntegerField to match the BIGINT
column created by the migration. Remove the str() workaround in
get_creator_by_discord_id() that was compensating for the type mismatch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After removing db.close() calls, 22 finally: blocks were left empty
(12 in custom_commands.py, 10 in help_commands.py), causing
IndentationError at import time. Removed the finally: clause entirely
since connection lifecycle is now handled by the middleware.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Match the discord bot's CI pattern — trigger on CalVer tag push
instead of branch push/PR. Removes auto-CalVer generation and
simplifies to a single build step.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sp.on_first/on_second/on_third don't exist — the actual columns are
on_first_id/on_second_id/on_third_id. This caused failures when
updating season pitching stats after games.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After handle_db_errors no longer catches HTTPException, GET /plays/999999999
correctly returns 404 instead of 500. Update the assertion and docstring
to reflect the fixed behavior.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The decorator was catching all exceptions including intentional
HTTPException (401, 404, etc.) and re-wrapping them as 500 "Database
error". This masked auth failures and other deliberate HTTP errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The MAX_LIMIT/DEFAULT_LIMIT caps added in 16f3f8d are too restrictive
for the /players endpoint — bot and website consumers need full player
lists without pagination. Reverts limit param to Optional[int] with no
ceiling while keeping caps on all other endpoints.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Capture total_count before .limit() so the response count reflects
all matching rows, not just the capped page size. Resolves#100.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add MAX_LIMIT=500 cap across all list endpoints, empty string
stripping middleware, and limit/offset to /transactions. Resolves#98.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds schema_versions table and migrations.py runner to prevent
double-application and missed migrations across dev/prod environments.
- migrations/2026-03-27_add_schema_versions_table.sql: creates tracking table
- migrations.py: applies pending .sql files in sorted order, records each in schema_versions
- .gitignore: untrack migrations.py (was incorrectly ignored as legacy root file)
First run on an existing DB will apply all migrations (safe — all use IF NOT EXISTS).
Closes#81
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add DISCORD_WEBHOOK_URL to docker-compose.yml api service environment block
- Add empty placeholder entry in .env for discoverability
- Move DISCORD_WEBHOOK_URL constant to the env-var constants section at top of dependencies.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace inline webhook URL+token with DISCORD_WEBHOOK_URL env var.
Logs a warning and returns False gracefully if the var is unset.
The exposed webhook token should be rotated in Discord.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Raise RuntimeError on startup if POSTGRES_PASSWORD env var is not set,
instead of silently falling back to a known password in source code.
Closes #C2 from postgres migration review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Closes#65
`PitchingStat.combined_season()` was referenced in the `get_pitstats`
handler but never defined, causing a 500 on `s_type=combined/total/all`.
Added `combined_season` as a `@staticmethod` matching the pattern of
`BattingStat.combined_season` — returns all rows for the given season
with no week filter (both regular and postseason).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The three skipped tests in TestPlayerServiceCache required caching
in get_players() (read-through cache) and cache propagation through
the cls() pattern in write methods — neither is implemented and the
architecture does not support it without significant refactoring.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Guard bulk ID queries against empty lists to prevent PostgreSQL
syntax error (WHERE id IN ()) when batch POST endpoints receive
empty request bodies.
Affected endpoints:
- POST /api/v3/transactions
- POST /api/v3/results
- POST /api/v3/schedules
- POST /api/v3/battingstats
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace per-row Team/Player lookups with bulk IN-list queries before
the validation loop in post_transactions, post_results, post_schedules,
and post_batstats. A 50-move batch now uses 2 queries instead of 150.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>