Initial commit: CLEAN architecture foundation for fantasy hockey backend

Implemented CLEAN architecture with clear separation of concerns:
- Domain layer with entities (Player, Team, Stats, FantasyTeam) and repository interfaces
- Application layer with use case implementations
- Infrastructure layer with NHL API and Yahoo Fantasy API adapters
- Presentation layer with FastAPI configuration and dependency injection

Key features:
- Swappable data source adapters (NHL API, Yahoo Fantasy API)
- Repository pattern for data access abstraction
- Dependency injection for loose coupling
- FastAPI framework with async support
- PostgreSQL database configuration
- Environment-based configuration management

Technology stack: Python 3.11+, FastAPI, PostgreSQL, nhl-api-py, yfpy

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Michael Simard
2025-11-23 17:13:58 -06:00
commit 337a6377de
26 changed files with 973 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
"""Domain repository interfaces package."""
from .player_repository import PlayerRepository
from .team_repository import TeamRepository
from .fantasy_repository import FantasyRepository
__all__ = [
"PlayerRepository",
"TeamRepository",
"FantasyRepository",
]

View File

@@ -0,0 +1,31 @@
"""Fantasy team repository interface."""
from abc import ABC, abstractmethod
from typing import List, Optional
from src.domain.entities import FantasyTeam
class FantasyRepository(ABC):
"""Abstract interface for Yahoo Fantasy Hockey data access."""
@abstractmethod
async def get_fantasy_team(
self, league_id: str, team_id: str
) -> Optional[FantasyTeam]:
"""Retrieves a specific fantasy team from a league."""
pass
@abstractmethod
async def get_user_teams(self, user_id: str) -> List[FantasyTeam]:
"""Retrieves all fantasy teams for a user."""
pass
@abstractmethod
async def get_team_roster(self, league_id: str, team_id: str) -> List[str]:
"""Retrieves the player IDs on a fantasy team's roster."""
pass
@abstractmethod
async def get_league_standings(self, league_id: str) -> List[FantasyTeam]:
"""Retrieves all teams in a league ordered by standings."""
pass

View File

@@ -0,0 +1,36 @@
"""Player repository interface."""
from abc import ABC, abstractmethod
from typing import List, Optional
from src.domain.entities import Player, SkaterStats, GoalieStats
class PlayerRepository(ABC):
"""Abstract interface for player data access."""
@abstractmethod
async def get_player_by_id(self, player_id: str) -> Optional[Player]:
"""Retrieves a player by their unique identifier."""
pass
@abstractmethod
async def get_players_by_team(self, team_id: str) -> List[Player]:
"""Retrieves all players for a specific team."""
pass
@abstractmethod
async def search_players(
self, name: str, position: Optional[str] = None
) -> List[Player]:
"""Searches for players by name and optionally by position."""
pass
@abstractmethod
async def get_skater_stats(self, player_id: str) -> Optional[SkaterStats]:
"""Retrieves current season statistics for a skater."""
pass
@abstractmethod
async def get_goalie_stats(self, player_id: str) -> Optional[GoalieStats]:
"""Retrieves current season statistics for a goalie."""
pass

View File

@@ -0,0 +1,29 @@
"""Team repository interface."""
from abc import ABC, abstractmethod
from typing import List, Optional
from src.domain.entities import NHLTeam
class TeamRepository(ABC):
"""Abstract interface for NHL team data access."""
@abstractmethod
async def get_team_by_id(self, team_id: str) -> Optional[NHLTeam]:
"""Retrieves a team by its unique identifier."""
pass
@abstractmethod
async def get_all_teams(self) -> List[NHLTeam]:
"""Retrieves all NHL teams."""
pass
@abstractmethod
async def get_teams_by_division(self, division: str) -> List[NHLTeam]:
"""Retrieves all teams in a specific division."""
pass
@abstractmethod
async def get_teams_by_conference(self, conference: str) -> List[NHLTeam]:
"""Retrieves all teams in a specific conference."""
pass