Architecture¶
This document provides a technical overview of aiogram-cmds architecture, design decisions, and internal structure.
๐๏ธ High-Level Architecture¶
aiogram-cmds follows a layered architecture that provides three levels of complexity:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ User Interface โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Auto-Setup โ Simple Mode โ Advanced Mode โ
โ โ โ โ
โ setup_commands_ โ CmdsSettings + โ CmdsConfig + โ
โ auto() โ CommandPolicy โ ProfileResolver โ
โโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโ
โ CommandScopeMgr โ
โ โ
โ โข setup_all() โ
โ โข update_user() โ
โ โข clear_user() โ
โโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ Builder โ โ Registry โ โ Translator โ
โ โ โ โ โ โ
โ โข build_cmds โ โ โข resolve_profileโ โ โข i18n adapter โ
โ โข validate โ โ โข get_command โ โ โข fallback โ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโ
โ Telegram API โ
โ โ
โ โข set_commands โ
โ โข delete_commandsโ
โ โข menu_button โ
โโโโโโโโโโโโโโโโโโโโ
๐ฏ Design Principles¶
1. Progressive Complexity¶
- Start simple with auto-setup
- Scale to advanced configurations as needed
- No forced complexity for simple use cases
2. Type Safety¶
- Full type hints throughout the codebase
- Strict type checking with Pyright
- Runtime validation with Pydantic
3. i18n First¶
- Built-in support for multiple languages
- Graceful fallback handling
- Extensible translation system
4. Telegram API Compliance¶
- Respects all Telegram command constraints
- Proper scope hierarchy handling
- Menu button integration
๐ฆ Core Components¶
CommandScopeManager¶
The central orchestrator that coordinates all command management operations.
class CommandScopeManager:
def __init__(self, bot: Bot, *, settings=None, config=None, ...):
# Supports both simple and advanced modes
async def setup_all(self) -> None:
# Apply all configured scopes and menu button
async def update_user_commands(self, user_id: int, **flags) -> None:
# Dynamically update user commands based on flags
async def clear_user_commands(self, user_id: int) -> None:
# Remove user-specific command overrides
Key Features: - Dual-mode operation (simple + advanced) - Automatic scope ordering by specificity - Profile-based command resolution - i18n integration
Builder System¶
Converts command names and configurations into Telegram BotCommand objects.
def build_bot_commands(
command_names: List[str],
*,
lang: str,
translator: Optional[Translator] = None,
key_prefix: str = "cmd",
) -> List[BotCommand]:
# Build BotCommand objects with i18n descriptions
Key Features: - Command name validation and sanitization - i18n description resolution - Fallback handling for missing translations - Telegram API compliance (length limits, character restrictions)
Registry System¶
Manages command profiles and resolves which commands belong to which profiles.
class CommandRegistry:
def __init__(self, cfg: CmdsConfig):
# Initialize with configuration
def resolve_profile_commands(self, profile: str) -> List[str]:
# Get command list for a profile (include - exclude)
def get_command(self, name: str) -> Optional[CommandDef]:
# Get command definition by name
Key Features: - Profile-based command grouping - Include/exclude logic - Command definition lookup - Configuration validation
Translator System¶
Provides a unified interface for i18n integration.
class Translator(Protocol):
def __call__(self, key: str, *, locale: str) -> Optional[str]: ...
def build_translator_from_i18n(i18n_obj) -> Translator:
# Create translator adapter from aiogram i18n instance
Key Features: - Protocol-based design for extensibility - aiogram i18n integration - Graceful fallback handling - No-op translator for testing
๐ Data Flow¶
1. Initialization Flow¶
2. Setup Flow¶
3. Dynamic Update Flow¶
๐๏ธ Configuration System¶
Simple Mode Configuration¶
@dataclass
class CmdsSettings:
languages: List[str] = ["en"]
fallback_language: str = "en"
i18n_key_prefix: str = "cmd"
profile: str = "default"
menu_button: str = "commands"
Advanced Mode Configuration¶
class CmdsConfig(BaseModel):
languages: List[str] = ["en"]
fallback_language: str = "en"
i18n_key_prefix: str = "cmd"
commands: Dict[str, CommandDef] = Field(default_factory=dict)
profiles: Dict[str, ProfileDef] = Field(default_factory=dict)
scopes: List[ScopeDef] = Field(default_factory=list)
menu_button: MenuButtonDef = Field(default_factory=MenuButtonDef)
๐ง Policy System¶
Command Policy (Simple Mode)¶
class CommandPolicy(Protocol):
def __call__(self, flags: Flags) -> List[str]: ...
def default_policy(flags: Flags) -> List[str]:
# Convert user flags to command list
Profile Resolver (Advanced Mode)¶
class ProfileResolver(Protocol):
def __call__(self, flags: Flags) -> str: ...
def my_profile_resolver(flags: Flags) -> str:
# Convert user flags to profile name
๐ i18n Integration¶
Translation Key Pattern¶
Example:
- cmd.start.desc โ "Start the bot"
- cmd.help.desc โ "Show help information"
Fallback Strategy¶
- Try i18n key with user's language
- Try i18n key with fallback language
- Use Title Case of command name
- Use "Command" as final fallback
๐ฏ Scope Management¶
Scope Hierarchy (Most Specific First)¶
chat_member- Specific user in specific chatchat_admins- All admins in specific chatchat- All users in specific chatall_chat_admins- All chat administrators globallyall_group_chats- All group chatsall_private_chats- All private chatsdefault- Global fallback
Scope Application Order¶
Commands are applied in order of specificity, with more specific scopes overriding broader ones.
๐ Dynamic Updates¶
User Command Updates¶
await manager.update_user_commands(
user_id=12345,
is_registered=True,
has_vehicle=False,
user_language="en"
)
Process: 1. Create Flags object from parameters 2. Resolve profile (policy or resolver) 3. Get command list from registry 4. Build BotCommand objects with i18n 5. Apply to user's private chat scope
Command Clearing¶
Process: 1. Delete user-specific command overrides 2. User falls back to broader scope commands 3. Log the operation for debugging
๐งช Testing Architecture¶
Unit Tests¶
- Test individual components in isolation
- Mock external dependencies (Telegram API, i18n)
- Validate configuration models
- Test edge cases and error conditions
Integration Tests¶
- Test full command setup workflows
- Verify Telegram API interactions
- Test i18n integration
- Validate scope hierarchy
Performance Tests¶
- Benchmark command building performance
- Test with large command sets
- Measure memory usage
- Validate scalability
๐ Security Considerations¶
Input Validation¶
- Command names are validated against Telegram constraints
- User IDs are validated as positive integers
- Configuration is validated with Pydantic
- i18n keys are sanitized
Error Handling¶
- Graceful degradation on i18n failures
- Fallback to default commands on errors
- Comprehensive logging for debugging
- No sensitive data in logs
๐ Performance Optimizations¶
Caching¶
- Command definitions are cached in registry
- Translation results can be cached (future enhancement)
- Profile resolution results can be memoized
Batch Operations¶
- Multiple scopes are applied in single operations
- Command building is optimized for bulk operations
- Minimal API calls to Telegram
Memory Efficiency¶
- Lazy loading of configurations
- Efficient data structures
- Minimal object creation in hot paths
๐ฎ Future Enhancements¶
Planned Features¶
- Rate Limiting: Built-in rate limiting for command updates
- Caching: Redis-based caching for multi-worker deployments
- Analytics: Command usage analytics and insights
- Webhooks: Webhook-based command management
- Admin Panel: Web interface for command management
Architecture Evolution¶
- Plugin system for custom command types
- Event-driven architecture for real-time updates
- Microservices support for large-scale deployments
- GraphQL API for advanced integrations
This architecture provides a solid foundation for command management while remaining flexible and extensible for future needs.