Commit Graph

435 Commits

Author SHA1 Message Date
cal
25c533ed3d Merge branch 'main' into ci/fix-action-auth
All checks were successful
Build Docker Image / build (pull_request) Successful in 47s
2026-02-18 19:49:03 +00:00
Cal Corum
ea71371b95 Fix act_runner auth: short-form local actions + full GitHub URLs
All checks were successful
Build Docker Image / build (pull_request) Successful in 46s
DEFAULT_ACTIONS_URL=self requires local actions use short form
(cal/gitea-actions/...) so the runner passes its auth token, and
GitHub actions use full URLs (https://github.com/...) to bypass
local resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 13:32:14 -06:00
cal
36f01a2d61 Merge pull request 'ci: Use Gitea API for tag creation' (#4) from ci/api-tags into main
All checks were successful
Build Docker Image / build (push) Successful in 42s
Reviewed-on: #4
2026-02-17 23:24:50 +00:00
Cal Corum
eff6c1136b ci: Use Gitea API for tag creation to avoid branch protection issues
All checks were successful
Build Docker Image / build (pull_request) Successful in 43s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:23:21 -06:00
cal
d3ffb89e6e Merge pull request 'ci: Switch to CalVer versioning' (#3) from ci/calver into main
Some checks failed
Build Docker Image / build (push) Failing after 43s
Reviewed-on: #3
2026-02-17 23:11:55 +00:00
Cal Corum
6622839ffa ci: Switch to CalVer (YYYY.MM.BUILD) with auto-generated versions
All checks were successful
Build Docker Image / build (pull_request) Successful in 43s
Remove manual semver validation from PR checks. Versions are now
auto-generated on merge to main by counting existing monthly tags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:10:31 -06:00
Cal Corum
b76c8166fa Remove CLAUDE.md from .gitignore
CLAUDE.md should be tracked in version control.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:10:25 -06:00
Cal Corum
e0d0ba59ff Optimize CLAUDE.md from 158 to 43 lines
Remove full router listing, production ops examples, and boilerplate.
Keep commands, architecture, environment table, and key constants.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:10:25 -06:00
cal
b6f1a85a49 Merge pull request 'ci: switch Docker build cache to type=registry' (#2) from ci/registry-cache into main
All checks were successful
Build Docker Image / build (push) Successful in 10m6s
2026-02-11 22:14:27 +00:00
cal
305e1b0ffa ci: switch Docker build cache from type=gha to type=registry
Some checks failed
Build Docker Image / build (pull_request) Failing after 14s
The gha cache backend silently fails on Gitea Actions due to Docker
networking issues between the Buildx builder container and the
act_runner cache server. Registry-based caching stores layers on
Docker Hub, which is more reliable for self-hosted runners.
2026-02-11 22:12:30 +00:00
cal
65c00800d2 Merge pull request 'postgres-migration' (#1) from postgres-migration into main
All checks were successful
Build Docker Image / build (push) Successful in 3m21s
Reviewed-on: #1
2026-02-05 19:43:13 +00:00
Cal Corum
737bde9b94 Add Gitea Actions CI/CD workflow for Docker builds
All checks were successful
Build Docker Image / build (pull_request) Successful in 6m12s
- Semantic version validation on PRs
- Automated Docker image builds and pushes to Docker Hub
- Discord notifications for build status
- Multi-tag strategy: latest, semver, commit hash

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-05 13:35:08 -06:00
Cal Corum
3d4e5280e0 Remove deprecated legacy files and reorganize documentation
- Delete deprecated root main.py (superseded by app/main.py)
- Delete deprecated root db_engine.py (superseded by app/db_engine.py)
- Delete legacy sheets.py (Google Sheets integration, unused)
- Archive db_migrations.py and SQL migrations to .claude/archive/
- Archive POSTGRES_MIGRATION_PLAN.md to .claude/archive/
- Move active documentation to docs/ directory

This cleanup removes ~10,000 lines of deprecated code and organizes
remaining documentation for better maintainability.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-05 13:34:09 -06:00
Cal Corum
2168f85924 Bump version to 1.5.5 2026-02-04 08:48:12 -06:00
Cal Corum
b8a6c6bd2c Fix KeyError: 'human' in gauntlet-9 CARDSETS
Added missing 'human' key to gauntlet-9 cardset configuration.
This was causing 500 errors when players tried to start gauntlet
games because the legal-check endpoint couldn't validate cards.

Error: KeyError: 'human' at app/routers_v2/cards.py:242
when checking CARDSETS[rarity_name]['human']

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-04 08:47:21 -06:00
Cal Corum
40c512c665 Add PostgreSQL compatibility fixes for query ordering
- 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>
2026-02-03 10:39:14 -06:00
Cal Corum
0437eab92a Add missing card templates for PostgreSQL deployment
- Recovered player_card.html and related templates from old server
- Required for card generation endpoints (/players/{id}/battingcard)
- Fixes TemplateNotFound errors in production
2026-02-01 19:18:04 -06:00
Cal Corum
b6743f704b Bump version to 1.5.4 2026-01-31 16:07:06 -06:00
Cal Corum
985a6ed2b0 Add default ORDER BY id to BaseModel.select() for PostgreSQL compatibility
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.
2026-01-31 16:06:44 -06:00
Cal Corum
7574e488d9 Bump version to 1.5.3 2026-01-31 15:56:51 -06:00
Cal Corum
8c039dedf8 Fix DateTimeField defaults for PostgreSQL compatibility
Paperdex and GauntletRun models used int timestamps as defaults which
worked in SQLite but fail in PostgreSQL. Changed to datetime.now.
2026-01-31 15:56:33 -06:00
Cal Corum
ab1a25aabc Bump version to 1.5.2 - PostgreSQL timestamp fixes
Fixed 17 timestamp conversion issues where Discord bot sends
milliseconds but PostgreSQL uses DateTimeField.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 23:02:31 -06:00
Cal Corum
5120963e18 Add .dockerignore
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:47:07 -06:00
Cal Corum
be7212032f Add local utility files to gitignore
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:46:56 -06:00
Cal Corum
af94a78ccf Bump version to 1.5.1
Preparing for bugfix release with PostgreSQL timestamp fixes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:46:10 -06:00
Cal Corum
1f78bd188b Fix missed timestamp issues in stats POST handlers
- 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>
2026-01-30 22:45:15 -06:00
Cal Corum
f4aafa35e7 Fix PostgreSQL timestamp conversion for stats GET filters
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>
2026-01-30 22:41:00 -06:00
Cal Corum
f3b0b90860 Fix PostgreSQL timestamp handling in gauntletruns.py
- 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>
2026-01-30 22:39:45 -06:00
Cal Corum
e1c39cfb17 Fix PostgreSQL timestamp conversion for GET filters
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>
2026-01-30 22:38:06 -06:00
Cal Corum
127c4fca65 Fix PostgreSQL timestamp conversion for POST/PATCH endpoints
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>
2026-01-30 22:37:31 -06:00
Cal Corum
cb89a61196 Fix PostgreSQL upsert column names and CSV null handling
- 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>
2026-01-30 17:28:40 -06:00
Cal Corum
3dce457463 Fix flashback cardset legality and rewards timestamp handling
- 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>
2026-01-30 15:08:21 -06:00
Cal Corum
23bf59e3db Add production deployment config and fix stringified list parsing
- 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>
2026-01-30 14:03:07 -06:00
Cal Corum
b063b73f92 Address documentation gaps from review
- Added Prerequisites section with software/infrastructure requirements
- Added pre-migration steps: stop API, password file creation
- Added PostgreSQL 15+ schema permission grant
- Added post-migration VACUUM ANALYZE step
- Added Troubleshooting section with common errors and solutions
- Added verification queries for debugging
- Added expected record counts table
- Added connection string for external tools
- Expanded checklist with pre/post sections
- Added monitoring guidance
- Clarified CRITICAL warnings about data consistency
2026-01-27 15:27:18 -06:00
Cal Corum
ea5c047b15 Update migration guide with finalized production plan
- 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
2026-01-27 14:03:05 -06:00
Cal Corum
94c8564282 Fix migration order: move gamerewards after player table
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.
2026-01-27 10:41:54 -06:00
Cal Corum
392833a5d9 Add missing GROUP BY to decisions/rest endpoint for PostgreSQL
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.
2026-01-26 22:01:38 -06:00
Cal Corum
92fc101e38 Fix PostgreSQL compatibility for GROUP BY queries and aggregations
- 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
2026-01-26 21:59:25 -06:00
Cal Corum
0cba52cea5 PostgreSQL migration: Complete code preparation phase
- Add db_helpers.py with cross-database upsert functions for SQLite/PostgreSQL
- Replace 12 on_conflict_replace() calls with PostgreSQL-compatible upserts
- Add unique indexes: StratPlay(game, play_num), Decision(game, pitcher)
- Add max_length to Team model fields (abbrev, sname, lname)
- Fix boolean comparison in teams.py (== 0/1 to == False/True)
- Create migrate_to_postgres.py with ID-preserving migration logic
- Create audit_sqlite.py for pre-migration data integrity checks
- Add PROJECT_PLAN.json for migration tracking
- Add .secrets/ to .gitignore for credentials

Audit results: 658,963 records across 29 tables, 2,390 orphaned stats (expected)

Based on Major Domo migration lessons learned (33 issues resolved there)
2026-01-25 23:05:54 -06:00
Cal Corum
fbe8623eb4 Merge branch 'main' into postgres-migration 2026-01-25 22:53:35 -06:00
Cal Corum
7cf507e3c2 Pin numpy<2 for older CPU compatibility
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>
2026-01-07 13:17:07 -06:00
Cal Corum
09924faea5 Normalize Player.franchise to city-agnostic values
- 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>
2026-01-07 12:00:45 -06:00
Cal Corum
bf1601c9a0 Add VERSION file for docker build tracking
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>
2025-11-15 09:24:25 -06:00
Cal Corum
a34e553b25 2005 Live Series Updates 2025-11-08 18:25:08 -06:00
Cal Corum
ad1f28b7df CLAUDE: Add QUICK_START.md with step-by-step testing guide 2025-11-07 14:07:17 -06:00
Cal Corum
cac8e7d126 CLAUDE: Comment out API service - prevents race condition in db_engine.py
- 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
2025-11-07 14:07:13 -06:00
Cal Corum
e9f70b7ed0 CLAUDE: Fix PostgreSQL startup - use local directory instead of volume
- 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
2025-11-07 13:30:37 -06:00
Cal Corum
08460c3884 CLAUDE: Change Adminer port to 8081 to avoid conflict with discord-app 2025-11-07 13:16:02 -06:00
Cal Corum
3e0445c70a CLAUDE: Fix YAML syntax in docker-compose.yml - comment out API service properly 2025-11-07 13:07:48 -06:00
Cal Corum
39a7d59fcd CLAUDE: Add docker-compose.yml and quickstart guide
- 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
2025-11-07 13:07:23 -06:00