From 05699744545d604cb373f6245f59119c1502990a Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Mon, 23 Mar 2026 08:53:58 -0500 Subject: [PATCH] feat: evolution/refractor schema migration (generated from dev) Idempotent PostgreSQL migration extracted directly from paperdynasty_dev on 2026-03-23. Replaces PR #84 which had schema drift. Creates evolution_track, evolution_card_state, evolution_tier_boost, evolution_cosmetic, batting_season_stats, pitching_season_stats. Adds card.variant, battingcard.image_url, pitchingcard.image_url. All DDL uses CREATE TABLE IF NOT EXISTS and ADD COLUMN IF NOT EXISTS. Wrapped in a single transaction. Co-Authored-By: Claude Sonnet 4.6 --- ...6-03-23_add_evolution_refractor_schema.sql | 207 ++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 migrations/2026-03-23_add_evolution_refractor_schema.sql diff --git a/migrations/2026-03-23_add_evolution_refractor_schema.sql b/migrations/2026-03-23_add_evolution_refractor_schema.sql new file mode 100644 index 0000000..0c79f97 --- /dev/null +++ b/migrations/2026-03-23_add_evolution_refractor_schema.sql @@ -0,0 +1,207 @@ +-- Migration: evolution/refractor schema +-- Generated from actual dev schema (paperdynasty_dev) on 2026-03-23 +-- +-- Creates: +-- - evolution_track +-- - evolution_card_state +-- - evolution_tier_boost +-- - evolution_cosmetic +-- - batting_season_stats +-- - pitching_season_stats +-- Adds columns: +-- - card.variant (INTEGER NULL) +-- - battingcard.image_url (VARCHAR(500) NULL) +-- - pitchingcard.image_url (VARCHAR(500) NULL) +-- +-- All statements are idempotent (IF NOT EXISTS / ADD COLUMN IF NOT EXISTS). +-- Run order respects FK dependencies: evolution_track before child tables, +-- season_stats after player and team exist. + +BEGIN; + +-- --------------------------------------------------------------------------- +-- evolution_track +-- Three rows expected: Batter, SP, RP (card_type is UNIQUE) +-- --------------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS evolution_track ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + card_type VARCHAR(50) NOT NULL, + formula VARCHAR(255) NOT NULL, + t1_threshold INTEGER NOT NULL, + t2_threshold INTEGER NOT NULL, + t3_threshold INTEGER NOT NULL, + t4_threshold INTEGER NOT NULL +); + +CREATE UNIQUE INDEX IF NOT EXISTS evolution_track_name_key + ON evolution_track (name); + +-- --------------------------------------------------------------------------- +-- evolution_card_state +-- One row per (player_id, team_id) — tracks tier progression for a roster slot +-- --------------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS evolution_card_state ( + id SERIAL PRIMARY KEY, + player_id INTEGER NOT NULL, + team_id INTEGER NOT NULL, + track_id INTEGER NOT NULL, + current_tier INTEGER NOT NULL DEFAULT 0, + current_value DOUBLE PRECISION NOT NULL DEFAULT 0.0, + fully_evolved BOOLEAN NOT NULL DEFAULT false, + last_evaluated_at TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT evolution_card_state_player_id_fkey + FOREIGN KEY (player_id) REFERENCES player(player_id) ON DELETE CASCADE, + CONSTRAINT evolution_card_state_team_id_fkey + FOREIGN KEY (team_id) REFERENCES team(id) ON DELETE CASCADE, + CONSTRAINT evolution_card_state_track_id_fkey + FOREIGN KEY (track_id) REFERENCES evolution_track(id) ON DELETE CASCADE +); + +CREATE UNIQUE INDEX IF NOT EXISTS evolution_card_state_player_team_uniq + ON evolution_card_state (player_id, team_id); + +-- --------------------------------------------------------------------------- +-- evolution_tier_boost +-- Defines per-tier stat boosts for each track +-- --------------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS evolution_tier_boost ( + id SERIAL PRIMARY KEY, + track_id INTEGER NOT NULL, + tier INTEGER NOT NULL, + boost_type VARCHAR(50) NOT NULL, + boost_target VARCHAR(50) NOT NULL, + boost_value DOUBLE PRECISION NOT NULL DEFAULT 0.0, + CONSTRAINT evolution_tier_boost_track_id_fkey + FOREIGN KEY (track_id) REFERENCES evolution_track(id) ON DELETE CASCADE +); + +CREATE UNIQUE INDEX IF NOT EXISTS evolution_tier_boost_track_tier_type_target_uniq + ON evolution_tier_boost (track_id, tier, boost_type, boost_target); + +-- --------------------------------------------------------------------------- +-- evolution_cosmetic +-- Cosmetic unlocks tied to tier thresholds; standalone (no FK to card_state) +-- --------------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS evolution_cosmetic ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + tier_required INTEGER NOT NULL DEFAULT 0, + cosmetic_type VARCHAR(50) NOT NULL, + css_class VARCHAR(255), + asset_url VARCHAR(500) +); + +CREATE UNIQUE INDEX IF NOT EXISTS evolution_cosmetic_name_key + ON evolution_cosmetic (name); + +-- --------------------------------------------------------------------------- +-- batting_season_stats +-- Accumulates in-season batting stats per player per team per season. +-- last_game_id nullable FK to stratgame; SET NULL on delete. +-- --------------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS batting_season_stats ( + id SERIAL PRIMARY KEY, + player_id INTEGER NOT NULL, + team_id INTEGER NOT NULL, + season INTEGER NOT NULL, + games INTEGER NOT NULL DEFAULT 0, + pa INTEGER NOT NULL DEFAULT 0, + ab INTEGER NOT NULL DEFAULT 0, + hits INTEGER NOT NULL DEFAULT 0, + doubles INTEGER NOT NULL DEFAULT 0, + triples INTEGER NOT NULL DEFAULT 0, + hr INTEGER NOT NULL DEFAULT 0, + rbi INTEGER NOT NULL DEFAULT 0, + runs INTEGER NOT NULL DEFAULT 0, + bb INTEGER NOT NULL DEFAULT 0, + strikeouts INTEGER NOT NULL DEFAULT 0, + hbp INTEGER NOT NULL DEFAULT 0, + sac INTEGER NOT NULL DEFAULT 0, + ibb INTEGER NOT NULL DEFAULT 0, + gidp INTEGER NOT NULL DEFAULT 0, + sb INTEGER NOT NULL DEFAULT 0, + cs INTEGER NOT NULL DEFAULT 0, + last_game_id INTEGER, + last_updated_at TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT batting_season_stats_player_id_fkey + FOREIGN KEY (player_id) REFERENCES player(player_id) ON DELETE CASCADE, + CONSTRAINT batting_season_stats_team_id_fkey + FOREIGN KEY (team_id) REFERENCES team(id) ON DELETE CASCADE, + CONSTRAINT batting_season_stats_last_game_id_fkey + FOREIGN KEY (last_game_id) REFERENCES stratgame(id) ON DELETE SET NULL +); + +CREATE UNIQUE INDEX IF NOT EXISTS batting_season_stats_player_team_season_uniq + ON batting_season_stats (player_id, team_id, season); + +CREATE INDEX IF NOT EXISTS batting_season_stats_player_season_idx + ON batting_season_stats (player_id, season); + +CREATE INDEX IF NOT EXISTS batting_season_stats_team_season_idx + ON batting_season_stats (team_id, season); + +-- --------------------------------------------------------------------------- +-- pitching_season_stats +-- Accumulates in-season pitching stats per player per team per season. +-- last_game_id nullable FK to stratgame; SET NULL on delete. +-- --------------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS pitching_season_stats ( + id SERIAL PRIMARY KEY, + player_id INTEGER NOT NULL, + team_id INTEGER NOT NULL, + season INTEGER NOT NULL, + games INTEGER NOT NULL DEFAULT 0, + games_started INTEGER NOT NULL DEFAULT 0, + outs INTEGER NOT NULL DEFAULT 0, + strikeouts INTEGER NOT NULL DEFAULT 0, + bb INTEGER NOT NULL DEFAULT 0, + hits_allowed INTEGER NOT NULL DEFAULT 0, + runs_allowed INTEGER NOT NULL DEFAULT 0, + earned_runs INTEGER NOT NULL DEFAULT 0, + hr_allowed INTEGER NOT NULL DEFAULT 0, + hbp INTEGER NOT NULL DEFAULT 0, + wild_pitches INTEGER NOT NULL DEFAULT 0, + balks INTEGER NOT NULL DEFAULT 0, + wins INTEGER NOT NULL DEFAULT 0, + losses INTEGER NOT NULL DEFAULT 0, + holds INTEGER NOT NULL DEFAULT 0, + saves INTEGER NOT NULL DEFAULT 0, + blown_saves INTEGER NOT NULL DEFAULT 0, + last_game_id INTEGER, + last_updated_at TIMESTAMP WITHOUT TIME ZONE, + CONSTRAINT pitching_season_stats_player_id_fkey + FOREIGN KEY (player_id) REFERENCES player(player_id) ON DELETE CASCADE, + CONSTRAINT pitching_season_stats_team_id_fkey + FOREIGN KEY (team_id) REFERENCES team(id) ON DELETE CASCADE, + CONSTRAINT pitching_season_stats_last_game_id_fkey + FOREIGN KEY (last_game_id) REFERENCES stratgame(id) ON DELETE SET NULL +); + +CREATE UNIQUE INDEX IF NOT EXISTS pitching_season_stats_player_team_season_uniq + ON pitching_season_stats (player_id, team_id, season); + +CREATE INDEX IF NOT EXISTS pitching_season_stats_player_season_idx + ON pitching_season_stats (player_id, season); + +CREATE INDEX IF NOT EXISTS pitching_season_stats_team_season_idx + ON pitching_season_stats (team_id, season); + +-- --------------------------------------------------------------------------- +-- Column additions to existing tables +-- All use ADD COLUMN IF NOT EXISTS for idempotency +-- --------------------------------------------------------------------------- + +-- card.variant: nullable integer, identifies refractor/variant tier +ALTER TABLE card + ADD COLUMN IF NOT EXISTS variant INTEGER NULL; + +-- battingcard.image_url: cached S3/CDN URL for rendered card image +ALTER TABLE battingcard + ADD COLUMN IF NOT EXISTS image_url VARCHAR(500) NULL; + +-- pitchingcard.image_url: cached S3/CDN URL for rendered card image +ALTER TABLE pitchingcard + ADD COLUMN IF NOT EXISTS image_url VARCHAR(500) NULL; + +COMMIT;