major-domo-v2/models/README.md
Cal Corum 8515caaf21 CLAUDE: Implement voice channel management system
Add comprehensive voice channel system for Discord gameplay with:

## New Features
- `/voice-channel public` - Create public voice channels with random codenames
- `/voice-channel private` - Create private team vs team channels with role permissions
- Automatic cleanup after configurable empty duration (default: 5 minutes)
- Restart-resilient JSON persistence for channel tracking
- Background monitoring service with graceful error handling

## Technical Implementation
- **Voice Commands Package** (`commands/voice/`)
  - `channels.py` - Main slash command implementation with modern command groups
  - `cleanup_service.py` - Background service for automatic channel deletion
  - `tracker.py` - JSON-based persistent channel tracking
  - `__init__.py` - Package setup with resilient loading
- **Bot Integration** - Voice cleanup service integrated into bot lifecycle
- **Service Dependencies** - Integration with team, league, and schedule services
- **Permission System** - Team-based Discord role permissions for private channels

## Key Features
- **Public Channels**: Random codenames, open speaking permissions
- **Private Channels**: "{Away} vs {Home}" naming, team role restrictions
- **Auto-cleanup**: Configurable intervals with empty duration thresholds
- **Restart Resilience**: JSON file persistence survives bot restarts
- **Error Handling**: Comprehensive validation and graceful degradation
- **Migration Support**: Deprecated old prefix commands with helpful messages

## Documentation & Testing
- Comprehensive README.md following project patterns
- Full test suite with 15+ test methods covering all scenarios
- Updated CLAUDE.md files with voice command documentation
- Clean IDE diagnostics with proper type safety

## Integration Points
- Team service for user validation and role lookup
- League service for current season/week information
- Schedule service for opponent detection in private channels
- Background task management in bot startup/shutdown

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-24 23:17:39 -05:00

9.6 KiB

Models Directory

The models directory contains Pydantic data models for Discord Bot v2.0, providing type-safe representations of all SBA (Strat-o-Matic Baseball Association) entities. All models inherit from SBABaseModel and follow consistent validation patterns.

Architecture

Pydantic Foundation

All models use Pydantic v2 with:

  • Automatic validation of field types and constraints
  • Serialization/deserialization for API interactions
  • Type safety with full IDE support
  • JSON schema generation for documentation
  • Field validation with custom validators

Base Model (base.py)

The foundation for all SBA models:

class SBABaseModel(BaseModel):
    model_config = {
        "validate_assignment": True,
        "use_enum_values": True,
        "arbitrary_types_allowed": True,
        "json_encoders": {datetime: lambda v: v.isoformat() if v else None}
    }

    id: Optional[int] = None
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None

Breaking Changes (August 2025)

Database entities now require id fields since they're always fetched from the database:

  • Player model: id: int = Field(..., description="Player ID from database")
  • Team model: id: int = Field(..., description="Team ID from database")

Model Categories

Core Entities

League Structure

  • team.py - Team information, abbreviations, divisions
  • division.py - Division structure and organization
  • manager.py - Team managers and ownership
  • standings.py - Team standings and rankings

Player Data

  • player.py - Core player information and identifiers
  • sbaplayer.py - Extended SBA-specific player data
  • batting_stats.py - Batting statistics and performance metrics
  • pitching_stats.py - Pitching statistics and performance metrics
  • roster.py - Team roster assignments and positions

Game Operations

  • game.py - Individual game results and scheduling
  • transaction.py - Player transactions (trades, waivers, etc.)

Draft System

  • draft_pick.py - Individual draft pick information
  • draft_data.py - Draft round and selection data
  • draft_list.py - Complete draft lists and results

Custom Features

  • custom_command.py - User-created Discord commands

Legacy Models

  • current.py - Legacy model definitions for backward compatibility

Model Validation Patterns

Required Fields

Models distinguish between required and optional fields:

class Player(SBABaseModel):
    id: int = Field(..., description="Player ID from database")  # Required
    name: str = Field(..., description="Player full name")        # Required
    team_id: Optional[int] = None                                  # Optional
    position: Optional[str] = None                                 # Optional

Field Constraints

Models use Pydantic validators for data integrity:

class BattingStats(SBABaseModel):
    at_bats: int = Field(ge=0, description="At bats (non-negative)")
    hits: int = Field(ge=0, le=Field('at_bats'), description="Hits (cannot exceed at_bats)")

    @field_validator('batting_average')
    @classmethod
    def validate_batting_average(cls, v):
        if v is not None and not 0.0 <= v <= 1.0:
            raise ValueError('Batting average must be between 0.0 and 1.0')
        return v

Custom Validators

Models implement business logic validation:

class Transaction(SBABaseModel):
    transaction_type: str
    player_id: int
    from_team_id: Optional[int] = None
    to_team_id: Optional[int] = None

    @model_validator(mode='after')
    def validate_team_requirements(self):
        if self.transaction_type == 'trade':
            if not self.from_team_id or not self.to_team_id:
                raise ValueError('Trade transactions require both from_team_id and to_team_id')
        return self

