Add boss battles, level caps, and badge tracking

Introduces full boss battle system: data models (BossBattle, BossPokemon,
BossResult), API endpoints for CRUD and per-run defeat tracking, and frontend
UI including a sticky level cap bar with badge display on the run page,
interleaved boss battle cards in the encounter list, and an admin panel
section for managing boss battles and their pokemon teams.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-08 11:16:13 +01:00
parent 3b87397432
commit 190b08eb26
23 changed files with 1614 additions and 61 deletions

View File

@@ -1,3 +1,13 @@
from app.schemas.boss import (
BossBattleCreate,
BossBattleResponse,
BossBattleUpdate,
BossPokemonInput,
BossPokemonResponse,
BossResultCreate,
BossResultResponse,
BossResultUpdate,
)
from app.schemas.encounter import (
EncounterCreate,
EncounterDetailResponse,
@@ -29,6 +39,14 @@ from app.schemas.pokemon import (
from app.schemas.run import RunCreate, RunDetailResponse, RunResponse, RunUpdate
__all__ = [
"BossBattleCreate",
"BossBattleResponse",
"BossBattleUpdate",
"BossPokemonInput",
"BossPokemonResponse",
"BossResultCreate",
"BossResultResponse",
"BossResultUpdate",
"BulkImportItem",
"BulkImportResult",
"EncounterCreate",

View File

@@ -0,0 +1,80 @@
from datetime import datetime
from app.schemas.base import CamelModel
from app.schemas.pokemon import PokemonResponse
class BossPokemonResponse(CamelModel):
id: int
pokemon_id: int
level: int
order: int
pokemon: PokemonResponse
class BossBattleResponse(CamelModel):
id: int
game_id: int
name: str
boss_type: str
badge_name: str | None
badge_image_url: str | None
level_cap: int
order: int
after_route_id: int | None
location: str
sprite_url: str | None
pokemon: list[BossPokemonResponse] = []
class BossResultResponse(CamelModel):
id: int
run_id: int
boss_battle_id: int
result: str
attempts: int
completed_at: datetime | None
# --- Input schemas ---
class BossBattleCreate(CamelModel):
name: str
boss_type: str
badge_name: str | None = None
badge_image_url: str | None = None
level_cap: int
order: int
after_route_id: int | None = None
location: str
sprite_url: str | None = None
class BossBattleUpdate(CamelModel):
name: str | None = None
boss_type: str | None = None
badge_name: str | None = None
badge_image_url: str | None = None
level_cap: int | None = None
order: int | None = None
after_route_id: int | None = None
location: str | None = None
sprite_url: str | None = None
class BossPokemonInput(CamelModel):
pokemon_id: int
level: int
order: int
class BossResultCreate(CamelModel):
boss_battle_id: int
result: str
attempts: int = 1
class BossResultUpdate(CamelModel):
result: str | None = None
attempts: int | None = None