Add all Gen 1-9 games with colors to seed data

- Add 37 games from Gen 1-9 (Red/Blue through Scarlet/Violet)
- Add color field to Game model matching box art/branding
- Add migration for games.color column
- Update fetch_pokeapi.py to fetch all games and output colors
- Update seed loader to upsert game colors
- Update frontend Game type to include color field

Games without PokeAPI encounter data (ORAS, Let's Go, Sword/Shield,
BDSP, Legends Arceus, Scarlet/Violet) have location structure but
empty encounter tables.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Julian Tabel
2026-02-06 11:46:10 +01:00
parent 5406e5a386
commit f7f5417b6b
41 changed files with 130695 additions and 32 deletions

View File

@@ -0,0 +1,29 @@
"""add color field to games
Revision ID: d4e5f6a7b8c9
Revises: c3d4e5f6a7b8
Create Date: 2026-02-06 14:00:00.000000
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'd4e5f6a7b8c9'
down_revision: Union[str, Sequence[str], None] = 'c3d4e5f6a7b8'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.add_column(
'games',
sa.Column('color', sa.String(7), nullable=True),
)
def downgrade() -> None:
op.drop_column('games', 'color')

View File

@@ -14,6 +14,7 @@ class Game(Base):
region: Mapped[str] = mapped_column(String(50))
box_art_url: Mapped[str | None] = mapped_column(String(500))
release_year: Mapped[int | None] = mapped_column(SmallInteger)
color: Mapped[str | None] = mapped_column(String(7)) # Hex color e.g. #FF0000
routes: Mapped[list["Route"]] = relationship(back_populates="game")
runs: Mapped[list["NuzlockeRun"]] = relationship(back_populates="game")

View File

@@ -17,6 +17,7 @@ class GameResponse(CamelModel):
region: str
box_art_url: str | None
release_year: int | None
color: str | None
class RouteWithChildrenResponse(RouteResponse):
@@ -37,6 +38,7 @@ class GameCreate(CamelModel):
region: str
box_art_url: str | None = None
release_year: int | None = None
color: str | None = None
class GameUpdate(CamelModel):
@@ -46,6 +48,7 @@ class GameUpdate(CamelModel):
region: str | None = None
box_art_url: str | None = None
release_year: int | None = None
color: str | None = None
class RouteCreate(CamelModel):

View File

@@ -0,0 +1 @@
[]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
[]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,37 +1,298 @@
[
{
"name": "Pokemon FireRed",
"slug": "firered",
"generation": 3,
"name": "Pokemon Red",
"slug": "red",
"generation": 1,
"region": "kanto",
"release_year": 2004
"release_year": 1996,
"color": "#FF1111"
},
{
"name": "Pokemon LeafGreen",
"slug": "leafgreen",
"generation": 3,
"name": "Pokemon Blue",
"slug": "blue",
"generation": 1,
"region": "kanto",
"release_year": 2004
"release_year": 1996,
"color": "#1111FF"
},
{
"name": "Pokemon Yellow",
"slug": "yellow",
"generation": 1,
"region": "kanto",
"release_year": 1998,
"color": "#FFD733"
},
{
"name": "Pokemon Gold",
"slug": "gold",
"generation": 2,
"region": "johto",
"release_year": 1999,
"color": "#DAA520"
},
{
"name": "Pokemon Silver",
"slug": "silver",
"generation": 2,
"region": "johto",
"release_year": 1999,
"color": "#C0C0C0"
},
{
"name": "Pokemon Crystal",
"slug": "crystal",
"generation": 2,
"region": "johto",
"release_year": 2000,
"color": "#4FD9FF"
},
{
"name": "Pokemon Ruby",
"slug": "ruby",
"generation": 3,
"region": "hoenn",
"release_year": 2002,
"color": "#A00000"
},
{
"name": "Pokemon Sapphire",
"slug": "sapphire",
"generation": 3,
"region": "hoenn",
"release_year": 2002,
"color": "#0000A0"
},
{
"name": "Pokemon Emerald",
"slug": "emerald",
"generation": 3,
"region": "hoenn",
"release_year": 2005
"release_year": 2005,
"color": "#00A000"
},
{
"name": "Pokemon FireRed",
"slug": "firered",
"generation": 3,
"region": "kanto",
"release_year": 2004,
"color": "#FF7327"
},
{
"name": "Pokemon LeafGreen",
"slug": "leafgreen",
"generation": 3,
"region": "kanto",
"release_year": 2004,
"color": "#00DD00"
},
{
"name": "Pokemon Diamond",
"slug": "diamond",
"generation": 4,
"region": "sinnoh",
"release_year": 2006,
"color": "#AAAAFF"
},
{
"name": "Pokemon Pearl",
"slug": "pearl",
"generation": 4,
"region": "sinnoh",
"release_year": 2006,
"color": "#FFAAAA"
},
{
"name": "Pokemon Platinum",
"slug": "platinum",
"generation": 4,
"region": "sinnoh",
"release_year": 2008,
"color": "#999999"
},
{
"name": "Pokemon HeartGold",
"slug": "heartgold",
"generation": 4,
"region": "johto",
"release_year": 2010
"release_year": 2010,
"color": "#B69E00"
},
{
"name": "Pokemon SoulSilver",
"slug": "soulsilver",
"generation": 4,
"region": "johto",
"release_year": 2010
"release_year": 2010,
"color": "#C0C0E0"
},
{
"name": "Pokemon Black",
"slug": "black",
"generation": 5,
"region": "unova",
"release_year": 2010,
"color": "#444444"
},
{
"name": "Pokemon White",
"slug": "white",
"generation": 5,
"region": "unova",
"release_year": 2010,
"color": "#E1E1E1"
},
{
"name": "Pokemon Black 2",
"slug": "black-2",
"generation": 5,
"region": "unova",
"release_year": 2012,
"color": "#424B50"
},
{
"name": "Pokemon White 2",
"slug": "white-2",
"generation": 5,
"region": "unova",
"release_year": 2012,
"color": "#E3CED0"
},
{
"name": "Pokemon X",
"slug": "x",
"generation": 6,
"region": "kalos",
"release_year": 2013,
"color": "#025DA6"
},
{
"name": "Pokemon Y",
"slug": "y",
"generation": 6,
"region": "kalos",
"release_year": 2013,
"color": "#EA1A3E"
},
{
"name": "Pokemon Omega Ruby",
"slug": "omega-ruby",
"generation": 6,
"region": "hoenn",
"release_year": 2014,
"color": "#CF3025"
},
{
"name": "Pokemon Alpha Sapphire",
"slug": "alpha-sapphire",
"generation": 6,
"region": "hoenn",
"release_year": 2014,
"color": "#26649C"
},
{
"name": "Pokemon Sun",
"slug": "sun",
"generation": 7,
"region": "alola",
"release_year": 2016,
"color": "#F1912B"
},
{
"name": "Pokemon Moon",
"slug": "moon",
"generation": 7,
"region": "alola",
"release_year": 2016,
"color": "#5599CA"
},
{
"name": "Pokemon Ultra Sun",
"slug": "ultra-sun",
"generation": 7,
"region": "alola",
"release_year": 2017,
"color": "#E95B2B"
},
{
"name": "Pokemon Ultra Moon",
"slug": "ultra-moon",
"generation": 7,
"region": "alola",
"release_year": 2017,
"color": "#204E8C"
},
{
"name": "Pokemon Let's Go Pikachu",
"slug": "lets-go-pikachu",
"generation": 7,
"region": "kanto",
"release_year": 2018,
"color": "#F5DA00"
},
{
"name": "Pokemon Let's Go Eevee",
"slug": "lets-go-eevee",
"generation": 7,
"region": "kanto",
"release_year": 2018,
"color": "#D4924B"
},
{
"name": "Pokemon Sword",
"slug": "sword",
"generation": 8,
"region": "galar",
"release_year": 2019,
"color": "#00D4E7"
},
{
"name": "Pokemon Shield",
"slug": "shield",
"generation": 8,
"region": "galar",
"release_year": 2019,
"color": "#EF3B6E"
},
{
"name": "Pokemon Brilliant Diamond",
"slug": "brilliant-diamond",
"generation": 8,
"region": "sinnoh",
"release_year": 2021,
"color": "#44BAE5"
},
{
"name": "Pokemon Shining Pearl",
"slug": "shining-pearl",
"generation": 8,
"region": "sinnoh",
"release_year": 2021,
"color": "#E18AAA"
},
{
"name": "Pokemon Legends: Arceus",
"slug": "legends-arceus",
"generation": 8,
"region": "hisui",
"release_year": 2022,
"color": "#36597B"
},
{
"name": "Pokemon Scarlet",
"slug": "scarlet",
"generation": 9,
"region": "paldea",
"release_year": 2022,
"color": "#F93C3C"
},
{
"name": "Pokemon Violet",
"slug": "violet",
"generation": 9,
"region": "paldea",
"release_year": 2022,
"color": "#A96EEC"
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1 @@
[]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
[]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1 @@
[]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
[]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
[]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -32,23 +32,98 @@ def extract_id(url: str) -> int:
return int(url.rstrip("/").split("/")[-1])
# Game definitions
# Game definitions - Gen 1 through Gen 8
VERSION_GROUPS = {
"firered-leafgreen": {
"versions": ["firered", "leafgreen"],
"generation": 3,
# === Generation 1 ===
"red-blue": {
"versions": ["red", "blue"],
"generation": 1,
"region": "kanto",
"region_id": 1,
"games": {
"firered": {
"name": "Pokemon FireRed",
"slug": "firered",
"release_year": 2004,
"red": {
"name": "Pokemon Red",
"slug": "red",
"release_year": 1996,
"color": "#FF1111",
},
"leafgreen": {
"name": "Pokemon LeafGreen",
"slug": "leafgreen",
"release_year": 2004,
"blue": {
"name": "Pokemon Blue",
"slug": "blue",
"release_year": 1996,
"color": "#1111FF",
},
},
},
"yellow": {
"versions": ["yellow"],
"generation": 1,
"region": "kanto",
"region_id": 1,
"games": {
"yellow": {
"name": "Pokemon Yellow",
"slug": "yellow",
"release_year": 1998,
"color": "#FFD733",
},
},
},
# === Generation 2 ===
"gold-silver": {
"versions": ["gold", "silver"],
"generation": 2,
"region": "johto",
"region_id": 2,
"extra_regions": [1], # Kanto post-game
"games": {
"gold": {
"name": "Pokemon Gold",
"slug": "gold",
"release_year": 1999,
"color": "#DAA520",
},
"silver": {
"name": "Pokemon Silver",
"slug": "silver",
"release_year": 1999,
"color": "#C0C0C0",
},
},
},
"crystal": {
"versions": ["crystal"],
"generation": 2,
"region": "johto",
"region_id": 2,
"extra_regions": [1], # Kanto post-game
"games": {
"crystal": {
"name": "Pokemon Crystal",
"slug": "crystal",
"release_year": 2000,
"color": "#4FD9FF",
},
},
},
# === Generation 3 ===
"ruby-sapphire": {
"versions": ["ruby", "sapphire"],
"generation": 3,
"region": "hoenn",
"region_id": 3,
"games": {
"ruby": {
"name": "Pokemon Ruby",
"slug": "ruby",
"release_year": 2002,
"color": "#A00000",
},
"sapphire": {
"name": "Pokemon Sapphire",
"slug": "sapphire",
"release_year": 2002,
"color": "#0000A0",
},
},
},
@@ -62,6 +137,62 @@ VERSION_GROUPS = {
"name": "Pokemon Emerald",
"slug": "emerald",
"release_year": 2005,
"color": "#00A000",
},
},
},
"firered-leafgreen": {
"versions": ["firered", "leafgreen"],
"generation": 3,
"region": "kanto",
"region_id": 1,
"games": {
"firered": {
"name": "Pokemon FireRed",
"slug": "firered",
"release_year": 2004,
"color": "#FF7327",
},
"leafgreen": {
"name": "Pokemon LeafGreen",
"slug": "leafgreen",
"release_year": 2004,
"color": "#00DD00",
},
},
},
# === Generation 4 ===
"diamond-pearl": {
"versions": ["diamond", "pearl"],
"generation": 4,
"region": "sinnoh",
"region_id": 4,
"games": {
"diamond": {
"name": "Pokemon Diamond",
"slug": "diamond",
"release_year": 2006,
"color": "#AAAAFF",
},
"pearl": {
"name": "Pokemon Pearl",
"slug": "pearl",
"release_year": 2006,
"color": "#FFAAAA",
},
},
},
"platinum": {
"versions": ["platinum"],
"generation": 4,
"region": "sinnoh",
"region_id": 4,
"games": {
"platinum": {
"name": "Pokemon Platinum",
"slug": "platinum",
"release_year": 2008,
"color": "#999999",
},
},
},
@@ -70,16 +201,238 @@ VERSION_GROUPS = {
"generation": 4,
"region": "johto",
"region_id": 2,
"extra_regions": [1], # Kanto post-game
"games": {
"heartgold": {
"name": "Pokemon HeartGold",
"slug": "heartgold",
"release_year": 2010,
"color": "#B69E00",
},
"soulsilver": {
"name": "Pokemon SoulSilver",
"slug": "soulsilver",
"release_year": 2010,
"color": "#C0C0E0",
},
},
},
# === Generation 5 ===
"black-white": {
"versions": ["black", "white"],
"generation": 5,
"region": "unova",
"region_id": 5,
"games": {
"black": {
"name": "Pokemon Black",
"slug": "black",
"release_year": 2010,
"color": "#444444",
},
"white": {
"name": "Pokemon White",
"slug": "white",
"release_year": 2010,
"color": "#E1E1E1",
},
},
},
"black-2-white-2": {
"versions": ["black-2", "white-2"],
"generation": 5,
"region": "unova",
"region_id": 5,
"games": {
"black-2": {
"name": "Pokemon Black 2",
"slug": "black-2",
"release_year": 2012,
"color": "#424B50",
},
"white-2": {
"name": "Pokemon White 2",
"slug": "white-2",
"release_year": 2012,
"color": "#E3CED0",
},
},
},
# === Generation 6 ===
"x-y": {
"versions": ["x", "y"],
"generation": 6,
"region": "kalos",
"region_id": 6,
"games": {
"x": {
"name": "Pokemon X",
"slug": "x",
"release_year": 2013,
"color": "#025DA6",
},
"y": {
"name": "Pokemon Y",
"slug": "y",
"release_year": 2013,
"color": "#EA1A3E",
},
},
},
"omega-ruby-alpha-sapphire": {
"versions": ["omega-ruby", "alpha-sapphire"],
"generation": 6,
"region": "hoenn",
"region_id": 3,
"games": {
"omega-ruby": {
"name": "Pokemon Omega Ruby",
"slug": "omega-ruby",
"release_year": 2014,
"color": "#CF3025",
},
"alpha-sapphire": {
"name": "Pokemon Alpha Sapphire",
"slug": "alpha-sapphire",
"release_year": 2014,
"color": "#26649C",
},
},
},
# === Generation 7 ===
"sun-moon": {
"versions": ["sun", "moon"],
"generation": 7,
"region": "alola",
"region_id": 7,
"games": {
"sun": {
"name": "Pokemon Sun",
"slug": "sun",
"release_year": 2016,
"color": "#F1912B",
},
"moon": {
"name": "Pokemon Moon",
"slug": "moon",
"release_year": 2016,
"color": "#5599CA",
},
},
},
"ultra-sun-ultra-moon": {
"versions": ["ultra-sun", "ultra-moon"],
"generation": 7,
"region": "alola",
"region_id": 7,
"games": {
"ultra-sun": {
"name": "Pokemon Ultra Sun",
"slug": "ultra-sun",
"release_year": 2017,
"color": "#E95B2B",
},
"ultra-moon": {
"name": "Pokemon Ultra Moon",
"slug": "ultra-moon",
"release_year": 2017,
"color": "#204E8C",
},
},
},
"lets-go": {
"versions": ["lets-go-pikachu", "lets-go-eevee"],
"generation": 7,
"region": "kanto",
"region_id": 1,
"games": {
"lets-go-pikachu": {
"name": "Pokemon Let's Go Pikachu",
"slug": "lets-go-pikachu",
"release_year": 2018,
"color": "#F5DA00",
},
"lets-go-eevee": {
"name": "Pokemon Let's Go Eevee",
"slug": "lets-go-eevee",
"release_year": 2018,
"color": "#D4924B",
},
},
},
# === Generation 8 ===
"sword-shield": {
"versions": ["sword", "shield"],
"generation": 8,
"region": "galar",
"region_id": 8,
"games": {
"sword": {
"name": "Pokemon Sword",
"slug": "sword",
"release_year": 2019,
"color": "#00D4E7",
},
"shield": {
"name": "Pokemon Shield",
"slug": "shield",
"release_year": 2019,
"color": "#EF3B6E",
},
},
},
"brilliant-diamond-shining-pearl": {
"versions": ["brilliant-diamond", "shining-pearl"],
"generation": 8,
"region": "sinnoh",
"region_id": 4,
"games": {
"brilliant-diamond": {
"name": "Pokemon Brilliant Diamond",
"slug": "brilliant-diamond",
"release_year": 2021,
"color": "#44BAE5",
},
"shining-pearl": {
"name": "Pokemon Shining Pearl",
"slug": "shining-pearl",
"release_year": 2021,
"color": "#E18AAA",
},
},
},
"legends-arceus": {
"versions": ["legends-arceus"],
"generation": 8,
"region": "hisui",
"region_id": 9,
"games": {
"legends-arceus": {
"name": "Pokemon Legends: Arceus",
"slug": "legends-arceus",
"release_year": 2022,
"color": "#36597B",
},
},
},
# === Generation 9 ===
"scarlet-violet": {
"versions": ["scarlet", "violet"],
"generation": 9,
"region": "paldea",
"region_id": 10,
"games": {
"scarlet": {
"name": "Pokemon Scarlet",
"slug": "scarlet",
"release_year": 2022,
"color": "#F93C3C",
},
"violet": {
"name": "Pokemon Violet",
"slug": "violet",
"release_year": 2022,
"color": "#A96EEC",
},
},
},
@@ -197,10 +550,10 @@ def process_version(version_name: str, vg_info: dict) -> list[dict]:
region = load_resource("region", vg_info["region_id"])
location_refs = list(region["locations"])
# For HGSS, also include Kanto locations
if version_name in ("heartgold", "soulsilver"):
kanto = load_resource("region", 1)
location_refs = location_refs + list(kanto["locations"])
# Include extra regions (e.g., Kanto for Johto games)
for extra_region_id in vg_info.get("extra_regions", []):
extra_region = load_resource("region", extra_region_id)
location_refs = location_refs + list(extra_region["locations"])
print(f" Found {len(location_refs)} locations")
@@ -510,6 +863,7 @@ def main():
"generation": vg_info["generation"],
"region": vg_info["region"],
"release_year": game_info["release_year"],
"color": game_info.get("color"),
})
write_json("games.json", games)

View File

@@ -20,6 +20,7 @@ async def upsert_games(session: AsyncSession, games: list[dict]) -> dict[str, in
generation=game["generation"],
region=game["region"],
release_year=game.get("release_year"),
color=game.get("color"),
).on_conflict_do_update(
index_elements=["slug"],
set_={
@@ -27,6 +28,7 @@ async def upsert_games(session: AsyncSession, games: list[dict]) -> dict[str, in
"generation": game["generation"],
"region": game["region"],
"release_year": game.get("release_year"),
"color": game.get("color"),
},
)
await session.execute(stmt)

View File

@@ -21,7 +21,27 @@ from app.seeds.loader import (
DATA_DIR = Path(__file__).parent / "data"
GAME_FILES = ["firered", "leafgreen", "emerald", "heartgold", "soulsilver"]
# All Gen 1-9 games
GAME_FILES = [
# Gen 1
"red", "blue", "yellow",
# Gen 2
"gold", "silver", "crystal",
# Gen 3
"ruby", "sapphire", "emerald", "firered", "leafgreen",
# Gen 4
"diamond", "pearl", "platinum", "heartgold", "soulsilver",
# Gen 5
"black", "white", "black-2", "white-2",
# Gen 6
"x", "y", "omega-ruby", "alpha-sapphire",
# Gen 7
"sun", "moon", "ultra-sun", "ultra-moon", "lets-go-pikachu", "lets-go-eevee",
# Gen 8
"sword", "shield", "brilliant-diamond", "shining-pearl", "legends-arceus",
# Gen 9
"scarlet", "violet",
]
def load_json(filename: str) -> list[dict]: