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>
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:
Playermodel:id: int = Field(..., description="Player ID from database")Teammodel:id: int = Field(..., description="Team ID from database")
Model Categories
Core Entities
League Structure
team.py- Team information, abbreviations, divisionsdivision.py- Division structure and organizationmanager.py- Team managers and ownershipstandings.py- Team standings and rankings
Player Data
player.py- Core player information and identifierssbaplayer.py- Extended SBA-specific player databatting_stats.py- Batting statistics and performance metricspitching_stats.py- Pitching statistics and performance metricsroster.py- Team roster assignments and positions
Game Operations
game.py- Individual game results and schedulingtransaction.py- Player transactions (trades, waivers, etc.)
Draft System
draft_pick.py- Individual draft pick informationdraft_data.py- Draft round and selection datadraft_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=Trueto reduce serialization size
Development Guidelines
Adding New Models
- Inherit from SBABaseModel for consistency
- Define required fields explicitly with proper types
- Add field descriptions for documentation
- Include validation rules for data integrity
- Provide
from_api_data()class method if needed - 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:
- Review existing model implementations for patterns
- Understand the validation rules and field constraints
- Check the service layer integration in
/services - Follow the testing patterns with complete model data
- Consider the API data format when creating new models