- Add explicit ORDER BY id to all queries for consistent results across SQLite and PostgreSQL
- PostgreSQL does not guarantee row order without ORDER BY, unlike SQLite
- Skip table creation when DATABASE_TYPE=postgresql (production tables already exist)
- Fix datetime handling in notifications (PostgreSQL native datetime vs SQLite timestamp)
- Fix grouped query count() calls that don't work in PostgreSQL
- Update .gitignore to include storage/templates/ directory
This completes the PostgreSQL migration compatibility layer while maintaining
backwards compatibility with SQLite for local development.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Recovered player_card.html and related templates from old server
- Required for card generation endpoints (/players/{id}/battingcard)
- Fixes TemplateNotFound errors in production
PostgreSQL does not guarantee row order without ORDER BY, unlike SQLite
which implicitly returned rows by rowid. This caused bugs where queries
returned results in unexpected order (e.g., get_team_by_owner returning
gauntlet team instead of main team).
Override select() in BaseModel to add default ordering by id. Explicit
.order_by() calls will override this default.
Also mark legacy db_engine.py as deprecated.
Fixed 17 timestamp conversion issues where Discord bot sends
milliseconds but PostgreSQL uses DateTimeField.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix batstats.py and pitstats.py POST handlers to convert timestamps
- Fix Pydantic model defaults from *100000 to *1000 (wrong multiplier)
Found during second-pass audit.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert milliseconds to datetime for created filter in batstats.py
and pitstats.py GET endpoints.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Convert milliseconds to datetime for GET filters (created_after/before, ended_after/before)
- Fix is_active filter to use is_null() instead of comparing to 0
- Fix PATCH to use datetime.now() instead of int timestamps
- Fix POST to convert timestamps and use None for nullable ended field
- Update Pydantic model defaults to None instead of int
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert milliseconds timestamps to datetime for created_after filter
in notifications and created_after/before filters in paperdex.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert milliseconds timestamps from Discord bot to datetime objects
for PostgreSQL DateTimeField columns in notifications, packs, paperdex,
and rewards routers. Also fix rewards GET created_after filter.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix upsert_many() to use column_name for EXCLUDED references
(ForeignKeyField columns end in _id, e.g., batter -> batter_id)
- Add null checks in batting/pitching CSV output for player, team, game
fields to prevent 'NoneType' not subscriptable errors
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 2018 Promos (14) and 2022 Promos (4) to flashback mode legal cardsets
- Convert Unix timestamps to datetime in rewards POST/PATCH for PostgreSQL
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix /legal-check endpoint to handle card_ids passed as stringified list
- Add compose.production.yml for akamai deployment (pd_api container)
- Add migrate_missing_data.py script for filling gaps from initial migration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Updated test results with final migration metrics (549,788 records)
- Documented all tested endpoints with status
- Added complete step-by-step production migration plan
- Included rollback procedures and deployment checklist
- Documented known limitations and connection details
gamerewards has a FK to player (player_id), so it must be migrated
after the player table. Previously this caused the Pablo Sanchez Card
reward (id=9, player_id=9399) to fail with FK violation.
PostgreSQL requires GROUP BY for all non-aggregated columns when using
aggregate functions. Added group_by(pitcher, game) to the StratPlay query
that calculates pitcher innings in the /decisions/rest endpoint.
- Fix NULL handling for FK checks in stratplays.py: use x.field_id instead
of x.field to avoid triggering FK lookups on potentially missing rows
- Cast boolean is_start to integer for SUM() - PostgreSQL cannot sum booleans
- Add missing GROUP BY clause to Decision aggregate query
- Add Case import for boolean-to-integer casting
- Update migration script with boolean/datetime column mappings
- Exclude legacy battingstat/pitchingstat tables from migration
- Add comprehensive POSTGRES_MIGRATION_GUIDE.md documentation
Tested: /plays/batting and /plays/pitching endpoints work with group_by=player
NumPy 2.x requires X86_V2 instruction set (SSE4.2/AVX) which
the production server CPU doesn't support. Pin to numpy 1.x
to avoid RuntimeError on startup.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add SQL migration script to update all franchise values
- Change AI roster queries from Team.lname to Team.sname
- Add FRANCHISE_NORMALIZE helper for bulk imports
- Update St Louis Cardinals hardcoded fix
Enables cross-era player matching for AI rosters (fixes Oakland Athletics issue)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Initial version: 1.5
This file tracks the current version for Docker builds. When building
and pushing new versions, this file will be updated and the commit
will be tagged with the version number.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- db_engine.py calls db.create_tables() at import time
- Multiple gunicorn workers cause duplicate key violations
- Run API locally for better development experience
- Keeps postgres and adminer services only
- Switch from Docker volume to local directory mount to avoid space issues
- Comment out API service (run locally for development)
- Create logs/database directory
- Add postgres_data/ to .gitignore
- Fixes 'No space left on device' error
- PostgreSQL 17 Alpine container with health checks
- Adminer database UI on port 8080
- Persistent volumes for data
- Environment variable support via .env
- Comprehensive quickstart guide with common commands
- Troubleshooting section
- Production considerations
- Update .gitignore to allow base docker-compose.yml
- Documents all environment variables
- Includes SQLite and PostgreSQL configurations
- Provides example configurations for different environments
- Adds security notes and best practices
- Includes migration notes for PostgreSQL transition
- Refactor get_batting_totals() to conditionally build SELECT fields based on group_by parameter
- Refactor get_pitching_totals() with same pattern
- Ensures all non-aggregated SELECT fields are included in GROUP BY clause
- Based on successful Major Domo migration pattern
- Add environment-based PostgreSQL configuration to db_engine.py
- Add table_name to all 30 models (Meta class)
- Update db_migrations.py to auto-select migrator based on DB type
- Add comprehensive PostgreSQL migration plan document