feat: evolution/refractor schema migration (generated from dev)
All checks were successful
Build Docker Image / build (pull_request) Successful in 8m32s

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 <noreply@anthropic.com>
This commit is contained in:
Cal Corum 2026-03-23 08:53:58 -05:00
parent dcf9036140
commit 0569974454

View File

@ -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;