diff --git a/bot/utils/usernames.py b/bot/utils/usernames.py
new file mode 100644
index 0000000..b2eff8c
--- /dev/null
+++ b/bot/utils/usernames.py
@@ -0,0 +1,409 @@
+"""
+Утилиты для работы с информацией о пользователях
+"""
+from typing import Optional, Union
+from enum import Enum
+
+from aiogram.types import Message, CallbackQuery, User, InlineQuery, ChatMemberUpdated
+
+__all__ = (
+ 'get_user_display_name',
+ 'get_user_mention',
+ 'get_user_id',
+ 'username',
+ 'format_user',
+ 'UserFormat',
+ 'is_bot',
+ 'has_username',
+ 'is_premium',
+ 'get_language_code',
+ 'compare_users',
+ 'get_user_info_dict'
+)
+
+
+class UserFormat(str, Enum):
+ """Форматы отображения пользователя"""
+ USERNAME = 'username' # @username или @id123
+ FULL_NAME = 'full_name' # Имя Фамилия
+ MENTION = 'mention' # HTML mention
+ MENTION_MARKDOWN = 'markdown' # Markdown mention
+ FIRST_NAME = 'first_name' # Только имя
+ ID_ONLY = 'id' # Только ID
+ DETAILED = 'detailed' # @username (Имя Фамилия, ID: 123)
+
+
+# Тип для всех событий с пользователем
+EventType = Union[Message, CallbackQuery, InlineQuery, ChatMemberUpdated]
+
+
+def _extract_user(event: EventType) -> Optional[User]:
+ """
+ Извлекает объект User из события.
+
+ Args:
+ event: Объект события
+
+ Returns:
+ User или None
+ """
+ if isinstance(event, (Message, CallbackQuery, InlineQuery)):
+ return event.from_user
+ elif isinstance(event, ChatMemberUpdated):
+ return event.from_user or event.new_chat_member.user
+
+ return None
+
+
+def get_user_display_name(
+ event: EventType,
+ default: str = "Unknown User"
+) -> str:
+ """
+ Возвращает отображаемое имя пользователя (Full Name).
+
+ Args:
+ event: Объект события (Message, CallbackQuery, и т.д.)
+ default: Значение по умолчанию если пользователь не найден
+
+ Returns:
+ str: Полное имя пользователя
+
+ Example:
+ >> get_user_display_name(message)
+ 'John Doe'
+ >> get_user_display_name(message)
+ 'John' # Если нет фамилии
+ """
+ user = _extract_user(event)
+
+ if not user:
+ return default
+
+ # Полное имя (приоритет)
+ if user.full_name:
+ return user.full_name
+
+ # Только имя
+ if user.first_name:
+ return user.first_name
+
+ # Username как запасной вариант
+ if user.username:
+ return f"@{user.username}"
+
+ # ID как последний вариант
+ return f"User {user.id}"
+
+
+def get_user_mention(
+ event: EventType,
+ parse_mode: str = 'HTML',
+ show_username: bool = False
+) -> str:
+ """
+ Возвращает упоминание пользователя (кликабельное).
+
+ Args:
+ event: Объект события
+ parse_mode: Режим парсинга ('HTML' или 'Markdown')
+ show_username: Показывать username вместо имени
+
+ Returns:
+ str: HTML/Markdown упоминание
+
+ Example:
+ >> get_user_mention(message)
+ 'John Doe'
+
+ >> get_user_mention(message, parse_mode='Markdown')
+ '[John Doe](tg://user?id=123456789)'
+
+ >> get_user_mention(message, show_username=True)
+ '@johndoe'
+ """
+ user = _extract_user(event)
+
+ if not user:
+ return "Unknown User"
+
+ # Определяем текст для отображения
+ if show_username and user.username:
+ display_text = f"@{user.username}"
+ else:
+ display_text = user.full_name or user.first_name or f"User {user.id}"
+
+ # Формируем ссылку
+ user_link = f"tg://user?id={user.id}"
+
+ if parse_mode.upper() == 'HTML':
+ return f'{display_text}'
+ elif parse_mode.upper() in ('MARKDOWN', 'MARKDOWNV2'):
+ # Экранируем специальные символы для Markdown
+ display_text = display_text.replace('[', '\\[').replace(']', '\\]')
+ return f'[{display_text}]({user_link})'
+ else:
+ return display_text
+
+
+def get_user_id(event: EventType) -> Optional[int]:
+ """
+ Возвращает ID пользователя.
+
+ Args:
+ event: Объект события
+
+ Returns:
+ int или None: ID пользователя
+
+ Example:
+ >> get_user_id(message)
+ 123456789
+ """
+ user = _extract_user(event)
+ return user.id if user else None
+
+
+def username(
+ event: EventType,
+ with_at: bool = True,
+ fallback_to_id: bool = True
+) -> str:
+ """
+ Возвращает username пользователя или ID если username отсутствует.
+
+ Это основная функция для получения идентификатора пользователя
+ в формате @username или @id123.
+
+ Args:
+ event: Объект события (Message, CallbackQuery, и т.д.)
+ with_at: Добавлять @ в начало
+ fallback_to_id: Использовать ID если нет username
+
+ Returns:
+ str: Username или ID пользователя
+
+ Raises:
+ ValueError: Если информация о пользователе отсутствует
+
+ Example:
+ >> username(message)
+ '@johndoe'
+
+ >> username(message) # Нет username
+ '@123456789'
+
+ >> username(message, with_at=False)
+ 'johndoe'
+
+ >> username(message, fallback_to_id=False)
+ '' # Если нет username
+ """
+ user = _extract_user(event)
+
+ if not user:
+ raise ValueError("Информация о пользователе отсутствует в событии")
+
+ # Если есть username
+ if user.username:
+ return f"@{user.username}" if with_at else user.username
+
+ # Fallback на ID
+ if fallback_to_id:
+ return f"@{user.id}" if with_at else str(user.id)
+
+ # Если ничего нет
+ return ""
+
+
+def format_user(
+ event: EventType,
+ format_type: UserFormat = UserFormat.USERNAME,
+ default: str = "@System"
+) -> str:
+ """
+ Универсальная функция форматирования пользователя.
+
+ Args:
+ event: Объект события
+ format_type: Тип форматирования (из enum UserFormat)
+ default: Значение по умолчанию
+
+ Returns:
+ str: Отформатированная информация о пользователе
+
+ Example:
+ >> format_user(message, UserFormat.USERNAME)
+ '@johndoe'
+
+ >> format_user(message, UserFormat.FULL_NAME)
+ 'John Doe'
+
+ >> format_user(message, UserFormat.MENTION)
+ 'John Doe'
+
+ >> format_user(message, UserFormat.DETAILED)
+ '@johndoe (John Doe, ID: 123456789)'
+ """
+ user = _extract_user(event)
+
+ if not user:
+ return default
+
+ # USERNAME: @username или @id
+ if format_type == UserFormat.USERNAME:
+ if user.username:
+ return f"@{user.username}"
+ return f"@{user.id}"
+
+ # FULL_NAME: Имя Фамилия
+ elif format_type == UserFormat.FULL_NAME:
+ return user.full_name or user.first_name or f"User {user.id}"
+
+ # MENTION: HTML упоминание
+ elif format_type == UserFormat.MENTION:
+ display = user.full_name or user.first_name or f"User {user.id}"
+ return f'{display}'
+
+ # MENTION_MARKDOWN: Markdown упоминание
+ elif format_type == UserFormat.MENTION_MARKDOWN:
+ display = user.full_name or user.first_name or f"User {user.id}"
+ display = display.replace('[', '\\[').replace(']', '\\]')
+ return f'[{display}](tg://user?id={user.id})'
+
+ # FIRST_NAME: Только имя
+ elif format_type == UserFormat.FIRST_NAME:
+ return user.first_name or f"User {user.id}"
+
+ # ID_ONLY: Только ID
+ elif format_type == UserFormat.ID_ONLY:
+ return str(user.id)
+
+ # DETAILED: Подробная информация
+ elif format_type == UserFormat.DETAILED:
+ parts = []
+
+ # Username
+ if user.username:
+ parts.append(f"@{user.username}")
+
+ # Full name
+ if user.full_name:
+ parts.append(f"({user.full_name}")
+ elif user.first_name:
+ parts.append(f"({user.first_name}")
+
+ # ID
+ parts.append(f"ID: {user.id})")
+
+ return ' '.join(parts) if parts else f"User {user.id}"
+
+ # По умолчанию
+ return default
+
+
+# ================= ДОПОЛНИТЕЛЬНЫЕ УТИЛИТЫ =================
+
+def is_bot(event: EventType) -> bool:
+ """
+ Проверяет, является ли пользователь ботом.
+
+ Args:
+ event: Объект события
+
+ Returns:
+ bool: True если бот
+ """
+ user = _extract_user(event)
+ return user.is_bot if user else False
+
+
+def has_username(event: EventType) -> bool:
+ """
+ Проверяет, есть ли у пользователя username.
+
+ Args:
+ event: Объект события
+
+ Returns:
+ bool: True если есть username
+ """
+ user = _extract_user(event)
+ return bool(user and user.username)
+
+
+def is_premium(event: EventType) -> bool:
+ """
+ Проверяет, есть ли у пользователя Telegram Premium.
+
+ Args:
+ event: Объект события
+
+ Returns:
+ bool: True если Premium
+ """
+ user = _extract_user(event)
+ return user.is_premium if user else False
+
+
+def get_language_code(event: EventType) -> Optional[str]:
+ """
+ Возвращает код языка пользователя.
+
+ Args:
+ event: Объект события
+
+ Returns:
+ Optional[str]: Код языка ('ru', 'en', и т.д.)
+ """
+ user = _extract_user(event)
+ return user.language_code if user else None
+
+
+def compare_users(event1: EventType, event2: EventType) -> bool:
+ """
+ Сравнивает двух пользователей по ID.
+
+ Args:
+ event1: Первое событие
+ event2: Второе событие
+
+ Returns:
+ bool: True если это один и тот же пользователь
+ """
+ user1 = _extract_user(event1)
+ user2 = _extract_user(event2)
+
+ if not user1 or not user2:
+ return False
+
+ return user1.id == user2.id
+
+
+def get_user_info_dict(event: EventType) -> dict:
+ """
+ Возвращает всю информацию о пользователе в виде словаря.
+
+ Args:
+ event: Объект события
+
+ Returns:
+ dict: Словарь с информацией о пользователе
+ """
+ user = _extract_user(event)
+
+ if not user:
+ return {}
+
+ return {
+ 'id': user.id,
+ 'username': user.username,
+ 'first_name': user.first_name,
+ 'last_name': user.last_name,
+ 'full_name': user.full_name,
+ 'is_bot': user.is_bot,
+ 'is_premium': user.is_premium,
+ 'language_code': user.language_code,
+ 'mention': get_user_mention(event),
+ 'display_name': get_user_display_name(event)
+ }