API Integration

Data Transformation

Models provide methods for API interaction:

class Player(SBABaseModel):
    @classmethod
    def from_api_data(cls, data: Dict[str, Any]):
        """Create model instance from API response data."""
        if not data:
            raise ValueError(f"Cannot create {cls.__name__} from empty data")
        return cls(**data)

    def to_dict(self, exclude_none: bool = True) -> Dict[str, Any]:
        """Convert model to dictionary for API requests."""
        return self.model_dump(exclude_none=exclude_none)

Serialization Examples

Models handle various data formats:

# From API JSON
player_data = {"id": 123, "name": "Player Name", "team_id": 5}
player = Player.from_api_data(player_data)

# To API JSON
api_payload = player.to_dict(exclude_none=True)

# JSON string serialization
json_string = player.model_dump_json()

# From JSON string
player_copy = Player.model_validate_json(json_string)

Testing Requirements

Model Validation Testing

All model tests must provide complete data:

def test_player_creation():
    # ✅ Correct - provides required ID field
    player = Player(
        id=123,
        name="Test Player",
        team_id=5,
        position="1B"
    )
    assert player.id == 123

def test_incomplete_data():
    # ❌ This will fail - missing required ID
    with pytest.raises(ValidationError):
        Player(name="Test Player")  # Missing required id field

Test Data Patterns

Use helper functions for consistent test data:

def create_test_player(**overrides) -> Player:
    """Create a test player with default values."""
    defaults = {
        "id": 123,
        "name": "Test Player",
        "team_id": 1,
        "position": "1B"
    }
    defaults.update(overrides)
    return Player(**defaults)

def test_player_with_stats():
    player = create_test_player(name="Star Player")
    assert player.name == "Star Player"
    assert player.id == 123  # Default from helper

Field Types and Constraints

Common Field Patterns

Identifiers

id: int = Field(..., description="Database primary key")
player_id: int = Field(..., description="Foreign key to player")
team_id: Optional[int] = Field(None, description="Foreign key to team")

Names and Text

name: str = Field(..., min_length=1, max_length=100)
abbreviation: str = Field(..., min_length=2, max_length=5)
description: Optional[str] = Field(None, max_length=500)

Statistics

games_played: int = Field(ge=0, description="Games played (non-negative)")
batting_average: Optional[float] = Field(None, ge=0.0, le=1.0)
era: Optional[float] = Field(None, ge=0.0, description="Earned run average")

Dates and Times

game_date: Optional[datetime] = None
created_at: Optional[datetime] = None
season_year: int = Field(..., ge=1900, le=2100)

Model Relationships

Foreign Key Patterns

Models reference related entities via ID fields:

class Player(SBABaseModel):
    id: int
    team_id: Optional[int] = None  # References Team.id

class BattingStats(SBABaseModel):
    player_id: int  # References Player.id
    season: int
    team_id: int    # References Team.id

Nested Objects

Some models contain nested structures:

class CustomCommand(SBABaseModel):
    name: str
    creator: Manager  # Nested Manager object
    response: str

class DraftPick(SBABaseModel):
    pick_number: int
    player: Optional[Player] = None  # Optional nested Player
    team: Team                       # Required nested Team

Validation Error Handling

Common Validation Errors

  • Missing required fields - Provide all required model fields
  • Type mismatches - Ensure field types match model definitions
  • Constraint violations - Check field validators and constraints
  • Invalid nested objects - Validate all nested model data

Error Examples

try:
    player = Player(name="Test")  # Missing required id
except ValidationError as e:
    print(e.errors())
    # [{'type': 'missing', 'loc': ('id',), 'msg': 'Field required'}]

try:
    stats = BattingStats(hits=5, at_bats=3)  # hits > at_bats
except ValidationError as e:
    print(e.errors())
    # Constraint violation error

Performance Considerations

Model Instantiation

  • Use model_validate() for external data
  • Use model_construct() for trusted internal data (faster)
  • Cache model instances when possible
  • Avoid repeated validation of the same data

Memory Usage

  • Models are relatively lightweight
  • Nested objects can increase memory footprint
  • Consider using __slots__ for high-volume models
  • Use exclude_none=True to reduce serialization size

Development Guidelines

Adding New Models

  1. Inherit from SBABaseModel for consistency
  2. Define required fields explicitly with proper types
  3. Add field descriptions for documentation
  4. Include validation rules for data integrity
  5. Provide from_api_data() class method if needed
  6. Write comprehensive tests covering edge cases

Model Evolution

  • Backward compatibility - Add optional fields for new features
  • Migration patterns - Handle schema changes gracefully
  • Version management - Document breaking changes
  • API alignment - Keep models synchronized with API

Testing Strategy

  • Unit tests for individual model validation
  • Integration tests with service layer
  • Edge case testing for validation rules
  • Performance tests for large data sets

Next Steps for AI Agents:

  1. Review existing model implementations for patterns
  2. Understand the validation rules and field constraints
  3. Check the service layer integration in /services
  4. Follow the testing patterns with complete model data
  5. Consider the API data format when creating new models