- Add 4 TELEGRAM_WIDGET_* settings to config (size, radius, userpic, request_access)
- Register TELEGRAM_WIDGET category with choices, hints, and prefix mapping
- Add public GET /branding/telegram-widget endpoint returning widget config
- Use Literal type for size validation, Field(ge=0, le=20) for radius bounds
- Clamp radius values from DB to prevent out-of-range values
Root cause: ensure_tariffs_synced runs BEFORE bot_configuration_service.initialize(),
so SALES_MODE from system_settings is not yet applied. If SALES_MODE=classic is set
via cabinet (not .env), load_period_prices_from_db sees tariffs mode and loads tariff
prices into _DB_PERIOD_PRICES. Then refresh_period_prices() always prefers
_DB_PERIOD_PRICES over settings.PRICE_*_DAYS, even in classic mode.
Three fixes:
1. refresh_period_prices() now checks settings.is_tariffs_mode() before using
_DB_PERIOD_PRICES — classic mode always uses settings.PRICE_*_DAYS
2. initialize() calls refresh_period_prices() after all DB overrides are applied,
so SALES_MODE is correct when prices are recalculated
3. Switching SALES_MODE to classic via cabinet now clears _DB_PERIOD_PRICES
- Multi-channel subscription enforcement via middleware, events, and cabinet API
- 3-layer cache architecture: Redis -> PostgreSQL -> rate-limited Telegram API
- ChatMemberUpdated event-driven tracking with automatic VPN access control
- Admin management via bot FSM handler and REST API with full CRUD
- Channel ID normalization: @username resolved to numeric ID at creation time
- Fail-closed error handling: API errors deny access (security-first)
- Background reconciliation with keyset pagination (100 per batch)
- Per-user rate limiting on subscription check button (5s cooldown)
- Redis connection pooling via cache singleton (no per-request connections)
- Database: channel_id index, multi-row upsert optimization
- Localization: en, ru, zh, fa, ua translations for all new strings
- Frontend blocking UI with channel list and subscription status
- Admin channel management page with toggle, delete, and create
When changing SUPPORT_SYSTEM_MODE via system settings admin panel, the
SupportSettingsService JSON cache was not updated, causing the old value
to take priority. Now both services stay in sync bidirectionally.
- 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
- Rename mode from 'text' to 'cabinet' (text/text_only/minimal kept as aliases)
- Add build_cabinet_url() for joining MINIAPP_CUSTOM_URL with section paths
- Cabinet main menu now has section-specific buttons: subscription, balance,
referral, support, info — each opens the corresponding cabinet page
- Add CALLBACK_TO_CABINET_PATH mapping for automatic deep-linking from
callback_data to cabinet routes (/subscription, /balance, /referral, etc.)
- Unmapped callback_data gracefully falls back to regular Telegram callbacks
- Add startup validation warning when cabinet mode is active without MINIAPP_CUSTOM_URL
- Update admin broadcast buttons with section-specific routing
- Backward compatible: is_text_main_menu_mode() kept as alias for is_cabinet_mode()
Remove AUTO_ACTIVATE_AFTER_TOPUP and SHOW_ACTIVATION_PROMPT_AFTER_TOPUP
features from all payment providers, config, system settings, and tests.
Cart auto-purchase (AUTO_PURCHASE_AFTER_TOPUP) is preserved.
Bug fixes:
- fix KeyError 'months' in devices.py for custom locale overrides
- fix IntegrityError on trial subscription retry (update existing PENDING instead of INSERT)
- fix PendingRollbackError cascade by adding db.rollback() before recovery
- fix TelegramForbiddenError not caught in photo_message.py
- fix "query is too old" spam in required_sub_channel_check
- add missing trial locale keys (TRIAL_PAYMENT_DESCRIPTION, TRIAL_REFUND_DESCRIPTION, TRIAL_ACTIVATION_ERROR)
New setting allows granular control over trial availability:
- none: trial available for all (default)
- email: trial disabled for email users
- telegram: trial disabled for telegram users
- all: trial disabled for everyone
Enforced in bot handlers, cabinet API, and miniapp routes.
Automatically appears in admin panel as dropdown via CHOICES.
- 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
- Добавлена кнопка "⚙️ Настройки трафика" в меню мониторинга
- Добавлен UI для управления быстрой и суточной проверками трафика
- Можно включать/выключать проверки, менять пороги и интервалы
- Настройки сохраняются в БД через BotConfigurationService
- Добавлены SETTING_HINTS с описаниями параметров
- Introduced new ban notification messages for device limit, WiFi, and mobile network violations in the configuration.
- Refactored the BanNotificationService to utilize the new messages from the configuration for sending notifications.
- Added a new method to handle mobile network ban notifications.
- Updated API routes to support the new notification type for mobile network bans.
- Обновлены схемы и маршруты для поддержки покупки тарифов и управления трафиком.
- Реализована синхронизация тарифов и серверов из RemnaWave при запуске.
- Добавлены новые параметры в тарифы: server_traffic_limits и allow_traffic_topup.
- Обновлены настройки и логика для проверки доступности докупки трафика в зависимости от тарифа.
- Внедрены новые эндпоинты для работы с колесом удачи и обработка платежей через Stars.
Обновлён .env.example с новыми параметрами для режима продаж подписок.