Split player model architecture into dedicated documentation files for clarity and maintainability. Added Phase 1 status tracking and comprehensive player model specs covering API models, game models, mappers, and testing strategy. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
7.2 KiB
7.2 KiB
SBA API Models Specification
Purpose: Pydantic models that exactly match SBA API responses
File: backend/app/models/api_models.py (SBA section)
Overview
SBA player data comes from 1 API call:
/players/:player_id?short_output=false- Player with nested team data
Much simpler than PD - no separate ratings calls needed.
Base URL
SBA_API_BASE_URL = "https://api.sba.manticorum.com/"
Model Hierarchy
SbaPlayerApi (player data)
└─ team: SbaTeamApi
├─ manager1: SbaManagerApi
├─ manager2: Optional[SbaManagerApi]
└─ division: SbaDivisionApi
Nested Models
SbaManagerApi
JSON Example:
{
"id": 3,
"name": "Cal",
"image": null,
"headline": null,
"bio": null
}
Pydantic Model:
class SbaManagerApi(BaseModel):
"""SBA Manager (nested in team response)"""
id: int
name: str
image: Optional[str] = None
headline: Optional[str] = None
bio: Optional[str] = None
SbaDivisionApi
JSON Example:
{
"id": 41,
"division_name": "Big Chungus",
"division_abbrev": "BBC",
"league_name": "SBa",
"league_abbrev": "SBa",
"season": 12
}
Pydantic Model:
class SbaDivisionApi(BaseModel):
"""SBA Division (nested in team response)"""
id: int
division_name: str
division_abbrev: str
league_name: str
league_abbrev: str
season: int
SbaTeamApi
JSON Example:
{
"id": 499,
"abbrev": "WV",
"sname": "Black Bears",
"lname": "West Virginia Black Bears",
"manager_legacy": null,
"division_legacy": null,
"gmid": "258104532423147520",
"gmid2": null,
"manager1": {
"id": 3,
"name": "Cal",
"image": null,
"headline": null,
"bio": null
},
"manager2": null,
"division": {
"id": 41,
"division_name": "Big Chungus",
"division_abbrev": "BBC",
"league_name": "SBa",
"league_abbrev": "SBa",
"season": 12
},
"mascot": null,
"stadium": "https://i.postimg.cc/rpRZ2NNF/wvpark.png",
"gsheet": null,
"thumbnail": "https://i.postimg.cc/HjDc8bBF/blackbears-transparent.png",
"color": "6699FF",
"dice_color": null,
"season": 12,
"auto_draft": null
}
Pydantic Model:
class SbaTeamApi(BaseModel):
"""SBA Team (nested in player response)"""
id: int
abbrev: str
sname: str # Short name
lname: str # Long name
manager_legacy: Optional[str] = None
division_legacy: Optional[str] = None
gmid: str # Discord Guild/Manager ID
gmid2: Optional[str] = None
manager1: SbaManagerApi
manager2: Optional[SbaManagerApi] = None
division: SbaDivisionApi
mascot: Optional[str] = None
stadium: Optional[str] = None
gsheet: Optional[str] = None
thumbnail: Optional[str] = None
color: str # Hex color without #
dice_color: Optional[str] = None
season: int
auto_draft: Optional[bool] = None
Player Model
SbaPlayerApi
API Endpoint: GET /players/:player_id?short_output=false
JSON Example:
{
"id": 12288,
"name": "Ronald Acuna Jr",
"wara": 0.0,
"image": "https://sba-cards-2024.s3.us-east-1.amazonaws.com/2024-cards/ronald-acuna-jr.png",
"image2": null,
"team": {
"id": 499,
"abbrev": "WV",
"sname": "Black Bears",
"lname": "West Virginia Black Bears",
"manager_legacy": null,
"division_legacy": null,
"gmid": "258104532423147520",
"gmid2": null,
"manager1": {
"id": 3,
"name": "Cal",
"image": null,
"headline": null,
"bio": null
},
"manager2": null,
"division": {
"id": 41,
"division_name": "Big Chungus",
"division_abbrev": "BBC",
"league_name": "SBa",
"league_abbrev": "SBa",
"season": 12
},
"mascot": null,
"stadium": "https://i.postimg.cc/rpRZ2NNF/wvpark.png",
"gsheet": null,
"thumbnail": "https://i.postimg.cc/HjDc8bBF/blackbears-transparent.png",
"color": "6699FF",
"dice_color": null,
"season": 12,
"auto_draft": null
},
"season": 12,
"pitcher_injury": null,
"pos_1": "RF",
"pos_2": null,
"pos_3": null,
"pos_4": null,
"pos_5": null,
"pos_6": null,
"pos_7": null,
"pos_8": null,
"last_game": null,
"last_game2": null,
"il_return": null,
"demotion_week": 16,
"headshot": null,
"vanity_card": null,
"strat_code": "Acuna,R",
"bbref_id": "acunaro01",
"injury_rating": "5p30",
"sbaplayer": null
}
Pydantic Model:
class SbaPlayerApi(BaseModel):
"""SBA Player API response"""
id: int
name: str
wara: float # Wins Above Replacement Average
image: str # Card image URL
image2: Optional[str] = None
team: SbaTeamApi
season: int
# Positions (up to 8)
pos_1: Optional[str] = None
pos_2: Optional[str] = None
pos_3: Optional[str] = None
pos_4: Optional[str] = None
pos_5: Optional[str] = None
pos_6: Optional[str] = None
pos_7: Optional[str] = None
pos_8: Optional[str] = None
# Injury/status tracking
pitcher_injury: Optional[str] = None
last_game: Optional[str] = None
last_game2: Optional[str] = None
il_return: Optional[str] = None # Injured list return date
demotion_week: Optional[int] = None
# Additional metadata
headshot: Optional[str] = None
vanity_card: Optional[str] = None
strat_code: Optional[str] = None # Strat-O-Matic code
bbref_id: str # Baseball Reference ID
injury_rating: Optional[str] = None # e.g., "5p30"
sbaplayer: Optional[int] = None # Link to another player record?
Usage Example
import httpx
from app.models.api_models import SbaPlayerApi
# Fetch and deserialize player
async with httpx.AsyncClient() as client:
response = await client.get(
"https://api.sba.manticorum.com/players/12288?short_output=false"
)
player = SbaPlayerApi(**response.json())
# Access nested data with full type safety
print(f"{player.name} plays for {player.team.lname}")
print(f"Manager: {player.team.manager1.name}")
print(f"Division: {player.team.division.division_name}")
Differences from PD
| Aspect | SBA | PD |
|---|---|---|
| API Calls | 1 call | 3 calls (player + batting + pitching) |
| Primary Key | id |
player_id |
| Name Field | name |
p_name |
| Team Data | Full nested object | Just mlbclub string |
| Ratings | None (simplified gameplay) | Detailed outcome probabilities |
| Complexity | Simple | Complex |
Notes
- Single API call: Much simpler than PD - all data in one response
- Rich team data: Full team/manager/division hierarchy included
- No ratings: SBA uses simplified result charts, not detailed probabilities
- Position handling: Same pos_1-8 pattern as PD
- Injury tracking: Additional fields for roster management (IL, demotion)
Next: See game-models.md for game-optimized player models