- Remove double html.escape on payment_method (already escaped in helper)
- Use attribute_names=['landing'] keyword arg in db.refresh for consistency
- Use async with Bot() for guaranteed session cleanup
- New send_guest_purchase_notification() method in AdminNotificationService
with blockquote for payment details, landing slug, buyer/recipient info
- Called from fulfill_purchase() for both DELIVERED and PENDING_ACTIVATION
- Called from activate_purchase() when pending purchase is activated
- Different titles: regular purchase, gift purchase, pending activation
- Properly typed GuestPurchase, html.escape on all user data
- Refresh purchase with ['landing'] relationship after commit
- html.escape fallback in _get_payment_method_display
- ruff formatting fixes
- send_subscription_purchase_notification: abs(transaction.amount_kopeks) when no explicit amount_kopeks passed
- send_subscription_renewal_notification: abs(transaction.amount_kopeks) for SubscriptionEvent storage
- Prevents negative amounts in admin Telegram messages and SubscriptionEvent records
- Campaign notifications: add tariff bonus display, hide empty promo group,
compact format matching purchase notification style
- Ticket notifications: send media (photos) in the same topic as the text
notification instead of separately. Uses caption for short texts, sequential
messages for long texts with correct message_thread_id routing
- fix N+1 query in money laundering analysis with GROUP BY batch query
- fix N+1 query in cabinet referral earnings with batch user fetch
- eliminate double balance stats computation in withdrawal flow
- replace in-memory referral counting with SQL COUNT/CASE aggregation
- fix HTML injection in admin Telegram notifications via html.escape()
- standardize return types for reject/complete withdrawal methods
SUBSCRIPTION_PAYMENT transactions have inconsistent signs in DB
(some negative, some positive). Add func.abs()/abs() to all SUM
queries and display code to ensure correct totals regardless of sign.
Affected: admin statistics, referral contest stats, tariff revenue,
campaign stats, reporting service, admin renewal notifications.
- Add ContextVarsMiddleware for automatic user_id/chat_id/username binding
via structlog contextvars (aiogram) and http_method/http_path (FastAPI)
- Use bound_contextvars() context manager instead of clear_contextvars()
to safely restore previous state instead of wiping all context
- Register ContextVarsMiddleware as outermost middleware (before GlobalError)
so all error logs include user context
- Replace structlog.get_logger() with structlog.get_logger(__name__) across
270 calls in 265 files for meaningful logger names
- Switch wrapper_class from BoundLogger to make_filtering_bound_logger()
for pre-processor level filtering (performance optimization)
- Migrate 1411 %-style positional arg logger calls to structlog kwargs
style across 161 files via AST script
- Migrate log_rotation_service.py from stdlib logging to structlog
- Add payment module prefixes to TelegramNotifierProcessor.IGNORED_LOGGER_PREFIXES
and ExcludePaymentFilter.PAYMENT_MODULES to prevent payment data leaking
to Telegram notifications and general log files
- Fix LoggingMiddleware: add from_user null-safety for channel posts,
switch time.time() to time.monotonic() for duration measurement
- Remove duplicate logger assignments in purchase.py, config.py,
inline.py, and admin/payments.py
Remove all modem purchase/management code:
- Delete modem handler, service, and tests
- Remove modem button from keyboards and admin panel
- Remove modem pricing from calculations
- Remove modem REST API endpoint and schemas
- Remove modem decorator, config settings, and notification formatting
- Keep DB column and migration for backwards compatibility
- Add html.escape() to all untrusted webhook data in admin and device
notifications (prevents HTML/Telegram injection)
- Add public send_webhook_notification() and is_enabled property to
AdminNotificationService (eliminates private method access)
- Add dedicated NotificationType enum values for device and not_connected
events (fixes incorrect semantic mapping)
- Extend user resolution to handle nested user objects and userUuid for
device-scope events
- Replace manual __anext__() DB session with AsyncSessionLocal context
manager; skip DB session for admin-only events
- Replace deprecated datetime.utcnow() with datetime.now(UTC)
- Use db.flush() instead of db.commit() in handlers (router commits)
- Wrap _notify_user in try/except to prevent notification failures from
rolling back successful DB mutations
- Add GitHub Markdown to Telegram HTML converter utility
- Place release description in blockquote expandable
- Auto-truncate description to fit 4096 char message limit
- Clean compact layout with clickable version link
- Convert markdown headers, bold, italic, code, links, strikethrough
- Add pyproject.toml with uv and ruff configuration
- Pin Python version to 3.13 via .python-version
- Add Makefile commands: lint, format, fix
- Apply ruff formatting to entire codebase
- Remove unused imports (base64 in yookassa/simple_subscription)
- Update .gitignore for new config files
1. app/keyboards/inline.py
- Добавлен параметр callback_data: str = "back_to_menu" в get_back_keyboard()
- Позволяет использовать кнопку "Назад" с разными callback'ами
2. app/services/admin_notification_service.py
- Добавлен тип "modem" в update_types с заголовком "📡 ИЗМЕНЕНИЕ МОД
При наличии докупленного трафика (например 250 + 10 ГБ = 260 ГБ)
система округляла текущий пакет до ближайшего (500 ГБ) и позволяла
бесплатно переключиться на него.
Исправления:
- confirm_switch_traffic: используется базовый трафик для расчёта цены
- get_traffic_switch_keyboard: добавлен параметр base_traffic_gb
- handle_switch_traffic: показывает информацию о докупленном трафике
- execute_switch_traffic: сбрасывает purchased_traffic_gb при переключении
2) У промогрупп появится приоритет
3) У пользователя может быть несколько промогрупп, но влиять будет только с наивысшим приоритетом
4) Промокоды с промогруппой
5) При выводе пользователей с промогруппой будет также выводиться ссылка на каждого. Можно будет отследить сливы промокодов "для своих". Я в целом это добавлю во все места, где пользователь выводится в админке
6) Исправить баг исчезновения триалки при пополнении
7) Исправить падающие тесты и добавить новых
8) Трафик: 0 ГБ в тестовой подписке исправить на Трафик: Безлимит
9) При попытке изменить промогруппу "Пользователь не найден" - исправил