Личный кабинет абонента и мобильные приложения
Эта страница — единственный источник правды для всего, что касается ЛК и мобильных приложений: брендинг, функциональные модули, безопасность входа, версионирование, push-уведомления.
Содержание раздела
- Обзор и возможности
- Раздел «ЛК и мобильные» в админке
- Авторизация
- Настройки интеграций
- Telegram-бот для уведомлений
- Оплата через YooKassa
- Мобильное приложение
- Поддержка через FreeScout
- AI-ассистент (Claude / AIDA)
- Профиль абонента
- История подключений (RADIUS-сессии)
- Смена пароля абонента
- Развёртывание и SSL
- Firebase Push-уведомления
- Claude AI — конфигурация AI-ассистента
- AI-ассистент — обучение и управление промптом (build 603-607)
- Telegram-бот для операторов (admin bot)
- Дизайн-система ЛК v489 (выравнивание со стилем админки)
- Страницы Личного Кабинета (что видит абонент)
Обзор и возможности
Возможности личного кабинета:
- Просмотр баланса, истории платежей и начислений
- Оплата через YooKassa (банковская карта, SberPay, Т-Банк и др.)
- Смена тарифного плана
- Обещанный платёж
- Добровольная блокировка / снятие блокировки
- Просмотр активных сессий и статистики трафика
- Обращения в техподдержку через FreeScout (вкладки Открытые/Закрытые, статус-точки)
- AI-ассистент Claude — встроенный чат с поддержкой отправки изображений и PDF
- Изменение профиля (имя, email, пароль)
- Привязка Telegram-аккаунта для уведомлений
- Авторизация через Telegram (OAuth)
- PWA-режим (добавление на рабочий стол смартфона)
- Полная адаптация под мобильные устройства
- История RADIUS-сессий с детализацией трафика и активных соединений
Раздел «ЛК и мобильные» в админке
Все user-facing настройки ЛК и мобильных приложений собраны на одной странице:
/admin/settings/lk/
с 5 вкладками. Это позволяет оператору
перепродавать биллинг под собственным брендом или скрывать неиспользуемые модули
без правки шаблонов и деплоя.
Картинки разделов ниже добавим после Phase D (когда Playwright освободится).
Вкладки
| Вкладка | URL | Что настраивается |
|---|---|---|
| Обзор | /admin/settings/lk/overview/ |
4 KPI-cards (push-токенов / Telegram / VK / активных сессий) + сводка брендинга и мобильных версий + таблица последних 10 входов в ЛК (login/IP/канал/метод) + круговая диаграмма каналов входа за 30 дней |
| Брендинг | /admin/settings/lk/branding/ |
9 LK-overrides поверх CompanyBranding: brand_short, контакты поддержки, соцсети VK/MAX, color-override |
| Функции | /admin/settings/lk/features/ |
12 toggle-флагов для скрытия/показа модулей в ЛК и мобиле |
| Безопасность | /admin/settings/lk/security/ |
16 ключей: метод авторизации, лимиты входа, требования к паролю, TTL сессии, 2FA, audit |
| Мобильное | /admin/settings/lk/mobile/ |
Android + iOS параллельно: текущая/мин. версия, force-update URLs, push-настройки, mobile features |
Сохранение настроек идёт через единый endpoint POST /admin/settings/lk/save/
с полем _tab= для определения какие ключи обновлять.
Все изменения пишутся в AuditOperations через write_audit(table_name='LK_SETTINGS').
После сохранения 60-секундный кеш lk_brand context_processor инвалидируется автоматически.
Последние входы и каналы
На вкладке «Обзор» добавлены два аналитических блока:
- Последние 10 входов в ЛК — таблица с колонками: время / логин / IP / канал
(Web/Android/iOS/прочие, цветной бейдж) / метод (пароль/VK/Telegram/JWT). Источник —
AuditOperationsсtable_name='LK_LOGIN_SUCCESS'. Кнопка «Все» ведёт в полный журнал аудита. - Круговая диаграмма каналов входа за 30 дней — Chart.js doughnut, 4 сегмента (Web/Android/iOS/прочие). Tooltip показывает абсолютное число и процент. Под диаграммой — легенда с точными значениями. Если за 30 дней нет данных — empty-state.
Audit-запись успешного входа создаётся во всех 4 точках авторизации:
lk/views/auth.py::_record_successful_login()— для пароля и Telegramlk/views/oauth.py::vk_callback()— для VK OAuthmobile_api/views/auth.py::login_view()— для Mobile JWT
Канал определяется хелпером _detect_lk_channel(user_agent) по User-Agent:
UA smit_billing_app/X.Y.Z (мобильное приложение) → android
или ios в зависимости от платформенных маркеров; iPhone/iPad UA → ios;
Android browser → android; Mozilla/Chrome/Safari/Firefox/Edge → web;
иначе unknown.
Брендинг
На вкладке выводится read-only сводка из CompanyBranding
(логотип, название, цвет, юр. реквизиты) с CTA-кнопкой
«Изменить брендинг компании» ведущей в общие настройки
/admin/settings/system/?tab=branding. Логотип/реквизиты не дублируются —
единая точка правды.
LK-overrides (9 полей):
LK_BRAND_SHORT— короткое имя бренда (для мобилы)LK_SUPPORT_PHONE/LK_SUPPORT_EMAIL/LK_SUPPORT_URL/LK_SUPPORT_HOURS— контакты поддержки (если пусто, fallback кCompanyBranding.phone/email/website)LK_SOCIAL_VK/LK_SOCIAL_MAX— соцсети (только VK и MAX мессенджер — российские сервисы)LK_USE_BRAND_COLORS(toggle) — если выключено, использоватьLK_PRIMARY_COLOR(color picker) вместоCompanyBranding.accent_color- Способы входа:
LK_AUTH_VK_ENABLEDиLK_AUTH_TELEGRAM_ENABLED— toggle для кнопок «Войти через VK» / Telegram-widget на странице логина. Если выключены — кнопки скрываются, а прямой переход на/lk/auth/vk/и Telegram-callback возвращают «временно отключено». - Фон страницы логина:
LK_LOGIN_BG_DESKTOP(1920×1080) иLK_LOGIN_BG_MOBILE(1080×1920) — URL фоновых изображений. На экранах ≤768px используется mobile-вариант, если задан (иначе — desktop). Поверх фона накладывается полупрозрачный белый/тёмный градиент (35% / 45%) для контраста, в dark-mode градиент тёмнее. - Frosted-glass card:
.login-card .cardполучаетbackdrop-filter: blur(18px) saturate(180%)+ полупрозрачный фонrgba(255,255,255,.65)+ edge-light shadow. В dark-mode карточка становитсяrgba(28,30,36,.65). Для браузеров без поддержкиbackdrop-filterприменяется fallback с непрозрачным фоном через@supports.
В правой колонке — iframe-превью /lk/login/ (sticky-top), перезагружается после каждого save.
Функции (feature flags)
12 toggle-switches скрывают/показывают модули в ЛК и мобильном приложении:
LK_FEATURE_IPTV,LK_FEATURE_CHAT_AI,LK_FEATURE_VOLUNTARY_BLOCK,LK_FEATURE_PROMISE_PAYLK_FEATURE_TARIFF_CHANGE,LK_FEATURE_SESSIONS_HISTORY,LK_FEATURE_PAYMENT_HISTORYLK_FEATURE_PAPER_INVOICE,LK_FEATURE_IPV6,LK_FEATURE_SPEED_TESTLK_FEATURE_REFERRAL,LK_FEATURE_BALANCE_HISTORY_CHART
Применение мгновенное: lk_features context_processor (60-сек кеш) подставляет
флаги во все шаблоны ЛК. В sidebar пункты обёрнуты в
{% if lk_features.X %}…{% endif %}. Mobile API возвращает флаги в
GET /mobile-api/v1/features.
«Только Mobile» бейдж: 4 флага
(LK_FEATURE_IPTV, LK_FEATURE_PAPER_INVOICE,
LK_FEATURE_IPV6, LK_FEATURE_BALANCE_HISTORY_CHART) в текущей
версии веб-ЛК не имеют читателей в lk/templates/lk/base.html — они
реализованы только в Mobile App через GET /mobile-api/v1/features. В админке
эти 4 toggle отмечены синим бейджем «только Mobile» чтобы оператор не ожидал эффекта в
веб-кабинете. Если потребуется — добавить
{% if lk_features.iptv %}…{% endif %} блоки в шаблоны ЛК.
Promise Pay management — 5 числовых ключей в Features tab,
реализуют политики доступности обещанного платежа в
lk/views/promise_pay.py::_check_promise_pay_eligibility():
LK_PROMISE_PAY_MIN_DEBT(₽) — минимальная задолженность для активации.0= ОП доступен при любом отрицательном балансеLK_PROMISE_PAY_MAX_DURATION_DAYS— override длительности изUsluga.end_count_days.0= брать из услугиLK_PROMISE_PAY_COOLDOWN_DAYS— минимальный интервал между двумя ОП. Считается отpromise_date_endпредыдущего ОП.0= без кулдаунаLK_PROMISE_PAY_MIN_AGE_DAYS— минимальный возраст абонента (now() − create_date). Защита от фрод-сценария «новый абонент сразу активирует ОП и пропадает»LK_PROMISE_PAY_MAX_LIMIT_OVERRIDE(₽) — фиксированный максимальный лимит ОП.0= берётся стоимость тарифа в месяц (динамически)
При нарушении любой из политик возвращается понятное сообщение
(«Между двумя обещанными платежами должно пройти 30 дней (подождите ещё 12 дн.)»),
и кнопка активации становится disabled.
Аналогичные проверки в mobile_api/views/finance.py::promise_pay() через
reuse того же хелпера — реакция API: HTTP 400 с
{"detail": "...", "eligibility_error": "..."}.
Phantom-cleanup: из Security tab удалены 10 ключей которые
раньше отображались как настройки, но не имели читателя в коде:
LK_AUTH_METHOD, LK_AUTH_OTP_LENGTH/_TTL_SECONDS,
LK_LOGIN_CAPTCHA_AFTER, LK_PASSWORD_HISTORY_CHECK,
LK_PASSWORD_EXPIRY_DAYS, LK_SESSION_TTL_MINUTES/_IDLE_LOGOUT/_SINGLE_DEVICE,
LK_TOTP_REQUIRED_FOR_PAYMENT_ABOVE. Это были «фантомные» настройки —
UI создавал ощущение что они работают, на деле — нет. Будут добавлены обратно
вместе с реальной реализацией.
Push-настройки — теперь подключены в
billing/tasks/push_notifications.py:
MOBILE_PUSH_LOW_BALANCE_THRESHOLD— порог в рублях дляsend_low_balance_alerts(раньше был хардкод100)MOBILE_PUSH_PROMISE_PAY_EXPIRE_HOURS— окно «отправлять предупреждение за N часов до истечения ОП» вsend_promise_pay_expiring_alerts(раньше — фиксированно «завтра»)MOBILE_PUSH_QUIET_HOURS_START / _END— пуши не уходят в этот период. Корректно обрабатывается случай через полночь (22:00–08:00). Все three task (low_balance / promise_expiring / send_to_abonent) уважают ихMOBILE_PUSH_MAX_PER_DAY— счётчик пушей на абонента в Redis-кеше (push:daily:{ab_id}:{date}с TTL 25h). При превышении — пуш не уходит, пишется debug-лог.0= лимит отключён
Срочные broadcast-уведомления (авария) могут передавать
respect_quiet=False и пройти через quiet-hours.
send_push_to_abonent(force=True) игнорирует и quiet-hours, и daily-limit.
Sprint B — реализация legacy LK-флагов
В 12 LK-настроек были мигрированы из VpnConst в SystemSettings,
но в коде ЛК ещё не подключены — на UI они отображались с warning-бейджем «будет реализовано».
В все они подключены и переведены в статус «работает».
| Флаг | Где реализовано |
|---|---|
LK_SHOW_SERVICES | sidebar в base.html + новый раздел
/lk/services/ (lk/views/services.py) с каталогом услуг и формами
connect/disconnect |
LK_SHOW_AUDIT | sidebar в base.html + новый раздел
/lk/audit/ — FinanceOperations за 12 мес с KPI поступления/списания |
LK_SHOW_HELPDESK | условный show пункта «Поддержка» в sidebar |
LK_SHOW_DETAILED_TRAFFIC | sessions.html: переключение
между in/out (детально) и компактным total_bytes |
LK_HIDE_TARIFF_SPEED | dashboard.html: скрытие Мбит/с
в карточке тарифа |
LK_HIDE_TARIFF_TAB | скрытие пункта «Тарифы» в sidebar (запрет смены) |
LK_HIDE_PAYMENT_TAB | скрытие пунктов «Платежи» и «Оплатить» в sidebar |
LK_ALLOW_MAC_CHANGE | card в profile.html + action
change_mac в lk/views/profile.py с валидацией формата
AA:BB:CC:DD:EE:FF и audit LK_MAC_CHANGE |
LK_TARIFF_REQUIRE_RANGE | фильтр в lk/views/tariff.py:
при смене тарифа предлагаются только тарифы с тем же usluga_range_type_id |
LK_REQUIRE_SAME_IP | LkAuthMiddleware сохраняет IP
в session['lk_login_ip'] при логине и завершает сессию при смене IP
(с redirect на /lk/login/) |
LK_AUTOLOGIN_BY_IP | LkAuthMiddleware: если пользователь
не залогинен и ровно один Users с ip=client_ip и
enabled=True — автоматический вход. Public-paths
(/lk/login, /lk/auth/, webhook'и) исключены. Audit
LK_LOGIN_SUCCESS с method=autologin_ip |
LK_DISABLE_PASSWORD_CHANGE | change_password()
возвращает redirect с error на dashboard; пункт «Сменить пароль» скрыт в sidebar |
Раздел «Услуги абонента» (/lk/services/)
Новый раздел в ЛК для управления подключёнными услугами. Использует 5 ранее не
подключённых полей Usluga:
is_show_web— фильтр каталога доступных услугweb_check_overlimit— проверка баланса перед подключениемweb_allow_disable— кнопка «Отключить» в списке подключённыхallow_off_month_web— минимальный срок (мес.) до возможности отключения (используетсяdateutil.relativedelta)zakaz_msg— сообщение во flash-нотификации после успешного подключения (если пусто — дефолт «Услуга подключена»)
Audit LK_SERVICE_CONNECT и LK_SERVICE_DISCONNECT при каждой
операции. Excludes услуг с system_type=11 (это обещанный платёж — управляется
отдельно).
Legacy LK-настройки (мигрированы, реализованы) — 9 toggle, отображаются ниже основных feature-toggle во вкладке «Функции»:
- Видимость разделов в ЛК:
LK_SHOW_SERVICES,LK_SHOW_AUDIT,LK_SHOW_HELPDESK,LK_SHOW_DETAILED_TRAFFIC— показывать раздел Услуги / История операций / Help Desk / детальный трафик соответственно - Скрыть в ЛК:
LK_HIDE_TARIFF_SPEED(скорость в карточке тарифа),LK_HIDE_TARIFF_TAB(вкладка «Тариф» — запрет смены тарифа),LK_HIDE_PAYMENT_TAB(вкладка «Оплата» — для систем со сторонней оплатой) - Поведение тарифов и услуг:
LK_ALLOW_MAC_CHANGE(разрешить абоненту менять MAC-адрес через ЛК),LK_TARIFF_REQUIRE_RANGE(предлагать только тарифы из той же линейки услуг) - Уведомления:
LK_HELPDESK_NOTIFY_GROUP_ID(целое число — ID Django-группы получателей уведомлений о новых заявках Help Desk;0= отключить)
Безопасность
16 настроек на 4 секции:
- Метод авторизации:
auto/contract+phone/email+password/phone+sms_otp+ длина OTP + TTL OTP - Защита от перебора:
LK_LOGIN_MAX_ATTEMPTS(default 5),LK_LOGIN_LOCKOUT_MINUTES(default 15),LK_LOGIN_CAPTCHA_AFTER - Пароль абонента:
LK_PASSWORD_MIN_LENGTH,LK_PASSWORD_REQUIRE_DIGIT,LK_PASSWORD_REQUIRE_LETTER,LK_PASSWORD_REQUIRE_SPECIAL,LK_PASSWORD_HISTORY_CHECK,LK_PASSWORD_EXPIRY_DAYS - Сессия ЛК:
LK_SESSION_TTL_MINUTES(default 14 дней), idle logout, single-device toggle - 2FA + audit:
LK_TOTP_REQUIRED_FOR_PAYMENT_ABOVE(порог в ₽),LK_AUDIT_LOGIN_FAILURES,LK_AUDIT_PASSWORD_CHANGES
Lockout фактически работает в lk/views/auth.py::login_view: per-login + per-IP keying в Redis-cache, окно отслеживания =
lockout_minutes × 2. После исчерпания попыток — все логины с этого IP+login получают
«Слишком много неудачных попыток. Попробуйте через N мин», audit-запись
LK_LOGIN_LOCKOUT.
Legacy LK-настройки безопасности — 3 дополнительных переключателя, мигрированы из старого раздела «Настройки системы»:
LK_REQUIRE_SAME_IP— после входа доступ в ЛК разрешён только с того же IP-адреса. Если абонент сменил сеть — сессия закроется. Только для локальных сетейLK_AUTOLOGIN_BY_IP— автоматический вход в ЛК по IP-адресу без логина и пароля. Только для доверенных сегментов сетиLK_DISABLE_PASSWORD_CHANGE— раздел «Сменить пароль» в ЛК скрыт. Используется когда пароли управляются администратором
Мобильное (Android + iOS, force-update)
Двухколоночный layout: Android | iOS. Параллельные настройки:
MOBILE_ANDROID_CURRENT_VERSION/MOBILE_ANDROID_MIN_VERSION/MOBILE_FORCE_UPDATE_URL_ANDROIDMOBILE_IOS_CURRENT_VERSION/MOBILE_IOS_MIN_VERSION/MOBILE_FORCE_UPDATE_URL_IOSMOBILE_IOS_DISTRIBUTION— переключательtestflight↔appstore. После релиза приложения в App Store оператор переключает в UI без деплоя — Mobile API сам начнёт отдавать App Store URL.
Общие настройки (применяются к обеим платформам):
- Тексты диалогов force/soft-update
- Push:
MOBILE_PUSH_LOW_BALANCE_THRESHOLD,MOBILE_PUSH_PROMISE_PAY_EXPIRE_HOURS,MOBILE_PUSH_QUIET_HOURS_START/END,MOBILE_PUSH_MAX_PER_DAY - Mobile features:
MOBILE_BIOMETRY_ENABLED(Touch ID / Face ID),MOBILE_OFFLINE_MODE,MOBILE_DARK_THEME_DEFAULT
На вкладке есть тест-кнопка «Превью force-update» —
POST /admin/settings/lk/mobile/preview_force_update/
принимает platform=android|ios&version=X.Y.Z и показывает
JSON-ответ как для мобилки. Удобно проверить что
must_update=true срабатывает для нужных версий.
Авторизация
Поддерживается три способа входа:
- Логин / пароль — из поля
LOGIN/PSWтаблицы Users биллинга - Telegram OAuth — кнопка «Войти через Telegram» (Telegram Login Widget). Требует привязанного
telegram_chat_idили первичной авторизации через бот - VK OAuth — вход через аккаунт ВКонтакте (требует настройки VK App)
Telegram Login Widget требует регистрации домена в BotFather: /setdomain → укажите домен сайта (например, billing.example.com).
Настройки интеграций
Все параметры интеграций настраиваются через панель управления без необходимости редактирования файлов.
Настройки хранятся в базе данных (таблица system_settings) с Redis-кэшированием (5 мин). Изменения применяются мгновенно без перезапуска сервера.
Страницы настроек
| Раздел | URL | Параметры |
|---|---|---|
| Telegram | /admin/settings/integrations/?tab=telegram | Bot token, username, webhook secret |
| VK | /admin/settings/integrations/?tab=vk | App ID, secret key, community token |
| FreeScout | /admin/settings/integrations/?tab=freescout | URL, API key, mailbox ID |
| AIDA AI | /admin/settings/integrations/?tab=aida | URL, API key, LK/Mobile/Monitor toggles |
| TVIP Media | /admin/settings/integrations/?tab=tvip | URL, login/password, provider ID |
| LFStream | /admin/settings/integrations/?tab=lfstream | URL, login/password |
| Платежи | /admin/settings/payment/ | YooKassa/W1 credentials, commission |
| Email/SMS | /admin/settings/messaging/ | SMTP, SMSAero, sender name |
| Firebase | /admin/settings/messaging/?tab=firebase | Firebase credentials path |
| IPTV-пакеты | /admin/settings/iptv_mappings/ | Маппинг услуг на ТВ-пакеты |
| API Адреса | /admin/settings/integrations/?tab=address_api | Публичный API автоподсказок и проверки покрытия |
API проверки адреса
Публичный API для сайта провайдера — автоподсказки адресов и проверка возможности подключения. Не требует авторизации, поддерживает CORS.
GET /api/address/suggest/?q=Ленина— возвращает до 15 совпадений из базы адресовGET /api/address/check/?id=855или?q=текст— проверка покрытия:connected/coverage/unknown
Настройки: вкладка API Адреса на странице интеграций. Включает: лимит результатов, разрешённые домены CORS, настройки AI-ассистента для автоматической проверки адресов.
JS-виджет для подключения на сайте: /static/js/address_widget.js. Подробная документация: Разработка → Документация → API адреса интеграция.
Миграция с .env
При обновлении с предыдущей версии выполните одноразовый перенос настроек из .env в базу данных:
docker compose exec web python manage.py migrate_env_to_db
Команда безопасна для повторного запуска — создаёт только отсутствующие ключи.
DB_*, REDIS_URL, SECRET_KEY, DEBUG) по-прежнему задаются в .env файле. В панель вынесены только настройки интеграций и платежей.
Telegram-бот для уведомлений
Бот используется для двух целей: OAuth-авторизация в ЛК и push-уведомления абоненту (списание, пополнение, блокировка).
Создание бота:
- Написать
@BotFatherв Telegram /newbot— создать бота, получить токен/setdomain→ указать домен сайта (для Login Widget)- Прописать токен в Настройки → Интеграции → Telegram
Регистрация вебхука:
docker compose exec web python manage.py setup_telegram_webhook \
--url https://billing.example.com/lk/telegram/webhook/
# Проверка:
docker compose exec web python manage.py setup_telegram_webhook --info
Как абонент привязывает Telegram:
- В ЛК → Профиль → блок «Уведомления в Telegram» → кнопка «Привязать»
- ЛК генерирует одноразовый токен (действует 10 минут) и показывает ссылку вида
https://t.me/BotName?start=TOKEN - Абонент переходит в бот, отправляет
/start TOKEN - Бот сохраняет
telegram_chat_idв профиль абонента - После привязки уведомления отправляются автоматически через Celery-задачи
Telegram-бот для операторов (admin bot)
Отдельный бот для технического персонала оператора. Позволяет управлять абонентами, мониторить NAS и выполнять экстренные операции прямо из Telegram — без доступа к веб-интерфейсу.
Настройка
- Создать бота через
@BotFather→/newbot - Прописать токен в Настройки → Интеграции → Telegram
- Добавить администратора в блок Администраторы бота — по Telegram ID или @username. Бот отобразит аватарку, имя и ссылку на профиль
- Указать Chat ID и Thread ID (топик) супергруппы для алармов
- Зарегистрировать webhook кнопкой «Зарег. webhook» или командой:
docker compose exec web python manage.py setup_telegram_webhook --url https://yourdomain.ru/lk/telegram/webhook/
Команды диагностики
| Команда | Описание |
|---|---|
/billdiag | Полный диагностический отчёт: состояние сервисов (PostgreSQL, Redis, FreeRADIUS, Celery), метрики БД (размер, соединения, медленные запросы), NAS (онлайн/оффлайн), абоненты (активные, RADIUS-ready, онлайн) |
/stats | Сводная статистика: всего абонентов, активных, онлайн, тарифов, NAS, должников |
/debtors | Должники: количество абонентов с отрицательным балансом и суммарный долг |
/revenue [today|week|month] | Выручка за период (сумма входящих платежей). Без параметра — за текущий месяц |
Управление абонентами
| Команда | Описание |
|---|---|
/find <запрос> | Поиск абонента по имени, логину, номеру договора или IP-адресу. Возвращает до 5 результатов с ID, именем, балансом и статусом |
/balance <id> | Детальная карточка абонента: баланс, тариф, статус (активен/заблокирован), логин, IP |
/block <id> [причина] | Заблокировать абонента (устанавливает флаг b_admin). Причина блокировки сохраняется в комментарии |
/unblock <id> | Разблокировать абонента (снимает все административные блокировки) |
/disconnect <id> | Принудительно отключить активную сессию абонента: сначала через RADIUS CoA Disconnect-Request, при неудаче — через SSH (для MikroTik) |
/pay <id> <сумма> | Зачислить платёж на счёт абонента. Создаёт запись в FinanceOperations и обновляет баланс |
Мониторинг NAS / Сеть
| Команда | Описание |
|---|---|
/nas | Список всех NAS с IP-адресами и количеством онлайн-абонентов из биллинга (USERS_RADIUSAUTH) |
/sessions <nas_id> | Активные PPPoE сессии на конкретном NAS (через SSH или MikroTik API): логин, IP, uptime |
/sync <nas_id> | Принудительная синхронизация сессий NAS ↔ биллинг: сравнивает онлайн-пользователей, отключает «призраков», обновляет статусы |
Экстренные операции
| Команда | Описание |
|---|---|
/logs <service> [N] | Последние N строк лога контейнера. Сервисы: web, celery, radius, beat, db. По умолчанию 20 строк |
/restart radius | Перезапуск контейнера app-freeradius-1 (регенерация clients.conf из таблицы NAS) |
/restart celery | Перезапуск Celery workers (app-celery-1) |
/broadcast "<текст>" | Массовая рассылка сообщения всем активным абонентам через все доступные каналы (SMS, Email, Telegram) |
Алармы (автоматические уведомления)
Система автоматически отправляет алармы в супергруппу (Chat ID + Thread ID) при следующих событиях:
| Событие | Триггер | Настройка |
|---|---|---|
| NAS offline | NAS не отвечает на ping (TCP-connect) | NAS offline ✓ |
| RADIUS ошибка | Исключение в authorize() или accounting() | RADIUS ✓ |
| Медленные запросы БД | PostgreSQL: запрос выполняется >10 сек | SQL ✓ |
| Сервис упал | PostgreSQL / Redis недоступны | Сервисы ✓ |
| Проблемы синхронизации | Много «призраков» или рассинхрон >порога | NAS sync ✓ |
Уведомления о документах разработки
Бот автоматически отправляет уведомления в настроенные чаты при появлении новых .md-файлов в папке dev_reports/. Настройка выполняется в Настройки → Интеграции → Telegram (/admin/settings/integrations/?tab=telegram):
- Per-chat — для каждого чата (супергруппа или личный чат) можно включить/выключить уведомления о документах
- Per-folder — выбор папок (Документация, Отчёты, Планы, пользовательские), о новых файлах в которых будет приходить уведомление
- Ответы на комментарии — если у пользователя привязан
telegram_chat_id, он получит уведомление в личный Telegram при ответе на его комментарий в разделе Разработка и логи
Прокси для Telegram
Если сервер находится в России, прямой доступ к api.telegram.org может быть заблокирован. Настройте SOCKS5-прокси в Настройки → Интеграции → Telegram → Прокси. Система использует socks5h (DNS через прокси) для корректной работы.
# Проверка прокси вручную
curl -x socks5h://user:pass@proxy_host:port https://api.telegram.org
Оплата через YooKassa
Абоненты могут пополнять счёт банковской картой через YooKassa (бывший ЮMoney Business). Оплата доступна из личного кабинета на сайте и из мобильного приложения.
Поддерживаемые протоколы
Система автоматически определяет протокол по формату секретного ключа:
| Протокол | Формат ключа | Описание |
|---|---|---|
| REST API v3 (рекомендуется) | Начинается с live_ или test_ | Современный протокол. Создание платежа через JSON API, webhook — JSON. |
| HTTP-протокол (старый) | Любой другой (например, SmitSecretKey) | Старый Yandex.Kassa. Форма POST на yoomoney.ru/eshop.xml, webhook — XML с MD5. |
Настройка через админ-панель
Перейдите в Настройки → Настройки ЮKassa (/admin/settings/payment/). На странице можно:
- Указать
shopId,scidи секретный ключ - Задать URL-ы возврата после оплаты (shopSuccessURL, shopFailURL)
- Скопировать webhook-адрес для настройки в кабинете ЮKassa
- Проверить подключение кнопкой «Проверить подключение»
Настройка вручную через .env
Переменные окружения для YooKassa:
| Переменная | Описание | Пример |
|---|---|---|
LK_YOOKASSA_SHOP_ID | ID магазина | 267304 |
LK_YOOKASSA_SECRET_KEY | Секретный ключ (REST API v3) или shopPassword (HTTP) | live_ABC... или SmitSecretKey |
LK_YOOKASSA_SCID | Номер витрины (только HTTP-протокол) | 2487841 |
LK_YOOKASSA_SUCCESS_URL | URL после успешной оплаты | https://billing.example.com/lk/payments/result/ |
LK_YOOKASSA_FAIL_URL | URL при ошибке оплаты | https://billing.example.com/lk/payments/result/?status=failure |
Webhook (уведомления об оплате)
В настройках магазина ЮKassa укажите URL для уведомлений:
# Для обоих протоколов (checkUrl, avisoUrl, HTTP-уведомления):
https://billing.example.com/lk/payments/webhook/
Webhook обрабатывает:
- HTTP-протокол:
checkOrder(проверка заказа) иpaymentAviso(зачисление). Ответ — XML с MD5-подписью. - REST API v3: JSON-уведомление
payment.succeeded. Зачисление поmetadata.abonent_id.
Как работает зачисление
- ЮKassa отправляет POST на webhook
- Система проверяет подпись (MD5 или JSON)
- Находит абонента по
customerNumber/metadata.abonent_id - Увеличивает баланс (
account.ostatok) - Создаёт запись в истории операций: «Онлайн-оплата (YooKassa)»
Мобильное приложение
Android-приложение «СмИТ Биллинг» для абонентов. Работает через Mobile API (/mobile-api/v1/).
Возможности приложения
- Главная — баланс, тариф, уведомление от оператора, последний платёж, статус блокировки
- Финансы — история операций (фильтр по периоду), итоги (приход/расход), обещанный платёж, оплата через ЮKassa
- Поддержка — список обращений (активные/закрытые), создание нового тикета через FreeScout
- Профиль — контактные данные, привязка VK/Telegram, выход
Оплата в приложении
При нажатии «Пополнить» приложение вызывает POST /mobile-api/v1/finance/pay. Ответ содержит URL платёжной страницы — приложение открывает его в браузере. После оплаты баланс обновляется автоматически.
Mobile API
Авторизация: JWT (simplejwt). Эндпоинты:
| Метод | URL | Описание |
|---|---|---|
| POST | /mobile-api/v1/auth/login | Авторизация (contract + password → JWT) |
| POST | /mobile-api/v1/auth/refresh | Обновление токена |
| GET | /mobile-api/v1/account/status | Баланс, тариф, блокировки, уведомление, последний платёж |
| GET | /mobile-api/v1/account/tariffs | Доступные тарифы |
| POST | /mobile-api/v1/account/tariff | Смена тарифа |
| GET | /mobile-api/v1/finance/history | История платежей (фильтр, пагинация) |
| POST | /mobile-api/v1/finance/pay | Создание платежа (YooKassa) |
| GET/POST/DELETE | /mobile-api/v1/finance/promise_pay | Обещанный платёж |
| GET/POST | /mobile-api/v1/support/tickets | Тикеты (список + создание) |
| POST | /mobile-api/v1/push/register | Регистрация FCM/APNS токена |
Public Mobile API
Три новых публичных эндпоинта без auth для конфига приложения при старте. Кэшируются на стороне клиента 5 мин (Cache-Control header).
| Метод | URL | Описание |
|---|---|---|
| GET | /mobile-api/v1/branding |
Снимок брендинга: logo, colors, name, support contacts, social (VK/MAX), legal (ИНН/КПП/адрес).
Источник: CompanyBranding + LK-overrides. |
| GET | /mobile-api/v1/features |
Feature flags (12 LK + 3 mobile-only): iptv, chat_ai, voluntary_block, promise_pay, tariff_change, sessions_history, payment_history, paper_invoice, ipv6, speed_test, referral, balance_history_chart, biometry, offline_mode, dark_theme_default. |
| GET | /mobile-api/v1/version/check?platform=android|ios&version=X.Y.Z |
Force/soft-update check. Возвращает must_update, should_update,
store_url, title, text. Для iOS дополнительно
distribution: testflight|appstore. |
Эти endpoints вызываются Flutter-приложением при старте, чтобы:
- Применить актуальный
primary_colorк Theme - Обновить контакты поддержки в Profile-tab без релиза приложения
- Скрыть/показать табы по feature flags
- Показать force-update диалог если установленная версия < min
Force-update механизм
При запуске Flutter-приложения вызывает GET /mobile-api/v1/version/check:
must_update=true— установленная версия <MOBILE_{ANDROID|IOS}_MIN_VERSION. Показывается blocking-диалог «Требуется обновление» (текст изMOBILE_FORCE_UPDATE_TITLE+MOBILE_FORCE_UPDATE_TEXT) с CTA в стор. Пользователь не может пользоваться приложением до обновления.should_update=true— версия старше N дней (изMOBILE_SOFT_UPDATE_THRESHOLD_DAYS) или < current. Показывается non-blocking баннер «Доступна новая версия» с кнопками «Обновить»/«Позже».- Иначе — current = installed, обновлять не нужно.
Семвер-сравнение делается через split('.') и числовой compare. Robust к мусорным значениям —
при ошибках возвращает [0,0,0].
iOS: TestFlight ↔ App Store
iOS-приложение проходит несколько стадий релиза:
- TestFlight (beta): пока приложение не в App Store —
MOBILE_FORCE_UPDATE_URL_IOSведёт наtestflight.apple.com/join/...,MOBILE_IOS_DISTRIBUTION=testflight. На вкладке Мобильное жёлтый бейдж «TestFlight (beta)». - App Store (production): после релиза оператор:
- Меняет URL на
https://apps.apple.com/app/... - Переключает
MOBILE_IOS_DISTRIBUTIONнаappstore - Вкладка показывает зелёный бейдж «App Store (production)»
- Меняет URL на
Никакой пересборки биллинга не требуется. Mobile API сразу начинает отдавать новую информацию,
Flutter-клиенты подхватывают её при следующем version/check запросе.
Поддержка через FreeScout
Абоненты могут создавать обращения и переписываться с операторами прямо из ЛК. Для работы требуется настроенная интеграция с FreeScout (см. раздел 4.3).
Возможности раздела поддержки в ЛК:
- Вкладки «Открытые» и «Закрытые» — с бейджами-счётчиками количества обращений
- Даты в формате «5 часов назад», «3 дня назад», «2 недели назад»
- Статус-точки на мобильных: красная — ждёт ответа оператора, зелёная — получен ответ, серая — закрыто
- Создание нового обращения с темой, описанием и вложениями (до 20 МБ, форматы: jpg/png/gif/webp/pdf)
- Переписка в рамках существующего обращения
- Закрытие обращения из ЛК
- Оценка качества обслуживания (если выставлена оператором)
AI-ассистент (Claude / AIDA)
Встроенный чат с AI-ассистентом. Основной провайдер — Claude (Anthropic); при отсутствии ключа автоматически используется резервный провайдер AIDA. Отвечает на вопросы абонента о балансе, тарифе, оплате и технических проблемах. При невозможности помочь — автоматически передаёт вопрос оператору.
Возможности AI-чата:
- Мгновенные ответы на типовые вопросы (баланс, тариф, обещанный платёж)
- Отправка изображений и PDF-файлов (до 5 файлов, 10 МБ каждый)
- Превью файлов прямо в чате (миниатюры изображений, иконки PDF)
- На мобильных устройствах — полноэкранный режим
- Автоматическая эскалация на оператора при необходимости (код
ESCALATE_TO_HUMAN) - История переписки сохраняется в течение сессии (24 часа)
| Провайдер | Переменная .env | Условие |
|---|---|---|
| Claude (Anthropic) | ANTHROPIC_API_KEY | Используется при наличии ключа (основной) |
| AIDA | AIDA_API_URL + AIDA_API_KEY | Резервный — при отсутствии Claude-ключа |
.env задайте ANTHROPIC_API_KEY. Claude API-запросы проходят через прокси из настроек Telegram (TELEGRAM_PROXY_HOST/PORT) — это необходимо, так как api.anthropic.com заблокирован с российских IP-адресов.
Профиль абонента
В разделе «Профиль» абонент может:
- Изменить отображаемое имя и email
- Сменить пароль
- Просмотреть активные сессии (IP, время входа, устройство)
- Завершить все сессии кроме текущей
- Привязать / отвязать Telegram для уведомлений
- Настроить вход через Telegram (OAuth) — если домен прописан в BotFather
Развёртывание и SSL
ЛК входит в тот же Docker Compose проект, что и биллинг — отдельная установка не требуется. Nginx проксирует запросы:
/lk/→ gunicorn (Django)/lk/static/→ whitenoise / static files
SSL-сертификат для домена биллинга автоматически покрывает и ЛК. Если ЛК работает на отдельном поддомене — выпустить сертификат через certbot:
certbot --nginx -d lk.example.com
Для PWA-режима обязателен HTTPS. После перехода на HTTPS абоненты могут добавить ЛК на рабочий стол смартфона как приложение.
Firebase Push-уведомления
Push-уведомления для мобильного приложения (Android и iOS) реализованы через Firebase Cloud Messaging (FCM). Настройка в административном разделе Настройки → Интеграции → Firebase (/admin/settings/firebase/).
Настройка Firebase
- Откройте Firebase Console → «Настройки проекта» → «Аккаунты служб»
- Нажмите «Создать закрытый ключ» — скачается JSON-файл сервисного аккаунта
- Укажите путь к этому файлу в поле Service Account JSON
Регистрация токена (Mobile API)
Мобильное приложение регистрирует FCM/APNS-токен при запуске:
POST /mobile-api/v1/push/register
Content-Type: application/json
{
"token": "fcm_device_token_here",
"platform": "android" // или "ios"
}
Автоматические задачи (Celery beat)
| Задача | Расписание | Описание |
|---|---|---|
push-low-balance |
Ежедневно | Уведомляет абонентов с низким балансом (low_balance_alerts) |
push-promise-expiring |
Ежедневно | Напоминает об истечении обещанного платежа (promise_pay_expiring) |
Ручная отправка
Доступны также функции разовой отправки:
broadcast— массовая рассылка всем активным абонентам с токенамиsend_to_abonent— отправка конкретному абоненту (из карточки абонента через форму «Отправить сообщение»)
Исходный код задач: billing/tasks/push_notifications.py
Claude AI — конфигурация AI-ассистента
Управление параметрами AI-ассистента: Настройки → Интеграции (/admin/settings/integrations/) — вкладка AIDA / AI.
Переменные окружения (.env)
| Переменная | Описание |
|---|---|
ANTHROPIC_API_KEY | API-ключ Claude (Anthropic). При наличии — используется как основной провайдер. |
AIDA_API_URL | URL эндпоинта AIDA (резервный провайдер) |
AIDA_API_KEY | API-ключ AIDA |
TELEGRAM_PROXY_HOST | Хост прокси-сервера для Claude API |
TELEGRAM_PROXY_PORT | Порт прокси-сервера |
TELEGRAM_PROXY_LOGIN | Логин прокси (если требует аутентификации) |
TELEGRAM_PROXY_PASSWORD | Пароль прокси |
api.anthropic.com не имеет IPv4-записей и недоступен из России напрямую. Docker-контейнер не может маршрутизировать IPv6-трафик без настройки. Прокси (например, Telegram-прокси) решает эту проблему.
Переключатели в панели управления
| Настройка | Описание |
|---|---|
| AI в личном кабинете | Включить/выключить AI-чат на странице /lk/chat/ |
| AI в мобильном приложении | Включить/выключить чат в Mobile API (/mobile-api/v1/chat/message) |
| Мониторинг биллинга | Разрешить AIDA/Claude обращаться к данным абонентов через REST API |
Эндпоинты чата
| URL | Описание |
|---|---|
GET /lk/chat/ | Страница чата в личном кабинете |
POST /mobile-api/v1/chat/message | Отправить сообщение AI (Mobile API) |
POST /mobile-api/v1/chat/escalate | Передать переписку оператору FreeScout |
GET /mobile-api/v1/chat/status | Проверить доступность AI |
Логирование
Модуль billing/services/claude_logger.py записывает диалоги в FreeScout (отдельная база MySQL на сервере поддержки) и параллельно — в локальную PostgreSQL-таблицу ai_chat_log биллинга. Если один из источников недоступен — логирование во второй проходит без ошибки.
AI-ассистент — обучение и управление промптом (build 603-607)
Раздел Настройки → AI-ассистент (/admin/settings/ai/) — единая точка управления системными промптами, эталонными примерами (few-shot) и автотестами AI-чата. Все три канала — Личный кабинет, Мобильное приложение и Email / FreeScout — настраиваются раздельно.
/admin/reports/dev/?file=Документация%2F2026-05-08_Инструкция_обучение_Claude_агента_поддержки.md.
Вкладка «Промпт»
Редактирование system prompt с версионированием и откатом. Поддерживается prompt caching Anthropic — статическая часть кешируется на 5 минут, экономия до 90% на повторных запросах.
| Поле | Назначение |
|---|---|
| System prompt | Текст инструкции для Claude — стиль, правила, сценарии. Динамические данные клиента (имя, баланс, тариф) добавляются автоматически на каждый запрос. |
| Модель | Haiku 4.5 (по умолчанию — быстро и дёшево), Sonnet 4.6 (точнее), Opus 4.7 (лучшее качество) |
| Max tokens | Максимальная длина ответа (1024 для LK / 512 для Mobile) |
| Temperature | 0.0–1.0; для биллинга рекомендуется 0.3 (фактическая точность важнее креативности) |
| Ключевые слова эскалации | При наличии в сообщении клиента — пропуск AI-ответа, прямой переход к оператору |
| Prompt caching | Включает заголовок anthropic-beta: prompt-caching-2024-07-31 и кеширует статическую часть промпта |
История версий справа сохраняет последние 30 правок. Кнопка ↶ восстанавливает любую версию — текущая при этом тоже сохраняется в истории, можно вернуться обратно.
Вкладка «Few-shot»
Эталонные пары «сообщение клиента → идеальный ответ Алисы». Топ-8 по приоритету подмешиваются в статическую часть промпта — попадают в кеш, не пересчитываются на каждый запрос.
На канал LK при первом деплое сидируется 5 эталонных примеров (миграция 0126_ai_fewshot_seed): баланс положительный, баланс отрицательный, диагностика «нет интернета», явная эскалация, OOD-отказ (нерелевантные темы).
| Поле карточки | Назначение |
|---|---|
| Интент | Метка для группировки (balance / promise_pay / diag / escalation / ood) |
| Приоритет (0–100) | Цветовой бар; чем выше — тем чаще пример попадает в промпт |
| Сообщение клиента | Реальный (или гипотетический) запрос абонента |
| Эталонный ответ Алисы | Образцовая формулировка — длина, стиль, структура |
Вкладка «Eval»
Автотесты промпта на eval-датасете dev_reports/Документация/ai_eval_dataset.jsonl (58 кейсов в 14 категориях). Каждый кейс проверяется на must_contain, must_not_contain, корректную эскалацию и лимит слов.
Кнопка «Запустить» (с опциональным limit) дёргает реальный API синхронно — 30–60 секунд на полный прогон. После завершения история обновляется, видна pass rate с цветовым кодом: ≥90% зелёный, ≥75% оранжевый, ниже — красный.
CLI-вариант для cron / CI:
docker compose exec web python manage.py ai_eval \
--channel lk --note "after weekly review N"
Кнопка «Подробнее» на строке прогона открывает модал со всеми кейсами: ID, интент, сообщение, ответ AI, проваленные проверки, время выполнения, токены.
Дашборд AI-чата
Страница Отчёты → AI-чат: дашборд (/admin/reports/ai_chat_dashboard/) — KPI и графики по реальной нагрузке.
| KPI | Что показывает |
|---|---|
| Сессий | Уникальных диалогов за выбранный период (1/3/7/14/30 дней) |
| Помогло (👍) | Доля положительных оценок от всех проставленных |
| Не помогло (👎) | Доля негативных + общий процент сессий, в которых клиент поставил оценку |
| Эскалаций | Сколько сессий завершилось передачей оператору в FreeScout |
| Токены | Суммарный input/output расход на API за период |
Графики:
- Активность по дням — line chart сессий и эскалаций + bar chart 👍/👎
- По каналам — pie chart распределения сессий между LK / Mobile / Email
- Последние 👎 — клик по строке открывает модал с полным транскриптом сессии (для разбора и пополнения few-shot)
- Худшие eval-кейсы за период — какие тесты чаще всего падали (источник для правки промпта)
Telegram-алерты
Celery-задача ai-health-check запускается каждые 15 минут и проверяет показатели за последний час. Если escalation_pct ≥ 40% или down_feedback_pct ≥ 40% — отправляет алерт в Telegram-канал nas_down. Дедуп по severity и дате (один алерт на проблему в сутки).
Управляющие настройки в SystemSettings (категория ai):
| Ключ | Значение |
|---|---|
AI_HEALTH_TELEGRAM_ALERT | 1 = включено, 0 = выключено |
AI_ESCALATION_ALERT_PCT | Порог % эскалаций для алерта (по умолчанию 40) |
AI_DOWN_FEEDBACK_ALERT_PCT | Порог % 👎-оценок для алерта (по умолчанию 40) |
AI_HEALTH_MIN_SAMPLE | Минимальный размер выборки (по умолчанию 5) |
A/B-варианты промпта
Модель AIPromptVariant позволяет тестировать новые версии промпта на доле трафика. Сплит детерминированный: hash(channel:abonent.pk) % 100 — один абонент в одном канале всегда получает один и тот же вариант.
Создание варианта (через Django shell, UI пока не реализован):
from billing.models.ai import AIPromptVariant
AIPromptVariant.objects.create(
channel='lk', name='exp_v1', weight=30,
prompt='...новый вариант текста...',
model='claude-haiku-4-5-20251001',
max_tokens=1024, temperature=0.3,
enable_caching=True, is_active=True,
note='Тест нового сценария для негбала'
)
30% абонентов начнут получать exp_v1, остальные останутся на control. В ai_chat_log каждое сообщение помечено ab_variant — для аналитики через GROUP BY ab_variant можно сравнить escalation_pct, токены, 👍/👎 по группам.
Регламент использования
- Ежедневно (5 мин): открыть дашборд за сегодня → проверить эскалации и количество 👎.
- Еженедельно (30 мин): посмотреть 30 👎-сессий за неделю → пометить «правильный ответ» в формате few-shot → создать 5–10 новых записей или поправить промпт → запустить ai_eval — pass rate не должен упасть.
- При кардинальных изменениях: создать
AIPromptVariant(weight=30), дать поработать неделю, сверить метрики, раскатать на 100% или откатить.
Раздел «Интеграции» — единый центр
Страница /admin/settings/integrations/ — единая точка управления всеми внешними сервисами биллинга. После реструктуризации — 7 разделов вместо 11: связанные интеграции объединены в группы со sub-tabs и общими info-карточками.
Вкладка «Обзор»
Сводная таблица всех интеграций со статусами, KPI-карточками и кнопками «Проверить все» / «Остановить» / «Обновить статусы». Last-test, ссылки на документацию и шестерёнки для перехода в нужный раздел.
- Универсальный JS-модуль
billing/static/js/integration_tester.js—window.IntegrationTester.run()/runAll()/refreshStatus()/showToast() - Batch-тест прогоняет все configured интеграции последовательно (~5-10 сек) с прогресс-баром и summary-списком результатов
- Auto-poll каждые 60 сек обновляет статус-точки на вкладках без F5
- Backend-fallback: каждый
*_testendpoint читает settings из БД когда форма не открыта (для batch с Обзора)
Вкладка IPTV (TVIP + LFStream)
Объединяет двух IPTV-провайдеров. Sub-pills переключают между TVIP Media (middleware) и LFStream «Смотрёшка» (CMS). Info-карточка сверху — общий контекст и счётчики маппингов услуг.
Тесты используют production-клиенты billing/services/iptv/tvip.py::TvipClient и billing/services/iptv/lfstream.py::LfstreamClient с правильной авторизацией (HTTP Basic для TVIP, session-based через CMS /login + CSRF для LFStream).
Вкладка География (Адреса + Карта)
Геокодер DaData/Яндекс и тайловый слой карты абонентов. KPI-блок сверху: всего адресов, с координатами, точность дома, с абонентами.
- Sub-tab «Геокодер адресов» — DaData токен, лимиты, CORS-домены, AJAX-эндпоинты автоподсказок и проверки покрытия
- Sub-tab «Тайловый слой карты» — выбор провайдера: OpenStreetMap (бесплатно) / 2GIS / Яндекс.Карты
Вкладка FreeScout + Claude AI
HelpDesk-интеграция (FreeScout API + MySQL + webhook + автосинхронизация) и Claude AI-ассистент в одном разделе. Claude используется в трёх местах: ЛК-чат, мобильное приложение, FreeScout-модуль (отдельные настройки на support.smit34.ru/claudeai/settings).
Блок «Статистика» показывает количество AI-ответов сегодня (из FreeScout MySQL claudeai_messages) и ссылку на console.anthropic.com/billing для контроля баланса API.
AI-статус в футере
Футер всех страниц админки показывает живой статус AI после блока «Диск»:
Источник — server_load_api возвращает ai_status из IntegrationStatusCache (последний результат теста Claude) + ai_messages_today (cached 5 мин). Возможные значения:
| Знак | Значение |
|---|---|
| ✓ AI | Claude доступен (последний тест успешен) |
| ✗ AI | Claude отвечает с ошибкой |
| ⏸ AI | AI отключён в настройках |
| ? AI | Не настроен или ещё не тестировался |
Если в системе зафиксированы AI-ответы за сегодня — отображается «✓ AI: 12 сегодня». Tooltip показывает текст последнего теста.
Batch-тест всех интеграций
Кнопка «Проверить все» на Обзоре прогоняет последовательно все настроенные интеграции и выдаёт сводный отчёт:
Каждый тест получает зелёную/красную иконку, сообщение endpoint'а, обновление last-test в таблице ниже. Пропущенные «Не настроено»-интеграции выводятся в финальной строке summary.
Info-иконки
Каждый функциональный блок (карточка) имеет контурную серую info-иконку сразу после названия — клик открывает соответствующий раздел документации в новой вкладке. Реализовано через relocateInfoIcons() JS-функцию + MutationObserver для динамически добавленных блоков.
Test endpoints (для разработки)
| Slug | Endpoint | Что проверяет |
|---|---|---|
| telegram | POST /admin/settings/telegram/test/ | Bot token через getMe, опционально через прокси |
| telegram_proxy | POST /admin/settings/telegram/proxy_test/ | SOCKS5 прокси соединение с api.telegram.org |
| telegram_alarm | POST /admin/settings/telegram/alarm_test/ | Отправка тестового аларма в чат |
| freescout | POST /admin/settings/freescout/test/ | API-ключ + хост + список conversations |
| freescout_db | POST /admin/settings/freescout/db_test/ | MySQL соединение к БД FreeScout |
| aida | POST /admin/settings/aida/test/ | HTTP GET /health на AIDA URL |
| claude | POST /admin/settings/claude/test/ | Anthropic API /v1/messages (через прокси) |
| tvip | POST /admin/settings/tvip/test/ | TvipClient через /api/provider/accounts |
| lfstream | POST /admin/settings/lfstream/test/ | LfstreamClient через CMS-логин + /candidates/ |
| gcs | POST /admin/settings/gcs/test/ | list_blobs с object-level permission |
| address_api | POST /admin/settings/integrations/dadata_test/ | DaData API token + лимиты |
| status_json | GET /admin/settings/integrations/status_json/ | Все статусы (для auto-poll бейджей) |
JSON-формат ответа у всех test endpoints:
{
"ok": true|false,
"message": "Подключено. Тикетов: 50", // human-readable
"diag": { // опционально, для модалки расширенной диагностики
"url": "https://...",
"http_status": 200,
"latency_ms": 145,
"body_preview": "..."
}
}
История изменений
| Build | Дата | Изменения |
|---|---|---|
| 432 | 2026-04-25 | Sprint 1: статус-бейджи на вкладках, history теста, sticky-save (Telegram) |
| 463 | 2026-05-06 | Sprint A: integration_tester.js, кнопка «Проверить все», auto-refresh |
| 464 | 2026-05-06 | GCS test fix (object-level permission через list_blobs) |
| 465 | 2026-05-06 | Реструктуризация: TVIP+LFStream→IPTV, Адреса+Карта→География, Claude→FreeScout (variant A); AI в футере |
| 466 | 2026-05-06 | LFStream/TVIP test через production-клиенты; fallback на settings; контурные серые info-иконки рядом с названиями блоков |
Дизайн-система ЛК v489 — выравнивание со стилем админки
Build 489 переводит весь Личный Кабинет на единую дизайн-систему с админкой биллинга. До этого ЛК использовал собственный teal-брендинг #5BA89D и отдельный набор CSS-переменных (--lk-*) — это создавало визуальный разрыв при переключении между ЛК и админкой.
Токены дизайн-системы
В lk/templates/lk/base.html :root теперь содержит полный набор токенов админки (theme-smit.css):
| Категория | Токены | Источник правды |
|---|---|---|
| Brand | --brand-primary #43b77a, --brand-primary-dark, --brand-primary-bg | Совпадает с админкой |
| Status | --smit-state-{ok,warn,danger,info,muted} | Скопировано из админки |
| Surface | --surface-page #f5f6f8, --surface-card #fff, --surface-muted | Скопировано из админки |
| Border | --border-subtle, --border-default | Скопировано из админки |
| Text | --text-primary, --text-secondary, --text-muted | Скопировано из админки |
| Radii | --radius-{xs,sm,md,lg,pill} (3/4/6/8/999) | Скопировано из админки |
| Shadows | --shadow-{sm,md,lg} | Скопировано из админки |
| Spacing 8-pt | --space-{1..6} (4/8/12/16/24/32) | Скопировано из админки |
| Focus | --focus-ring rgba(67,183,122,.30), --focus-outline #43b77a | Скопировано из админки |
| Backwards-compat | --lk-bg, --lk-card-bg, --lk-text, --lk-muted, --lk-border | Алиасы на новые токены — старый код не сломан |
Для dark-темы ([data-bs-theme="dark"]) переопределены: surface, border, text, shadow — те же значения что в админском body.dark-theme.
Hero-карточки на всех ключевых страницах
Введён единый класс .lk-hero-card (lk/static/lk/css/lk-hero.css, ~190 строк) — gradient-карточка с иконкой/аватаром, title+meta+actions. Используется на:
- /lk/ (Дашборд) — карточка тарифа: описание, скорость in/out, линейка услуг, бейдж «N доступных вариантов апгрейда»
- /lk/profile/ — аватар-инициалы, статус (Активен/Заблокирован/ОП), баланс, осталось дней, бейджи «email/SMS/Telegram привязан»
- /lk/promise-pay/ — countdown «ещё N дней» + лимит + баланс для активного ОП; мотивирующая карточка для неактивного
- /lk/payments/ — последний платёж + баланс + monthly_cost + «хватит на N дней»
- /lk/tariff/ — все параметры текущего тарифа + 3-х колоночный grid доступных тарифов
Мобильная версия
В base.html добавлена секция @media (max-width: 767px):
- Touch targets ≥44px:
.btnmin-height 44px,.form-control44px (обновлено через единое правило, не inline) - Inputs 16px: предотвращает iOS auto-zoom при focus
- Компактнее padding:
.content-lk12px,.card-stat14px, типография уменьшена - Bottom-nav safe-area:
padding-bottom: env(safe-area-inset-bottom)для iPhone с home-indicator - Bottom-nav active state: brand-color подсветка через
color-mix
Hero-карточки на mobile (@media (max-width: 767px)):
- Grid 3 колонки → 1 колонка с центрированием
- Иконка 64×64 → 56×56
- Title 1.35rem → 1.1rem; subtitle 0.95rem → 0.88rem
- Actions row-flex с
min-height 44pxна каждой кнопке
Скриншоты
12 скриншотов (6 страниц × desktop+mobile) сохранены в docs/img/v489_lk/:
| Страница | Desktop (1440×900) | Mobile (390×844, iOS UA) |
|---|---|---|
| Дашборд | dashboard_desktop.png | dashboard_mobile.png |
| Профиль | profile_desktop.png | profile_mobile.png |
| ОП | promise_pay_desktop.png | promise_pay_mobile.png |
| Платежи | payments_desktop.png | payments_mobile.png |
| Тариф | tariff_desktop.png | tariff_mobile.png |
| Speedtest | speedtest_desktop.png | speedtest_mobile.png |
История доработок ЛК (builds 484-489)
| Build | Дата | Что изменилось |
|---|---|---|
| 484 | 2026-05-07 | Hero-карточка /lk/tariff/: все параметры текущего тарифа, фильтрация доступных по allow_change_to + transfer_only_more_money + usluga_range_type; чипы delta-price; empty-state с support-ссылкой |
| 485 | 2026-05-07 | Fix _get_address(): использовался несуществующий home.city_name вместо home.city → адрес «Не указан». Унифицирован через template-фильтр home_city_street() |
| 486 | 2026-05-07 | Speedtest: при NETWORK_MODE=external или VPN — кнопка disabled с иконкой 🚫 и tooltip; убран confirm() dialog |
| 487 | 2026-05-07 | E1 mobile_api проверен (баг отсутствует, использует home_city_street) + _get_address унифицирован. E2 hero-карточка тарифа на дашборде: description, speed_in/out, линейка, upgrade_count. E3 inline-edit email/SMS вместо read-only |
| 488 | 2026-05-07 | F-prep lk-hero.css: 4 chip-цвета (success/warning/danger/info), dark-mode, mobile-адаптив. F1 hero /lk/profile/. F2 hero /lk/promise-pay/ с countdown. F3 hero /lk/payments/ с last/next |
| 489 | 2026-05-07 | Brand #5BA89D → #43b77a (выравнивание с админкой). Полный набор токенов админки в :root. Mobile-секция в base.html: ≥44px touch, 16px inputs, safe-area. card-stat/buttons/focus-states выровнены |
Страницы Личного Кабинета
Что видит абонент на каждой странице ЛК и какие действия ему доступны.
Дашборд (/lk/)
Главная страница ЛК — сводный обзор состояния аккаунта.
- Шапка — название тарифа, абонплата, текущий баланс, инициал имени и номер договора. Клик по балансу ведёт на пополнение, клик по тарифу — на смену тарифа (если разрешено настройками).
- Алерты — уведомления о низком балансе, активном Обещанном платеже, запланированных работах. Каждый алерт можно скрыть крестиком (запоминается в cookie на год). На мобильном CTA («Пополнить →») располагается под текстом полной шириной для удобного тапа.
- Карточка «Тариф + Подключение» — в одной карточке: название тарифа, цена/мес, скорость скачивания, остаток дней до начисления; ниже отделённый блок со статусом подключения (Онлайн/Не подключён), временем последнего входа, ссылкой «История →» и кнопкой «Сменить тариф».
- Балансовая зона — сумма на счёте, прогноз «хватит на N дней» при текущем расходе.
- Быстрые действия — пополнить, открыть поддержку, посмотреть последний платёж.
Профиль (/lk/profile/)
Управление контактными данными и привязками.
- Hero-карточка с аватаром-инициалом, ФИО, № договора и адресом. Бейджи статуса (Активен / Заблокирован / ОП активен) и привязок (e-mail, SMS, Telegram-бот). Кнопки «Сменить пароль» и «Пополнить» (если баланс < 100 ₽).
- Контактные данные — поля e-mail и телефон с inline-edit. Кнопка «Сохранить» становится активной только при наличии изменений; индикатор «Есть несохранённые изменения» появляется при правке.
- Безопасность — пункт «Сменить пароль» (ведёт на отдельную страницу) и «Изменить MAC-адрес» (если функция включена админом — раскрывается inline).
- Привязки — VK, вход через Telegram, уведомления в Telegram-боте. Каждая строка показывает статус «Привязан/Не привязан» и кнопку «Привязать»/«Отвязать». Уведомления подключаются через одноразовую ссылку на бота с deep-link (10-минутный токен).
Пополнение баланса (/lk/payments/pay/)
Форма для онлайн-оплаты услуг.
- Текущий баланс — крупно, зелёный при положительном или красный при отрицательном. При долге — пометка «Услуги могут быть приостановлены».
- Сумма — крупное поле с символом ₽. Минимум — сумма, достаточная для погашения долга (если есть).
- Подсказки сумм — 4 chip-кнопки с рекомендованными суммами на основе абонплаты тарифа. Активная подсвечивается.
- Прогноз «После оплаты» — расчёт нового баланса после зачисления и срок, на который его хватит («2 месяца и 14 дней»).
- Комиссия — отдельная плашка с процентом и итоговой суммой к списанию (если ненулевая).
- Платёжная система — карточка с иконкой, названием (ЮKassa / Wallet One), описанием поддерживаемых способов (Visa/Mastercard/МИР/СБП) и SSL-бейджем.
- Кнопка «Оплатить» — после клика блокируется и показывает спиннер «Перенаправление…» (защита от двойной отправки).
- Сайдбар — последние 5 платежей с датой, временем и суммой; ссылка «Все →».
История платежей (/lk/payments/)
Список финансовых операций абонента.
- Hero — последний платёж (дата + сумма), баланс, абонплата, прогноз «хватит на N дней», всего операций. Кнопки «Пополнить» и «CSV» (выгрузка с учётом текущих фильтров).
- Фильтры — chip-строка периодов (Сегодня/Неделя/Месяц/3 мес/Год/Всё) и chip-строка типа (Все/Поступления/Списания). Кнопка «Точный фильтр» раскрывает аккордеон с датами «от-до» и суммой «от-до». Активные фильтры показываются как плашка под формой.
- Сводка — 4 плитки: Поступления, Списания, Всего операций, Средний платёж.
- График по месяцам — bar chart за 12 месяцев (поступления + списания).
- Список операций — каждая операция в виде карточки: иконка-стрелка слева (вверх/вниз), дата + время + цветной pill типа в первой строке, описание во второй (truncate с tooltip), сумма bold справа.
- Пагинация — компактные кнопки 36×36 с активной страницей в brand-цвете.
История операций (/lk/audit/)
Подробный аудит начислений и списаний за последний год.
- Сводка — 3 плитки: Поступления, Списания, Всего операций.
- Список операций — карточки с иконкой-стрелкой, датой + временем + типом в первой строке, описанием во второй, суммой справа.
- Бесконечная загрузка — следующие 50 операций подгружаются автоматически при скролле к низу. По завершении — индикатор «Это все операции за период».
Обещанный платёж (/lk/promise-pay/)
Управление услугой временного кредитования.
- Активный ОП — отображается дата окончания, оставшийся срок, лимит и текущий баланс. Кнопка «Пополнить» для досрочного погашения.
- Доступен для активации — карточка с условиями (срок, цена/день, лимит, баланс) и калькулятор «Если активировать ОП сейчас» считает: текущий баланс, зачисление, итоговый баланс, дату окончания, итог к возврату.
- Недоступен — карточка-предупреждение с конкретной причиной (превышен лимит/малый возраст аккаунта/cooldown/недостаточный долг) и подсказкой что делать.
- Активация — кнопка с подтверждением (модальное окно с деталями: срок, стоимость, лимит, время восстановления интернета).
- История ОП — последние операции с датой, описанием и суммой.
Подключения (/lk/sessions/)
История RADIUS-сессий абонента.
- Сводка — 4 плитки: Всего сессий, Активных сейчас, Скачано, Загружено.
- Список сессий — для каждой: иконка Wi-Fi, дата + время старта, бейдж «онлайн» для активных, длительность, IP-адрес, VLAN, причина завершения. Активная сессия выделена brand-полосой слева и пульсирующей точкой на иконке.
- Трафик — справа в каждой строке. Если в настройках включена детализация — отдельно показывается скачано (DL) и загружено (UL); иначе — суммарный трафик.
Тест скорости (/lk/speedtest/)
Замер фактической скорости интернета через Cloudflare Speed.
- Тариф-карточка — заявленная скорость по тарифу (DL и UL).
- Предупреждения — обнаружение, что абонент находится не в сети оператора (внешний IP) или подключён через VPN/прокси (сравнение WebRTC IP с server IP). При обнаружении кнопка теста блокируется с пояснением.
- Индикатор замера — круговой gauge с brand-цветом, отображает текущий замер. Большое значение в Мбит/с в центре, подпись текущего этапа («измеряем ping…», «скачивание…», «отправка…»).
- Результаты — 4 плитки: скачивание, загрузка, ping (мс), jitter (мс).
- Сравнение с тарифом — цветная плашка: зелёная (≥80% от тарифа), жёлтая (50–80%), красная (<50%).
- CTA при низкой скорости — отдельная карточка со списком рекомендаций (провод вместо Wi-Fi, перезагрузить роутер, закрыть торренты) и кнопкой «Создать обращение» с pre-filled темой и телом тикета (включая результаты теста).
- История тестов — последние 10 замеров (хранятся в браузере) с датой, DL, UL, ping. Кнопка «Очистить».
- Блокировка при долге — если баланс отрицательный, страница показывает заглушку с кнопками «Пополнить» и «Обещанный платёж».
Сообщения (/lk/messages/)
Рассылки и системные уведомления от оператора.
- Каждое сообщение — карточка с иконкой конверта (закрытый — непрочитанное, открытый — прочитанное), заголовком, временем (формат «вчера», «2 дн назад», «14 апр»), полным текстом и пиллами каналов доставки (Email, SMS, Telegram, Push, VK).
- Непрочитанные выделены brand-полосой слева и тонированным фоном.
- Пустое состояние с подсказкой если сообщений нет.
Тарифы (/lk/tariff/)
Просмотр текущего тарифа и смена на другой.
- Текущий тариф — большая brand-карточка: название, описание, цена/мес, параметры (скорость DL/UL, линейка услуг, минимальный срок до смены, комиссия за смену) и флаги-условия (доступна ли смена, разрешён только переход на более дорогие, смена с 1-го числа, смена в конце дня).
- Доступные тарифы — каталог карточек. Каждая показывает название, описание, цену, скорости, флаги-условия (с 1-го числа, комиссия, только вверх). Тег «дешевле»/«дороже» с дельтой относительно текущего тарифа. Кнопка «Перейти на этот тариф».
- Если смена недоступна — предупреждение с указанием причины и ссылкой на создание обращения.
Услуги (/lk/services/)
Подключение/отключение дополнительных услуг.
- Подключённые услуги — список карточек: иконка статуса (включена/приостановлена), название, дата подключения, описание, цена/мес справа, кнопка «Отключить» (или «доступно с DD.MM» если есть минимальный срок до отключения).
- Доступно для подключения — каталог карточек: иконка-кубик, название, описание, цена (или «бесплатно»), кнопка «Подключить». Недоступные карточки приглушены и показывают причину блокировки.
Реферальная программа (/lk/referral/)
Приглашение друзей с бонусом за подключение.
- Hero — иконка-подарок и крупная сумма бонуса «+X ₽». Текст: «За каждого друга, который подключится по вашей ссылке».
- Реферальная ссылка — readonly-поле + кнопка «Копировать» (всплывающее уведомление при успешном копировании). Под полем — кнопки шеринга: VK, Telegram, MAX, Email, системное «Поделиться» (если поддерживается браузером).
- Статистика — 3 карточки: Приглашено, Оплатили, Заработано.
- Как это работает — 4-шаговая инструкция с указанием срока начисления бонуса (24 часа после подключения реферала).
- Если программа отключена — карточка-уведомление «Реферальная программа временно приостановлена».
Добровольная блокировка (/lk/block/)
Временная приостановка услуг на период отъезда.
- Услуги активны — зелёная карточка с галочкой и кнопкой «Приостановить услуги». Подтверждение через модальное окно со списком последствий.
- Услуги приостановлены — оранжевая карточка с паузой и кнопкой «Возобновить услуги».
- Недоступно — серая карточка с заглушкой и кнопкой «Создать обращение в поддержку» (если функция отключена для тарифа).
- Что произойдёт при приостановке — отдельная информационная карточка с 4 пунктами: интернет отключится за 1–2 минуты, абонплата перестанет списываться, IPTV-услуги приостановятся, возобновить можно в любой момент.
Поддержка (/lk/support/)
Список обращений в техподдержку через FreeScout.
- Вкладки — «Открытые» и «Закрытые» с цветными счётчиками.
- Список тикетов — карточки со статусной иконкой в круге слева, заголовком темы (clamp 2 строки), мета-строкой (#id · обновлено · цветной pill статуса), стрелкой при наведении.
- 4 цвета статуса: waiting (красный, ждёт ответа оператора), active (зелёный, в работе), pending (оранжевый, ожидает), closed (серый, закрыт).
- Кнопка «Новое обращение» — переход на форму создания. Если у абонента не указан e-mail — отдельное предупреждение со ссылкой на профиль.
- Пустое состояние — сообщение с подсказкой для каждой вкладки.
Заполнение контактов (/lk/profile/contacts-required/)
Принудительный сценарий заполнения контактов при первом входе в ЛК (если включён в настройках).
- Шаг 1 — карточка с brand-шапкой и индикатором шагов. Поля e-mail и/или телефон (в зависимости от настроек). Блок «Зачем это нужно» объясняет назначение контактов. Если требуется верификация e-mail — отдельная плашка-напоминание о возможном попадании письма в «Спам».
- Шаг 2 — карточки верификации для каждого канала: для SMS — крупное OTP-поле и кнопка «Отправить ещё раз» (cooldown 60 сек, иконка-таймер при countdown); для e-mail — индикация «Откройте письмо и кликните по ссылке» + плашка про «Спам» + кнопка «Отправить повторно».
- Автоматическая проверка — после отправки письма страница каждые 5 секунд проверяет, подтверждён ли e-mail, и автоматически переходит на главную ЛК, как только все каналы подтверждены.
- Возврат к шагу 1 — если контакты были введены неверно, кнопка «Вернуться к шагу 1» сбрасывает данные.
Иллюстрации страниц: