Настройки: связь и сервисы
Интеграции, голосовые настройки, IPTV, личный кабинет и мобильное приложение, рассылки, персонал и доступы, лицензия и модули, обслуживание базы, гостевой портал.
Содержание раздела
- Модуль «Поддержка» — единое окно техподдержки
- 6.5А. Голосовая связь (провайдеры телефонии)
- 6.6. IPTV-пакеты
- 6.6А. Модуль IPTV — раздел /admin/iptv/
- 6.7. ЛК и мобильные
- 6.8. Сообщения
- 6.9. Персонал и доступ
- 6.10. Лицензия
- 6.10А. Модули и расширения
- 6.11. Резервные копии
- 6.12. Очистка БД и сессий
- 6.13. Диагностика
- 6.14. Массовые действия
- 6.15. Производительность и оптимизация
- 6.16. Captive Portal (финблокировка)
6.5. Интеграции
Единая точка управления внешними сервисами. Страница разделена на 8 вкладок. В нижней части любой страницы биллинга в футере отображается мини-индикатор статуса ИИ-ассистента (✓ AI / ✗ AI / ⏸ AI / ? AI) с количеством сообщений за сегодня.
Вкладка «Обзор»
Сводка всех настроенных интеграций со статусами. Цветной бейдж справа от каждой интеграции показывает: ✓ настроена / ✗ ошибка / ⏸ выключена / ? не настроена. Кнопка «Проверить все» запускает последовательно тест каждой настроенной интеграции; результаты появляются как Bootstrap-toast в правом верхнем углу.

Вкладка «Telegram»
Подключение Telegram-бота для двух целей: отправка уведомлений клиентам (те, кто подписался через личный кабинет) и чат оператора для системных алертов (NAS DOWN, ошибки платежей, СОРМ-выгрузка).

Параметры: токен бота, прокси SOCKS5 (api.telegram.org заблокирован для российских IP), ID чата администратора, переключатели типов алертов, тест отправки сообщения.
Вкладка «VK»
Интеграция VKontakte для двух функций: OAuth-логин в ЛК (клиент может зайти через свой VK-аккаунт) и отправка сообщений в личку группы.

Параметры: App ID для OAuth-логина, Community Token для отправки сообщений, ID группы. Тест соединения проверяет валидность токена.
Модуль «Поддержка» — единое окно техподдержки
Поддержка (/admin/support/) — нативный модуль
техподдержки внутри биллинга: приём обращений из всех каналов, карточка тикета со
связью с клиентом и CRM, AI-ответы, база знаний, аналитика. Весь приём и обработка обращений — внутри СмИТ Биллинг.
i-иконка рядом с заголовком раздела Поддержки и в модалках тикета ведёт прямо сюда.
Приём обращений — единая точка
Все каналы (email IMAP, VK, Telegram, MAX, голосовая почта Mango, веб-виджет) сходятся в единую функцию приёма, создающую или дополняющую тикет; AI-бот может ответить автоматически или эскалировать на оператора.
flowchart TD
EM["Email (IMAP)"] --> IN
VK["VK"] --> IN
TG["Telegram (polling)"] --> IN
MAX["MAX (WS)"] --> IN
VM["Голосовая почта Mango"] --> IN
WG["Веб-виджет"] --> IN
IN["ingest_message()"] --> CONV["Тикет (SupportConversation)"]
CONV --> AI{"AI-бот доступен?"}
AI -- "да" --> REPLY["Автоответ"]
AI -- "эскалация/нет" --> OP["Оператор: Входящие"]
REPLY -. "ESCALATE_TO_HUMAN" .-> OP
Входящие: список тикетов, поиск
KPI-карточки (Активные/Ожидают/Закрыто/Спам), статусные папки, фильтры (приоритет/категория/период/ящик) и умный поиск.

Поиск по тексту переписки. Ищет по теме, тексту сообщений, ФИО/договору клиента, адресу, телефону (любой формат) и №. Если совпадение не в теме — в строке тикета показывается сниппет-выдержка из тела сообщения с жёлтой подсветкой, чтобы оператор видел, почему тикет найден.

Карточка тикета и сайдбар
Слева — тред сообщений и редактор ответа (шаблоны saved-replies, AI-«Нейроответ»). Справа — сайдбар: Ответственный + Приоритет, Категория, Биллинг (аватар/баланс/тариф/статус/соцсети), SLA-таймер «Ждёт ответа», Прошлые обращения клиента, Теги, Доп. поля, Логи времени.

- SLA-таймер — время с последнего сообщения клиента без ответа оператора; цвет по порогу (зелёный <1 ч · оранжевый <4 ч · красный ≥4 ч).
- Прошлые обращения — последние 5 тикетов клиента (№ · тема · статус · дата), клик открывает тикет.
Выезжающая панель тикета
Клик по тикету из «Входящих» выдвигает панель быстрого просмотра без ухода со списка: мини-Биллинг (аватар/баланс/тариф/статус/соцсети), быстрая смена приоритета одним кликом, SLA-таймер, прошлые обращения, тред и блок ответа.

Мобильная адаптация
На узком экране над тредом появляется свёрнутая sticky-шапка клиента (аватар/ФИО/баланс/статус); разворот показывает SLA, договор/тариф/телефон и кнопки «Карточка» / «Управление». Ключевой контекст всегда перед глазами.

Вложения: политика, оптимизация, архив в GCS
- Политика вложений (настройки) — множественный выбор типов
файлов (изображения / документы / архивы / …) + макс. объём; список расширений
динамически мержится в
acceptформ загрузки. - Оптимизация картинок — изображения сжимаются при загрузке (Pillow, ≤1600px, JPEG q82) — экономия диска без видимой потери качества.
- Архивация в GCS — Celery-задача переносит старые вложения (настройки: возраст в днях, порог объёма) в облако; локальный файл удаляется только после успешного аплоада.
Категории обращений и «Перезвонить»
Категории настраиваются пер-ящик (у каждой — имя и иконка), выбираются в сайдбаре тикета и в модалке создания; фильтр по категории — в списке. Отметка «Перезвонить» на тикете создаёт заметку (с необязательным комментарием) и поднимает тикет в блок «требующие внимания».
Тикеты, требующие внимания + кнопка «следующий»
Под формой ответа — до 3 карточек тикетов, требующих внимания оператора («Перезвонить» и «Клиент ждёт N мин»); в шапке — кнопка перехода к следующему такому тикету. Включается настройкой.
Прочие возможности карточки
- Редактирование своего ответа/заметки — автор может исправить отправленное (с отметкой о правке); суперадмин — любое такое сообщение.
- Нормализация адресов — адрес из текста тикета прогоняется через DaData ФИАС (для голосовых — предварительно ИИ переводит адрес прописью в цифры), геокод попадает на карту сети.
- AI авто-триаж — команда закрытия/классификации старых тикетов с помощью AI (массовая разгрузка очереди).
- Модалка нового тикета — поиск клиента (имя/телефон/договор/ адрес), контакты и ящик подставляются по организации клиента, вложения-скриншоты, цветные кружки приоритета.
- Рейтинги — оценка ответа оператора клиентом (настройка).
- Учёт времени — таймер (авто-старт на своих тикетах) + ручное добавление, блок «Логи времени» в сайдбаре.
Настройки, база знаний, аналитика
Настройки Поддержки — вкладки (единый стиль): Общие, Авто-назначение ответственного/наблюдателя, Категории, Рейтинги, Учёт времени, IMAP+SMTP, Telegram/каналы (пер-ящик). Также: База знаний, Аналитика, Голосовая почта, Мессенджеры, Теги.

Вкладка «Резервный AI-провайдер»
Резервный ИИ-ассистент на случай недоступности основного. Используется те же сценарии (чат в ЛК и мобильном приложении), но через альтернативный API.

Параметры: адрес сервера, API-ключ, переключатели мест использования (LK / Mobile / Billing-monitor). Если настроены оба — приоритет у основного.
Вкладка «IPTV» (TVIP Media + LFStream)
Подразделы вкладки для двух IPTV-провайдеров: TVIP Media (российский middleware) и LFStream «Смотрёшка». Биллинг управляет пакетами клиента через их API: при активации или деактивации соответствующей услуги в биллинге автоматически включается/выключается пакет в middleware.


Параметры обоих сервисов: URL API, login/pass или API-ключ, ID оператора, тест соединения. Маппинг услуг → пакетов задаётся отдельно в разделе 6.6 IPTV-пакеты.
Вкладка «GCS» (Google Cloud Storage)
Google Cloud Storage используется для публичных файлов: скриншоты документации, иконки услуг, отчёты для скачивания.

Параметры: Service Account JSON-ключ (загружается через файл или вставляется как текст), имя GCP-проекта, имя бакета, префикс для путей внутри бакета.
Вкладка «География» (Адреса + Карта)
Объединяет два геосервиса: геокодер DaData (поиск адреса с автокомплитом и автоматический расчёт координат) и тайловый слой карты (OpenStreetMap / 2ГИС / Yandex Maps). Используется в карте клиентов и при создании адреса.


Параметры DaData: API-ключ. KPI-блок показывает сколько адресов уже геокодировано из общего числа (на демо: 4045 / 4261 = 94.93%).
6.5А. Голосовая связь (провайдеры телефонии)
URL: /admin/settings/telephony/ · Модуль: voice «Голосовая связь» (тариф Pro и выше) — приём звонков операторами: голосовая почта, click-to-call, записи разговоров → тикеты Поддержки и сделки CRM.
telephony («IP-телефония») — это оказание услуги связи клиентам (номера, SIP-учётки, тарифы, CDR). Модуль voice («Голосовая связь») — внутренний инструмент операторов: через какого оператора мы сами принимаем и совершаем звонки.
Оператор телефонии — плагины
Оператор подключается как плагин: базовый интерфейс TelephonyProvider в billing/services/telephony_providers.py. Новый оператор = новый класс в реестре, страница настроек не меняется. Активный провайдер хранится в настройке TELEPHONY_PROVIDER.
| Провайдер | Ключи | Проверка связи | Click-to-call |
|---|---|---|---|
Mango Office (mango) |
MANGO_API_KEY, MANGO_API_SALT, MANGO_API_URL |
vPBX API, подпись sha256(key+json+salt) |
callback: оператор → клиент |
Novofon (novofon) |
ASTERISK_ARI_URL, ASTERISK_ARI_USER, ASTERISK_ARI_PASSWORD, ASTERISK_TRUNK_ENDPOINT, ASTERISK_CALLERID |
Asterisk ARI GET /asterisk/info |
ARI originate через PJSIP-транк |
Карточка провайдера показывает бейджи «настроен / click-to-call / записи». Кнопка «Проверить связь» делает реальный запрос к API оператора и возвращает результат прямо на странице.
Голосовая почта — маршрутизация линий
Оператор присылает запись звонка письмом на служебный ящик. По номеру, на который позвонил клиент (VoiceMailLine.phone), выбирается:
- Ящик Поддержки или ящик Подключения — куда попадёт обращение (тикет или лид);
- Сегмент — физлица (B2C) / юрлица (B2B) / бренд / поддержка;
- Тип сделки в CRM и организация (мультиорг);
- UTM-метки и привязка к рекламной кампании.
Расшифровка звонка нормализуется AI и классифицируется: обращение в поддержку, заявка на подключение или мусор. Клиент определяется по номеру — если номер принадлежит клиенту, всегда создаётся тикет (не лид).
Пропущенные звонки → «Неразобранное»
Тумблер на странице включает настройку CRM_UNSORTED_MANGO: пропущенный входящий (и невнятное голосовое) создаёт сделку в воронке «Неразобранное» с дедупликацией по телефону — обращение не теряется, оператор разбирает его вручную. Запись разговора прикрепляется к сделке (DealCall.recording_gcs_url).
/admin/support/voicemail/ — разбор писем оператора, тест разбора без создания тикета (dry-run) и лог событий.
6.6. IPTV-пакеты
Маппинг услуг биллинга на IPTV-пакеты провайдера. Например: услуга «IPTV Базовый» в биллинге → пакет ID 12 в TVIP, услуга «IPTV Премиум» → пакет ID 18. При активации/деактивации услуги клиента биллинг автоматически включает/выключает соответствующий пакет в middleware.

Встроенный просмотр ТВ в ЛК и приложении
Клиент с активной IPTV-подпиской может смотреть каналы прямо в личном кабинете
и в мобильном приложении — без установки стороннего приложения провайдера.
В ЛК это HTML5-плеер (нативный HLS в Safari/iOS или через hls.js в остальных браузерах),
в приложении — нативный video_player (ExoPlayer на Android, AVPlayer на iOS).

Плейлист каналов формируется по шаблону URL провайдера с подстановкой
{login} / {account} клиента из таблицы маппинга
(IptvAccountMapping). Просмотр доступен только при выполнении всех условий:
- Просмотр включён — настройка
IPTV_WATCH_ENABLED; - Активна IPTV-подписка клиента (
UsersUsluga,system_type=21); - Клиент в сети СмИТ — у него есть интернет-тариф;
- опционально только онлайн — при активной RADIUS-сессии (
IPTV_WATCH_REQUIRE_ONLINE); - задан шаблон плейлиста провайдера.
Если условие не выполнено, клиенту показывается понятная причина («Просмотр доступен только в сети СмИТ», «Плеер каналов настраивается» и т.п.).
| Настройка | Назначение |
|---|---|
IPTV_WATCH_ENABLED | Включить встроенный просмотр (по умолчанию выкл) |
IPTV_WATCH_REQUIRE_ONLINE | Смотреть только при активной RADIUS-сессии |
IPTV_PLAYLIST_TEMPLATE_TVIP | Шаблон URL плейлиста TVIP, плейсхолдеры {login} {account} |
IPTV_PLAYLIST_TEMPLATE_LFSTREAM | Шаблон плейлиста «Смотрёшка» |
IPTV_TVIP_APP_URL / IPTV_LFSTREAM_APP_URL | Ссылки на приложения провайдеров |
Реализация: сервис billing/services/iptv_playlist.py
(can_watch / playlist_url / watch_context),
ЛК /lk/iptv/, мобильный экран «Интерактивное ТВ»
(GET /mobile-api/v1/iptv/packages возвращает блок watch).
6.6А. Модуль IPTV — раздел /admin/iptv/
Отдельный раздел сайдбара IPTV объединяет управление интеграцией с TV-провайдерами (TVIP Media и LFStream «Смотрёшка»): дашборд, пакеты, аккаунты клиентов, журнал API и настройки.

Дашборд
Бизнес-метрики: выручка IPTV (MRR — сумма активных подписок UsersUsluga с system_type=21),
число активных подписок и витринных пакетов, динамика подключений/отключений за 30 дней,
здоровье интеграции (% успешных запросов к провайдерам за сутки), топ-пакеты, распределение по провайдерам.

Пакеты и витрина провайдеров
Витрина-справочник популярных РФ-провайдеров: TVIP Media и LFStream — с рабочей интеграцией, остальные (24часаТВ, LIME HD, Ministra, Микроимпульс, Смартила) — справочно. Ниже — таблица маппинга «услуга биллинга ↔ пакет провайдера» с автоподбором по имени и подсветкой несопоставленных строк.

Аккаунты клиентов
Список связок «клиент ↔ аккаунт у провайдера» (IptvAccountMapping). Чипы-фильтры по статусу
(Все / Подтверждённые / Не подтверждённые / С ошибкой), колонки Пакет и Услуга
(берутся из БД через активные IPTV-услуги клиента, без онлайн-опроса провайдера).

Клик по кнопке «Подробнее» открывает модалку деталей аккаунта в три колонки — статус, синхронизация, аккаунт/логин, договор, тариф, баланс, блокировки + IPTV-услуги клиента и журнал запросов к провайдеру. Клик по имени клиента открывает слайд-панель (см. ниже).

Подтверждение аккаунта (account_verified): ресинк находит аккаунт у провайдера
по логину; только для подтверждённых аккаунтов реально выполняются block/unblock (гейт защищает от массовых
ложных ошибок). В TVIP-панели ~127 аккаунтов, из них принадлежат СмИТ — 16.
Журнал API и настройки
Журнал всех запросов к провайдерам (IptvApiLog) с человекочитаемым действием и телом ошибки.
Настройки — credentials TVIP/LFStream, тест подключения, биллинг-toggle.

Биллинг IPTV и kill-switch
IPTV-подписка — обычная услуга клиента (UsersUsluga, system_type=21), списывается
billing_worker штатно (1-го числа). В настройках есть переключатель
«Не списывать деньги за IPTV» (IPTV_BILLING_DISABLED) — режим тестирования:
плата за IPTV не списывается, дата следующего списания сдвигается вперёд (задним числом долг не образуется),
провижининг у провайдера продолжает работать. Блокировка IPTV при долге — опциональна
(IPTV_BLOCK_ON_NEGBAL, по умолчанию выкл).
Привязка пакета в карточке услуги
В модалке услуги типа «IP телевидение» есть вкладка IPTV — выбор провайдера и пакета. Связь «услуга ↔ пакет» можно задавать прямо из карточки услуги (не только на странице Пакеты).

На карточке клиента
На вкладке «Услуги» клиента в колонке «Примечание» для IPTV-услуги показывается
«📺 провайдер: пакет», для трафика — «⚡ N Мбит/с» (макс. скорость CEIL_IN). У IPTV-услуги —
бейдж «провайдер», открывающий модалку диагностики (сводка/пакеты/аккаунты/журнал).

Слайд-панель клиента: блок «Услуги» и IPTV-сайдбар
В слайд-панели клиента (открывается кликом по имени) после блока «Последняя сессия» добавлен аккордеон «Услуги» — список услуг с иконкой по типу, примечанием (провайдер/скорость) и ценой. При открытии со страницы аккаунтов аккордеон автоматически разворачивается.

У IPTV-услуги — кнопка «Провайдер», открывающая поверх вложенный IPTV-сайдбар (сводка, активные пакеты, аккаунты у провайдеров с отметкой «подтверждён», журнал запросов).

6.7. ЛК и мобильные
Настройки личного кабинета и мобильных приложений. Страница в админке разделена на 5 вкладок.
Вкладка «Обзор»
Сводка статуса ЛК: количество активных клиентов в личном кабинете за месяц, количество установок мобильного приложения, ссылки на сторы (Google Play / App Store), ссылка на сам ЛК и на админ-страницы HelpDesk.

Вкладка «Брендинг»
Фирменное оформление ЛК: логотип, цвет акцента, доменное имя
(lk.example.ru), favicon, OG-теги для соцсетей. Эти данные применяются
к ЛК отдельно от админки — у админки и у ЛК могут быть разные цвета и логотипы.

Вкладка «Функции»
Toggle-переключатели видимости разделов в ЛК. Каждый переключатель — это глобальное правило, видит ли его клиент. Например, выключив «Тариф», оператор скрывает у всех клиентов возможность сменить тариф самостоятельно.

Контролируемые функции: видимость тарифов и их смена, разрешение менять MAC-адрес, HelpDesk, история операций, обещанный платёж, реферальная программа, чат-AI и др.
Вкладка «Безопасность»
Параметры доступа в ЛК: разрешать ли вход только из сети оператора (когда клиент дома), автологин по IP без логина и пароля, запрет смены пароля клиентом (полезно при общем семейном договоре).

Вкладка «Мобильное»
Настройки мобильных приложений Android и iOS: текущая версия в сторе, минимальная версия для force-update (если клиент использует более старую — увидит диалог обновления), ссылки на стора, параметры push-уведомлений (Firebase).

Подробная документация — на отдельной странице
Описание возможностей ЛК, авторизация (Telegram/VK), настройки интеграций, AI-ассистент, push (Firebase), мобильные приложения Android и iOS — в разделе ЛК и мобильные.
6.8. Сообщения
Настройка каналов отправки уведомлений клиентам. Страница разделена на 5 вкладок.
Вкладка «Email (SMTP)»
Параметры SMTP-сервера для исходящей почты: «От кого» (From), хост, порт, логин/пароль, режим шифрования, проверка SSL-сертификата. Кнопка «Отправить тест» отправляет письмо на указанный адрес через текущие несохранённые значения формы — это позволяет проверить настройки до сохранения.

Шифрование SMTP — radio-группа
Тип шифрования задаётся одной radio-группой из трёх взаимоисключающих кнопок — включить два режима сразу нельзя:
- STARTTLS
(587)— наиболее распространённый вариант, default. Подключение в plain-text с upgrade до TLS через команду STARTTLS. - SSL (SMTPS)
(465)— TLS с первого байта (implicit TLS). - Без шифрования — порт 25, plain SMTP. Только для внутренних SMTP-relays/локальной тестовой инфраструктуры.
Авто-подстановка порта. При смене radio JS подставляет порт (587/465/25), если в поле сейчас стоит один из «дефолтных» портов. Если оператор задал кастомный порт (например, 2525) — он сохраняется.
Защита на back-end. Если из формы каким-то образом пришли email_use_tls=True и email_use_ssl=True одновременно (старый кэш браузера, legacy POST), email_test_send и email_settings_save применяют XOR-нормализацию: оставляют тот режим, который соответствует порту (465 → SSL, иначе STARTTLS), второй гасят. В SystemSettings теперь никогда не лежат оба True.
Поле «От кого» и политика отправителя
Большинство SMTP-серверов (включая SmitMailServ) применяют политику
«отправитель должен совпадать с авторизованным пользователем». Если у вас логин
noreply@вашдомен.ru, но в поле «От кого» вы указали
billing@вашдомен.ru — сервер вернёт ошибку:
SMTPRecipientsRefused: 553 5.7.1 <billing@вашдомен.ru>:
Sender address rejected: not owned by user noreply@вашдомен.ru
Решения:
- Простое — в поле «От кого» укажите тот же адрес, что и в «Логин».
- Гибкое — создайте alias на mail-сервере, чтобы
noreply@вашдомен.ruимел право отправлять от имени нужного адреса. Для SmitMailServ это делается через раздел «Почтовый сервер» → вкладка «Ящики» → редактирование ящика → полеsender_acl(или APIedit_mailbox).
Вкладка «SMS»
Выбор провайдера SMS из четырёх: SMSAero, SMSC.ru, SMS.ru, Свой шлюз (Android-телефон). Каждый со своими параметрами (логин/пароль или API-ключ), общий — имя отправителя. Тест отправки на тестовый номер.

Свой шлюз — СмИТ SMS Gate for Android
Установите приложение СмИТ SMS Gate for Android на телефон с SIM-картой и следуйте инструкциям прямо в приложении (мастер первого запуска подготовит всё за 1–2 минуты).
Старый Android-смартфон с SIM-картой превращается в локальный SMS-шлюз биллинга. Стоимость — только тариф вашего мобильного оператора (часто пакеты «безлимитный SMS» 200–300 ₽/мес). Приложение — re-skin форк open-source SMS Gateway for Android (capcom6, Apache-2.0) под брендом СмИТ; см. MobileApp/SmitSMSGateway/ в репозитории биллинга.
Поддерживается 2 режима:
- Local Server — биллинг шлёт прямо на IP телефона (требует чтобы биллинг и телефон были в одной сети). URL:
http://192.168.1.50:8080. - Cloud Server — телефон через WebSocket подключается к
api.sms-gate.app, биллинг шлёт REST туда. URL:https://api.sms-gate.app/3rdparty/v1. Не требует прямой связи между сетями.
Настройка телефона (Cloud-режим)
- Установить приложение СмИТ SMS Gate for Android на телефон с SIM-картой.
- На главном экране — переключатель «Облачный сервер» → ON.
- Скопировать Имя пользователя и Пароль с экрана.
- Включить Автозапуск (внизу экрана).
- В настройках Android: Батарея → СмИТ SMS Gate → «Без ограничений» (иначе уйдёт в фоновую заморозку).
- Внизу должна гореть надпись ОНЛАЙН — телефон подключён к cloud.
Настройка биллинга
| Поле | Значение |
|---|---|
| Шлюз | Свой шлюз (Android-телефон) |
| Имя пользователя | значение из приложения (например F14JMP) |
| Пароль | значение из приложения |
| URL шлюза | Local: http://192.168.1.50:8080Cloud: https://api.sms-gate.app/3rdparty/v1 |
| Номер SIM | 1 или 2 (для двухсимочников) |
После сохранения — поле «Тестовая отправка» внизу страницы. Введите свой номер, нажмите Отправить тест. Должно прийти SMS в течение 5–30 секунд.
Webhook статуса доставки
Только для cloud-режима sms-gate.app. Биллинг получает подтверждение реальной доставки SMS клиенту (не «отдано в шлюз», а «доставлено на телефон оператора»). Без webhook'а биллинг знает только что POST в шлюз вернул 200 OK — между «принято cloud'ом» и «дошло до пользователя» проходит от секунд до часов (если телефон-шлюз оффлайн).
Настройка (4 шага)
- В UI
/admin/settings/messaging/sms/при выборе шлюза «Свой шлюз (Android-телефон)» внизу появляется блок «Webhook delivery-status». - Скопировать URL для регистрации кнопкой «📋 Копировать» (формат
https://<ваш-биллинг>/api/sms/webhook/sms-gate/). - Нажать «🎲 Сгенерировать» для случайного 32-символьного hex-ключа HMAC-SHA256. Сохранить настройки.
- Регистрация webhook'ов в sms-gate.app — через REST API (в приложении на телефоне нет UI для этого):
Повторить для всех 3 событий:curl -u USERNAME:PASSWORD https://api.sms-gate.app/3rdparty/v1/webhooks \ -H 'Content-Type: application/json' \ -d '{"url":"адрес вашей установки/api/sms/webhook/sms-gate/", "event":"sms:delivered","signingKey":"<ваш-secret>"}'sms:sent,sms:delivered,sms:failed. Каждый зарегистрированный webhook возвращает свой ID.
Жизненный цикл SMS
| Шаг | Что происходит | Поле MsgStack |
|---|---|---|
| 1. Биллинг → cloud | POST /3rdparty/v1/messages возвращает {"id": "...", "state": "Pending"} | sms_external_id = id, sms_status = pending |
| 2. Cloud → телефон | WebSocket-push на телефон-шлюз (если ОНЛАЙН) | не меняется |
| 3. Телефон → оператор | SMS отправлено в сеть мобильного оператора | webhook sms:sent → sms_status = sent |
| 4. Оператор → клиент | SMS доставлено на телефон клиента | webhook sms:delivered → sms_status = delivered, sms_status_date = now() |
| 4'. Ошибка | Нет связи у телефона / номер заблокирован / денег нет | webhook sms:failed → sms_status = failed, sms_error = код ошибки |
Реальная статистика (с рабочего сервера 2026-05-07): pending → sent → delivered за 4–6 секунд при онлайн-телефоне. Если телефон оффлайн — sms-gate.app ставит сообщение в очередь и доставляет когда телефон вернётся (тестировано: 11 минут оффлайна — webhook'и пришли retry'ями сразу как телефон поднялся).
HMAC-подпись
Sms-gate.app шлёт подпись по схеме (официальная docs):
X-Signature: hex(HMAC-SHA256(secret, body + X-Timestamp))
X-Timestamp: 1715091045 # Unix epoch
Биллинг проверяет подпись через billing/views/sms_webhook.py::_verify_signature с поддержкой 4 форматов (для совместимости):
- HMAC(body+timestamp, secret) hex — официальный формат sms-gate.app
- HMAC(body, secret) hex — legacy без timestamp
- base64 любого из вышеперечисленных
- С префиксом
sha256=илиhmac-sha256=(стандартные конвенции webhook)
Constant-time сравнение для каждого кандидата. Если SMS_GATE_WEBHOOK_SECRET в SystemSettings пустой — подпись не проверяется (для теста / отладки). В production обязательно задавайте secret.
Защиты
- От подделки
- HMAC-SHA256 с секретом из
SystemSettings.SMS_GATE_WEBHOOK_SECRET. Невалидная подпись → HTTP 401 + лог с диагностикой (sig, ts, body_len, headers). - От downgrade статусов
- Если уже
delivered, повторный eventsms:sentне сбросит обратно. Приоритет:pending=0 < sent=1 < failed=2 < delivered=3. Учитывается только апгрейд по rank. - От Denial-of-Service
- Endpoint работает без auth (стандарт webhook'ов), но без подписи или с невалидной — атакующий может только обновить
sms_statusдля уже существующихsms_external_id. Записи не создаются, FK не нарушаются. Реальный риск — флуд логов, лечится rate-limit на nginx (опционально). - От retry-flood
- Sms-gate.app шлёт webhook несколько раз для одного события (retry'ит при failure). Биллинг идемпотентен: повторный webhook на тот же messageId+status — no-op (запись уже обновлена с правильным rank).
Endpoint
URL: POST /api/sms/webhook/sms-gate/ (публичный, CSRF-exempt).
Headers (от sms-gate.app):
Content-Type: application/jsonX-Signature: <hex>— HMAC-SHA256(body+timestamp)X-Timestamp: 1715091045— Unix epoch
Body (JSON):
{
"deviceId": "fIuD_aVrUyAIuN7DhxDw8",
"event": "sms:delivered",
"id": "<webhook-event-id>",
"payload": {
"messageId": "8_EwH18QDve2RnA_Sx7ye", // совпадает с MsgStack.sms_external_id
"phoneNumber": "+79991234567",
"deliveredAt": "2026-05-07T14:13:50.923+03:00",
"errorCode": "..." // только для sms:failed
},
"webhookId": "..."
}
Responses:
200 {"ok": true, "msg_id": 20697, "status": "delivered"}— успех, MsgStack обновлён200 {"ok": true, "matched": false, "message_id": "..."}— messageId не найден в БД (например, MsgStack удалена)200 {"ok": true, "ignored": true}— неизвестное event, не падаем200 {"ok": true, "skipped": "downgrade"}— попытка понизить статус (delivered → sent отвергнуто)400 {"ok": false, "error": "bad_json"}— невалидный JSON400 {"ok": false, "error": "no_message_id"}— нетmessageIdв payload401 {"ok": false, "error": "invalid_signature"}— HMAC не сходится (только если secret задан)
UI отображения статуса
На карточке клиента → вкладка «Сообщения» (8.16) бейдж SMS теперь показывает реальный статус доставки:
| Бейдж | Иконка | Статус | Tooltip |
|---|---|---|---|
| SMS | fa-check-double | delivered ✅ | «Доставлено в DD.MM HH:MM:SS» |
| SMS | fa-check | sent | «Отправлено оператору в DD.MM HH:MM:SS» |
| SMS | fa-clock | pending | «Ожидает доставки (id: внешний_id)» |
| SMS | fa-times | failed 🚫 | «Ошибка доставки: текст ошибки» |
| SMS | — | legacy (без webhook) | «SMS отправлено (без webhook delivery-status)» |
JS-функция _smsBadge(msg) в send_message_tab.html строит бейдж динамически после AJAX-create. MutationObserver на #msg-history-tbody автоинициализирует Bootstrap-tooltips на новых строках. После отправки бейдж 🟡 pending → через несколько секунд webhook → 🔵 sent → 🟢 delivered. Авторефреша без F5 пока нет (планируется в одном из обновлений — JS-poll на /sms_status/<msg_id>/).
Решение проблем
- SMS уходит, но в БД
sms_status='pending'навсегда - Webhook'и не зарегистрированы в sms-gate.app. Проверь
GET /3rdparty/v1/webhooksс твоей auth — должно быть 3 записи (sent / delivered / failed). - Webhook прилетает, но в логах
invalid HMAC signature - Secret в биллинге и в webhook-регистрации не совпадают. Удали webhook и зарегистрируй заново с правильным secret. Или временно очисти secret в UI — webhook начнёт работать без проверки подписи (для теста).
- SMS отправляется, но в БД
sms_external_id='' - Используется тестовая отправка из UI (кнопка «Отправить тест») — она шлёт напрямую через
_send_sms_tecnoбез созданияMsgStack. Это by design. Для реального теста с tracking — отправь сообщение через карточку клиента → вкладка «Сообщения». - Webhook прилетает, но MsgStack не обновляется (
{"matched": false}) - Не совпадает
messageId↔sms_external_id. Проверь что биллинг сохраняет id из ответа sms-gate.app:SELECT pk, sms_external_id FROM msg_stack WHERE sms_done=true ORDER BY id DESC LIMIT 5. - DNS-резолюция падает (
NameResolutionError 'api.sms-gate.app') - Известная нестабильность Docker-DNS. В
docker-compose.prod.ymlблокиwebиceleryдолжны содержатьextra_hosts: - "api.sms-gate.app:94.241.170.26". После добавления — recreate контейнеров.
Подтверждено вживую
(2026-05-07) на рабочем сервере, клиент Письменный Павел (#7686, +79177271796):
14:13:44 Биллинг → POST api.sms-gate.app/3rdparty/v1/messages
MsgStack #20697.sms_external_id = "8_EwH18QDve2RnA_Sx7ye"
MsgStack #20697.sms_status = 'pending'
14:13:46 cloud → телефон ОНЛАЙН → отправка SMS
14:13:48 оператор → +79177271796 (SMS доставлена)
14:13:50 cloud → POST webhook event=sms:delivered → HMAC ✓
MsgStack #20697.sms_status = 'delivered'
MsgStack #20697.sms_status_date = 2026-05-07 14:13:50
Полная цепочка от отправки до подтверждения доставки в БД — 6 секунд. UI обновляется при F5 страницы.
Вкладка «Telegram»
Отправка уведомлений клиентам через Telegram-бота. Условие — клиент должен один раз связать свой Telegram-аккаунт с учётной записью в личном кабинете (нажав кнопку «Привязать Telegram»).

Бот используется тот же, что и в разделе Интеграции → Telegram. На этой вкладке только переключатели: посылать ли уведомления через Telegram и какие именно типы.
Вкладка «Push»
Firebase Cloud Messaging для push-уведомлений в мобильном приложении. Параметры: путь к Service Account JSON-файлу Firebase, имя проекта, переключатели типов событий.

Вкладка «Шаблоны»
Текстовые шаблоны уведомлений с переменными подстановки. Каждое событие имеет свой шаблон и список включённых каналов. Например, событие «Низкий баланс» может отправляться по Email + SMS, а «Подключение услуги» — только по Push.

Поддерживаемые события (19):
- Блокировки: автоблокировка по балансу, административная блокировка, разблокировка, добровольная блокировка, снятие добровольной блокировки;
- Деньги: поступление платежа, баланс ниже порога, отрицательный баланс, обещанный платёж активирован, обещанный платёж истекает, обещанный платёж истёк;
- Услуги и тариф: подключение услуги, отключение услуги, смена тарифа, смена статуса подключения;
- Прочее: приветственное сообщение, восстановление пароля, ответ техподдержки, технические работы.
Доступные переменные — полный список, других подстановок нет:
%(abonent_name)s — ФИО клиента, %(contract_number)s — номер договора,
%(balance)s — текущий баланс, %(currecy)s — валюта,
%(tarif_name)s — тариф клиента, %(operator_name)s — название оператора,
%(text)s — дополнительный текст (услуга, сумма), %(psw_token)s — проверочный код.
При включённом флаге «Jinja» те же имена пишутся как {{ abonent_name }}.
Редактор шаблонов: Plain + HTML
Модальное окно редактирования шаблона расширено: 2 вкладки —
«Текст (plain)» для коротких сообщений (SMS / Push / Telegram / VK / ЛК) и
«HTML (Email)» с WYSIWYG-редактором TinyMCE 6 для
оформленных HTML-писем. Plain-текст используется для всех каналов кроме Email;
для Email — берётся HTML, если он заполнен, иначе fallback на plain (с заменой
переносов на <br>).

Возможности
- WYSIWYG TinyMCE 6 на вкладке HTML: заголовки, списки, ссылки, изображения, таблицы, выравнивание, шрифт, цвета. Подгружается с CDN при первом показе вкладки (lazy-load) — не нагружает страницу пока шаблон не открыт.
- Большое окно:
modal-xl(1140 px) с плавающим переходом вfullscreenна mobile/tablet (≤991 px). Высота TinyMCE — 520 px, можно растянуть кнопкой resize. Полноэкранный режим — кнопка fullscreen в toolbar. - Plain-текстарея увеличена до 14 строк (минимум 320 px) — удобнее редактировать длинные шаблоны для Email с уведомлением.
- Кликабельные переменные в правой панели: клик по
%(contract_number)sили{{ balance }}вставляет переменную в позицию курсора активного редактора (plain или HTML). Подсказка «Клик — вставить в редактор» под заголовком блока. - Бейдж рядом с вкладкой HTML: ✓ если HTML-версия заполнена, скрыт если пусто. Ссылка «очистить» под редактором — сбрасывает HTML.
- Санитайзер bleach при сохранении: разрешены теги
p, br, strong, em, a, ul, ol, li, h1-h6, table, tr, td, img, span, divи атрибутыclass, style, href, src, alt, target, rel. Скрипты, on*-обработчики, iframe — удаляются. Защита от XSS в HTML-шаблонах.

Кликабельные переменные
В правой панели модалки — справочник переменных в двух форматах:
Python format (%(name)s) и Jinja2
({{ name }}, при включённом флаге «Jinja»). Каждая переменная
обёрнута в кликабельный <code>: hover подсвечивает её зелёным,
клик — вставляет в позицию курсора. Если активна вкладка HTML — вставка идёт
в TinyMCE через insertContent(); если plain — в обычное
<textarea>.

Какой канал берёт что
| Канал | Источник | Пояснение |
|---|---|---|
| SMS | txt (plain) | HTML обрезается до текста (см. SMS webhook для счётчика сегментов). |
| Push (FCM) | txt (plain), 200 симв. | HTML не поддерживается push-сервисами. |
| Telegram | txt (plain) | Базовое форматирование Telegram через future-расширение. |
| VK | txt (plain) | Сообщения сообщества — только текст. |
| ЛК | txt (plain) | Notification banner в личном кабинете. |
html_body если заполнен,иначе txt с заменой \n → <br> | Один шаблон — два канала. Plain-fallback гарантирует совместимость со старыми шаблонами. |
Готовые HTML-шаблоны писем
В toolbar визуального редактора добавлена кнопка «Шаблоны писем»
(зелёная, с иконкой ). Клик открывает выпадающий список из
8 готовых пресетов с автоматической подстановкой брендинга компании
(CompanyBranding) — название, логотип, ИНН/КПП, контакты, адрес, акцентный цвет.

| Пресет | Сценарий использования |
|---|---|
| Чистый шаблон | Только шапка + подвал с брендингом, заголовок и заглушка для текста |
| Платёж получен | Подтверждение зачисления платежа с указанием баланса (зелёный card-style) |
| Низкий баланс | Предупреждение + CTA-кнопка «Пополнить счёт» (акцентный цвет) |
| Услуги приостановлены | Блокировка по балансу + кнопка восстановления |
| Услуга подключена | Уведомление о новом подключении (с балансом) |
| Технические работы | Информация о плановых работах (orange-style) |
| Поздравление с ДР | Праздничное письмо с центрированной вёрсткой |
| Восстановление пароля | Письмо с проверочным кодом (моноширинный шрифт, увеличенный текст) |
Каждый пресет — полноценное Email-письмо с тремя секциями:
- Шапка: логотип (или fallback-буква в круге с акцентным цветом) + название компании + ИНН/КПП. Снизу — 3px полоса акцентного цвета из брендинга.
- Контент: заголовок-сценарий, обращение к клиенту через
%(abonent_name)s, основной текст с%(contract_number)sи%(balance)s, при необходимости — CTA-кнопка с акцентным цветом. - Подвал: контакты компании (телефон, email, сайт) с иконками
📞 ✉ 🌐, юридический адрес, дисклеймер и подпись директора (если задано
director_nameв брендинге).

Поведение при вставке:
- Если редактор пуст или содержит менее 50 символов — пресет вставляется без подтверждения.
- Если в редакторе уже есть HTML — confirm-диалог: «Заменить готовым шаблоном «N»?».
- После вставки автоматически переключается на вкладку «Визуальный», чтобы оператор сразу увидел результат.
- Брендинг подгружается из CompanyBranding при каждом запросе — изменения логотипа/реквизитов мгновенно отражаются в новых пресетах.
Endpoint'ы:
GET /admin/settings/messaging/email_presets/→ список пресетов ({items:[{id,name,icon,description}]})GET /admin/settings/messaging/email_presets/?preset=<id>→ готовый HTML с подставленным брендингом ({ok:true, preset_id, html})
Реализация: billing/services/email_presets.py —
изолированный модуль с реестром PRESETS. Каждый пресет — функция-сборщик
контента, обёрнутая в общий wrapper _wrap() с шапкой и подвалом из
_branding_dict(). Добавление нового пресета = одна функция + запись в
PRESETS.
Миграция и схема
Поле AdminMsg.html_body (TextField, nullable) добавлено
(миграция 0120_adminmsg_html_body). Существующие шаблоны не затронуты —
у них html_body = NULL, Email-канал продолжает работать через
txt. Заполнить HTML можно постепенно по мере необходимости
(приветствие новому клиенту → красивая HTML-вёрстка, авто-уведомление о низком
балансе → plain).
6.9. Персонал и доступ
Управление сотрудниками биллинга. Доступно только пользователям с правами root. Страница разделена на 4 подраздела.
Чем группа доступа отличается от роли интерфейса, почему «не отмечено — значит запрещено» и что происходит с уволенным сотрудником.
Подраздел «Персонал»
Список сотрудников с фильтрами «Активные» / «Архив». Уволенный сотрудник переводится в архив (не удаляется), его действия в аудите остаются. Auto-аватары с инициалами на цветном градиенте (хеш от имени).

Карточка сотрудника содержит: ФИО, e-mail, телефон, должность, дату приёма, группы доступа, настройки уведомлений. Дополнительно у каждого сотрудника есть Профиль — личные настройки (аватар, избранные отчёты, журнал собственных действий).
Подраздел «Интерфейс»
Настройка видимости полей в формах для каждой роли. Поля можно скрыть от группы, сделать read-only или required. Например, кассиру оставить только поле «Сумма платежа», а инженеру — все поля кроме финансовых.

Подраздел «Доступ к моделям»
Какие модели биллинга видит каждая группа пользователей. Чекбоксы Read / Create / Update / Delete для каждой модели (Tarif, Usluga, Abonents, NAS, и т.д.). Без галочки Read — пункт меню скрывается у этой группы.

RBAC разделов админки
Обычные модели (Тариф, Услуга и т.п.) гейтятся чекбоксами выше. Но часть разделов — CRM, лендинги, настройки — это не модели, а отдельные страницы. Для них на странице группы есть блок «Разделы админки»: отметьте, какие разделы доступны этой группе.
Политика — deny-by-default: раздел из этого списка виден в меню и открывается по ссылке только у групп, где он отмечен (плюс суперпользователь — всегда). Без отметки раздел скрыт в меню и запрещён даже по прямой ссылке — открывается страница «Доступ к разделу запрещён».
flowchart TD
A[Запрос к разделу] --> B{Суперпользователь?}
B -- Да --> OK[Доступ разрешён]
B -- Нет --> C{Раздел в списке
«Разделы админки»?}
C -- Нет --> OK
C -- Да --> D{Есть отметка
у группы пользователя?}
D -- Да --> OK
D -- Нет --> DENY[403 «Доступ запрещён»
+ пункт скрыт в меню]

Дефолтное распределение, засеянное при внедрении (суперпользователь и Администратор + Директор — во всех разделах):
| Раздел | Кому доступен (кроме su, Администратора и Директора) |
|---|---|
| Salesbot / Рекламные кампании / Лендинги | Маркетинг |
| CRM: Мастер, Воронки, Доп. поля, Голосовая почта · Поддержка → Настройки | Старший менеджер |
| CRM → Настройки | — |
| Настройки: Система, Интеграции, Лицензия, ЛК, AI | — |
| Настройки → Финансы (платежи/фискал/банк) | Бухгалтер |
| Настройки → Инфраструктура (почта/DNS/бэкапы) | только Администратор |
| Настройки → Сообщения | Старший менеджер |
| Настройки → Маркетинг | Маркетинг |
| Клиенты | все операционные роли + Маркетинг (кроме Кладовщика) |
| Тарификация | Ст.менеджер, Менеджер, Ст.сэйлс, Бухгалтер, Отчётность, Маркетинг |
| CRM (воронка/задачи/карта) | менеджеры, сэйлсы, Монтажник, Отчётность, Маркетинг |
| Поддержка (входящие/тикеты) | Ст.менеджер, Менеджер, Отчётность |
| Оборудование | Монтажник, Отчётность |
| Справочники | Ст.менеджер, Менеджер, Бухгалтер, Монтажник |
| Отчёты | менеджеры, Ст.сэйлс, Бухгалтер, Отчётность, Маркетинг |
| Документы | Ст.менеджер, Менеджер, Бухгалтер |
| Видеонаблюдение | менеджеры, сэйлсы, Монтажник, Отчётность, Маркетинг |
| IPTV / IP-телефония | Ст.менеджер, Менеджер, Отчётность |
| Склад | Кладовщик, Монтажник, Отчётность |
Если у роли нет доступа к разделу, при переходе по ссылке открывается понятная страница:

Аварийный выключатель
Настройка SECTION_RBAC_ENABLED = 0 мгновенно отключает весь RBAC
разделов (доступ ко всем разделам открывается всем сотрудникам) — на случай, если
какая-то роль оказалась заблокирована ошибочно. Точечно доступ правится тут же,
галочками в блоке «Разделы админки».
Подраздел «Доступ к клиентам»
Какие папки клиентского дерева видит каждая группа. Полезно для разделения филиалов: агент филиала «Север» видит только папку «Север», агент филиала «Юг» — только папку «Юг», главный администратор видит весь корень.

6.10. Лицензия
Информация о действующей лицензии: количество разрешённых клиентов, дата окончания, тип (коммерческая / тестовая / OEM).

Подробная документация — на отдельной странице
Порядок поставки и продления, варианты оплаты, типичные проблемы — в разделе Лицензирование.
6.10А. Модули и расширения
URL: /admin/settings/modules/ — каталог модулей биллинга: что включено, что доступно в вашем тарифе и что можно докупить.
Карточка модуля
Каждый модуль показан карточкой с обложкой, номером версии (в правом верхнем углу), кратким описанием и чипами тарифов, в которые он входит. Управление:
- Тумблер — включить/выключить модуль. Выключенный модуль скрывается из меню и его разделы недоступны по прямой ссылке.
- «Настроить» — переход на страницу настроек модуля.
- «Подробнее» — модальное окно с полным описанием.
Недоступные модули
Модули, не входящие в ваш тариф, отображаются полупрозрачными с приглушённой обложкой, замком и подписью «Доступно в тарифе: …». Их карточки видны — чтобы понимать, что даёт переход на старший тариф. Ссылка «Перейти на тариф →» ведёт в раздел Лицензия.
Окно «Подробнее»
Открывает карточку модуля как в маркетплейсе: обложка, строка «категория · разработчик · тарифы» с кнопкой «Документация», полное описание и четыре вкладки:
- Возможности — что умеет модуль; здесь же список модулей, от которых он зависит.
- Как это работает — порядок действий по шагам.
- Скриншоты — реальные экраны раздела (клик открывает полноразмерное изображение).
- История версий — changelog по каждому релизу модуля.
Пустые вкладки скрываются автоматически. Содержимое карточек приходит с сервера лицензий и кэшируется на 6 часов — при недоступности сервера карточки продолжают работать, но без обложек и описаний.
Виджеты-плагины
Рядом с модулями — каталог виджетов (/admin/settings/widgets/): небольшие расширения, которые встраиваются в дашборды, карточку клиента, карточку сделки и сайдбар тикета. Виджет привязан к модулю и доступен, только если этот модуль включён.
6.11. Резервные копии
Резервные копии — самостоятельный таб в группе «Обслуживание».

Типы копий:
- db — только база данных (pg_dump в формате custom).
- files — медиа-файлы и шаблоны печати (tar.gz).
- both — БД + файлы.
- docker — самодостаточный пакет: БД, код, Dockerfile, docker-compose,
.env, медиа и скрипт
restore.sh. Достаточно для развёртывания на новом сервере. - configs («Конфиги сервера») — лёгкий снимок только
серверной конфигурации:
.env,docker-compose*.yml,Dockerfile,gunicorn.conf.py,requirements.txtи весь каталогdocker/(nginx / freeradius / postgres). Без БД и кода — обычно несколько килобайт. Удобно для быстрого сравнения/отката настроек сервера.
Настройка: имя конфигурации, тип, расписание (cron-выражение), количество хранимых копий, включить/выключить, кнопка «Сделать сейчас» (запуск вне расписания).
Список копий — записи с датой, размером, статусом, типом. Кнопки в строке: Скачать, Восстановить, Удалить. В процессе backup'а строка показывает анимированный прогресс-бар (опрос статуса каждые 3 секунды).
Защита от «зависших» копий: если Celery-воркер падает или
перезапускается во время резервного копирования (например, при переезде сервера), запись
могла навсегда остаться в статусе running — на странице крутился вечный
спиннер и шёл бесконечный опрос статуса. Теперь функция _reap_stale_running()
автоматически помечает любую запись в running старше 30 минут
как «Ошибка» с понятным сообщением. Срабатывает при открытии страницы и при каждом
опросе статуса (раз в 3 секунды), так что зомби-запись сбрасывается сама. Дополнительно
run_backup теперь явно завершается ошибкой при неизвестном типе бекапа или
если файл не был создан.
Восстановление — модалка с выбором: только БД / только файлы / полное восстановление. Для типа docker показывается инструкция как развернуть копию на новом сервере.
6.12. Очистка БД и сессий
URL: /admin/settings/db_cleanup/ (раздел «Обслуживание», только root-доступ).
Раздел централизованного автоматического обслуживания БД и борьбы с «зомби»-сессиями RADIUS. Состоит из 5 блоков (сверху вниз): Состояние БД, Автоочистка, История запусков, Аудит зомби-сессий, Выбор NAS для аудита.

Состояние БД сейчас
Верхний блок — реальный счётчик записей в 4 ключевых таблицах (обновляется AJAX):
MSG_STACK— журнал отправленных сообщений (Email/SMS/Push/Telegram). На рабочий сервер ~100K записей при ежедневной нагрузке 500–2000.AUDIT_OPERATIONS— аудит действий (создание/правка/удаление). На рабочий сервер ~600K записей за всё время.RADIUS_SESSIONS— история RADIUS-сессий (включая закрытые). На рабочий сервер ~5–7M записей при 1000+ онлайн-клиентах.NAS_EVENTS— события NAS (UP/DOWN, аларм). Маленькая таблица, чистится редко.
Каждая ячейка показывает размер (Кб/Мб/Гб) + количество записей. Если рядом с цифрой растёт ⚠ — таблица превышает порог опасного роста и требует внимания.
Автоочистка БД

Параметры retention (период хранения, после которого записи удаляются):
| Параметр | SystemSettings ключ | Default | Что удаляется |
|---|---|---|---|
| Сообщения | DB_CLEANUP_MSG_DAYS | 30 дней | MsgStack где send_date < now − N |
| Аудит | DB_CLEANUP_AUDIT_DAYS | 365 дней | AuditOperations где op_time < now − N |
| RADIUS-сессии | DB_CLEANUP_SESSIONS_DAYS | 90 дней | RadiusSessions где END_TIME IS NOT NULL AND END_TIME < now − N (только закрытые!) |
| NAS-события | DB_CLEANUP_EVENTS_DAYS | 30 дней | NasStatusLog где event_time < now − N |
| Размер батча | DB_CLEANUP_BATCH_SIZE | 5000 | Сколько строк удалять за один DELETE (чтобы не лочить таблицу надолго) |
| Включена | DB_CLEANUP_ENABLED | 1 | Тогл всей автоочистки |
Расписание: Celery beat-задача db-cleanup-daily запускается ежедневно в 03:30 по серверному времени. Время фиксированное, для теста есть кнопка «Запустить чистку сейчас».
Что делает задача (billing/tasks/db_cleanup.py::run_db_cleanup):
- Создаёт запись в
DbCleanupRunсstatus='running'. - Для каждой из 4 таблиц считает порог
cutoff = now - timedelta(days=N). - В цикле:
DELETE ... LIMIT batch_sizeпока есть записи. Между батчами 100мс паузы — снижает нагрузку. - Записывает в результат:
msg_deleted,audit_deleted,sessions_deleted,events_deleted,execution_time. - Обновляет
DbCleanupRun.status='ok'+finished_at. При ошибке —status='failed'+error. - Если за прогон удалено > 100K записей — отправляет Telegram-уведомление.
Кнопки управления:
- «Применить» — сохранить изменённые retention-параметры в SystemSettings (без перезапуска чистки).
- «Запустить чистку сейчас» — синхронный запуск task'а через Celery
.delay(). UI показывает spinner, через ~30 сек обновляет «Историю запусков». - Тогл «Включено» — глобально отключить автоочистку (полезно при миграциях/бэкапах).
История запусков
Таблица последних 50 запусков из DbCleanupRun:
- Время старта и длительность в секундах.
- Статус: 🟢 ok / 🔴 failed / 🟡 running.
- Удалено: разбивка по 4 таблицам (Msg / Audit / RadSes / Events).
- Запустил:
scheduledдля beat-task или username при ручном запуске. - Ошибка: tooltip с traceback при
status='failed'.
Аудит зомби-сессий на NAS

Зомби-сессия — это запись в RADIUS_SESSIONS с END_TIME IS NULL (то есть «сессия активна»), но при этом NAS не подтверждает её существование. Возникает когда:
- NAS перезагрузился / упал и не прислал Accounting-Stop для последних сессий.
- Сетевой обрыв между NAS и FreeRADIUS — Accounting-Stop потерян.
- Bug в прошивке NAS (типичный пример — MikroTik с переполнением счётчика, см. разбор зомби-сессий).
Зомби-сессии искажают виджет «Онлайн сейчас» на дашборде (показывает большее число, чем реально), мешают корректному выбору IP из пула при переавторизации, и забивают `RADIUS_SESSIONS` лишними «открытыми» строками.
Beat-задача session-audit-hourly (billing/tasks/session_audit.py):
- Запускается раз в час (default; настраивается через
SESSION_AUDIT_INTERVAL_MINUTES). - Берёт ровно 4 NAS (default
SESSION_AUDIT_NAS_PER_RUN=4) — те, у которых давно не было аудита (sort bylast_audit_at ASC). Так за сутки покрывается ~96 NAS — больше, чем у любого реального оператора. - Для каждого NAS берёт батч из 50 активных сессий (default
SESSION_AUDIT_BATCH_SIZE=50). Это ~2 минуты времени NAS — не нагружает его. - Для каждой сессии:
radclientзапрос Status-Server или Accounting Interim-Update к NAS — если NAS не подтверждает наличие session-id → метим как «подозрительную». - Через 5 минут идёт повторная проверка тех же сессий. Если NAS ещё раз не подтверждает — сессия считается зомби, ставится
END_TIME=now(),END_REASON='zombie-cleanup'. - Counter подтверждённых zombie добавляется в
SessionAuditRun.zombie_killed. - Если
zombie_killed > 0— отправляется Telegram-алерт с разбивкой по NAS.
Параметры аудита:
| Параметр | SystemSettings ключ | Default |
|---|---|---|
| Интервал между запусками | SESSION_AUDIT_INTERVAL_MINUTES | 60 минут |
| NAS за один запуск | SESSION_AUDIT_NAS_PER_RUN | 4 |
| Сессий за один батч | SESSION_AUDIT_BATCH_SIZE | 50 |
| Задержка повторной проверки | SESSION_AUDIT_RECHECK_DELAY | 300 сек (5 мин) |
| Telegram-алерт | SESSION_AUDIT_TG_ALERT | 1 |
| Включён | SESSION_AUDIT_ENABLED | 1 |
История аудитов ниже — таблица из SessionAuditRun: время, NAS, проверено сессий, найдено зомби, длительность, статус.
Выбор NAS для аудита

Таблица всех NAS с enabled=True и колонками:
- Имя + IP NAS.
- Чекбокс «Включён в аудит» — индивидуально для каждого NAS (тогл сохраняется в
Nas.session_audit_enabled). Удобно отключить аудит для проблемного NAS на время разбора. - Последний аудит — дата/время последнего
SessionAuditRunдля этого NAS. - Найдено зомби — счётчик из последнего аудита.
- Активных сессий сейчас — текущее количество.
- Кнопка «Запустить» — мгновенный аудит конкретного NAS (вне очереди), полезно для отладки.
На рабочий сервер сейчас в активном аудите 4 NAS: TOY, JOY, FAG, POT. Зомби-сессии редки (1–3 в неделю) — после фиксов (zombie-LOGGED + bigint миграция) это в основном NAS-перезагрузки.
Решение проблем
- Чистка не отрабатывает в 03:30
- Проверь Celery beat:
docker logs app-celery-beat-1 | grep db-cleanup. Должна быть запись «Scheduler: Sending due task db-cleanup-daily». Если нет — beat не запущен или не видит задачу (импортconfig/celery.py). - «MSG_STACK слишком большой» — 5М+ записей
- Уменьши
DB_CLEANUP_MSG_DAYSдо 14 или 7 → жми «Запустить чистку сейчас». При первом проходе может удалить миллионы строк (займёт 10–20 минут). Дальше beat-задача держит размер в норме. - RadiusSessions растёт быстрее, чем чистится
- В норме: 1 сессия = 1 строка с
END_TIME IS NOT NULLчерез 5–10 минут. Если строк сEND_TIME IS NULLмного — есть зомби, запусти аудит. Если все закрытые, но всё равно много — увеличьDB_CLEANUP_BATCH_SIZEдо 20000. - Telegram-алерт «zombie cleanup: 50+ sessions» каждый час
- Один из NAS постоянно теряет Accounting-Stop. Проверь логи NAS, прошивку, сетевые потери до FreeRADIUS. Временно отключи аудит для этого NAS (чекбокс «Включён в аудит» = False) пока разбираешься.
- Вернуть удалённые данные
- Backup до чистки берётся ежедневно в 03:00 (за 30 минут до db-cleanup) — в
/var/backups/carbon/. Восстановление таблицы:pg_restore -t msg_stack <dump-file>.dumpв отдельную БД, потомINSERTнужных строк.
6.13. Диагностика
Набор готовых команд для диагностики проблем с конкретным клиентом или NAS. Запускаются прямо из веб-интерфейса, результат показывается в модалке-терминале.
Примеры команд: пинг NAS, проверка живости клиента, тест авторизации radtest,
проверка SSH-доступа к NAS.
6.14. Массовые действия
Подменю с тремя инструментами обслуживания, объединёнными по смыслу «одно действие сразу для большой группы записей».
Подраздел «Разблокировать»
Массовая разблокировка клиентов. Открывается, если, например, партнёр-сборщик заплатил оптом за весь дом, и нужно одной кнопкой снять блокировку «долг» с десятков клиентов. Можно задать тип блокировки (b_negbal — долг, b_admin — админская) и фильтр клиентов (папка, тариф, дата блокировки).

Подраздел «Чистка БД»
Удаление тестовых/демо-данных при первичной настройке системы. Удаляет демо-клиентов, тестовые услуги, фейковые финансовые операции — всё, что было в стартовой поставке для демонстрации. Не трогает реальные данные оператора.

Запускать только один раз — после первичной настройки и до загрузки реальных клиентов. Действие необратимо, перед запуском система запрашивает подтверждение.
Подраздел «Закрытие периода»
Финальное действие месяца. Фиксирует балансы клиентов, переводит «корзину» (soft-deleted клиентов) в архив, готовит данные для бухгалтерской выгрузки. Запускается оператором вручную — обычно в первые дни нового месяца.

6.15. Производительность и оптимизация
В мае 2026 в биллинг внедрён пакет оптимизаций производительности. Главная цель — устранить «тяжёлые» страницы которые открывались по 3-4 секунды и тормозили работу операторов при одновременной нагрузке.
Что было сделано
Семь пакетов улучшений, выкаченных за один день без даунтайма биллинга:
- 8 composite-индексов PostgreSQL на самых частых полях запросов
(audit, abonents_block, users_usluga, users.nas_id, radius.logged, finance_operations.op_date).
Применены с
CREATE INDEX CONCURRENTLY— без блокировки таблиц. - Redis-кеши для главного дашборда (TTL 60с), мониторинга NAS (TTL 60с), карты клиентов (TTL 5 мин), VpnConst-настроек (TTL 60с с автоматической инвалидацией при сохранении через UI).
- Денормализация Abonents.last_payment_at — дата последнего платежа
теперь хранится прямо у клиента, обновляется автоматически PostgreSQL-триггером
на
finance_operations.INSERT. Используется в фильтрах должников (period chips: новые/средние/старые/хронические). - Денормализация Abonents.primary_nas_id + primary_pool_id — основной
NAS и пул IP-адресов клиента (по самой свежей учётной записи Users). Используется
в списке клиентов папки, глобальном поиске и AJAX-подгрузке. Обновляется тремя
триггерами на
users.INSERT/UPDATE/DELETE. - statement_timeout=30s для пользовательских SQL-отчётов
(
/admin/reports/AdminCustomReports/) — защита от тяжёлых запросов которые вешали gunicorn-worker на минуты. После таймаута показывается понятное сообщение «Отчёт прерван по таймауту». - Устранение N+1-запросов в 5 горячих местах: NAS list (DISTINCT ON для last_event), NAS Monitor (GROUP BY вместо N COUNT), AdminAccounts (3 count → 1 aggregate с filter=Q), folder/search (lookup из Nas/IpPull вместо JOIN Users).
- Убран функциональный cast
op_date::dateв FinanceOperations view — теперь используются B-Tree индексы вместо seq scan.
Что это дало
| Страница | Было (cold cache) | Стало | Ускорение |
|---|---|---|---|
| Должники, фильтр «не платили 90+ дней» | 3 821 мс | 0,34 мс | 11 000× |
| Папка клиентов | 545 мс | 100-300 мс | 2-5× |
| Глобальный поиск | 301 мс | 100-200 мс | 2-3× |
| Карточка клиента | 400 мс | ~100 мс | 4× |
| Главный Dashboard | 600-1500 мс | <100 мс | 5-15× |
| Мониторинг NAS (auto-refresh) | full SQL × 30с | warm cache | 3-5× |
Главный эффект — страница должников (одна из самых частых для операторов отдела взысканий) теперь открывается мгновенно вместо 4 секунд ожидания.
Защитные механизмы
- Backup при деплое: код (tar 254 МБ) + pg_dump (29 МБ) — откат 5-10 минут.
- Celery beat safety-net: раз в неделю запускается
rebuild-last-payment-atиrebuild-primary-nas-pool— полная сверка денормализованных полей с реальной таблицей. Если триггер пропустил какой-то платёж (например, при массовом импорте с отключёнными триггерами) — данные восстанавливаются автоматически. - CONCURRENTLY-индексы: создание индекса не блокирует таблицу для чтения и записи, клиенты ничего не замечают.
Документы (для разработчиков)
/admin/reports/dev/?id=392— общее описание простыми словами/admin/reports/dev/— все технические отчёты по фазам 1-4: план оптимизации, реализация индексов и кешей, денормализация last_payment_at, денормализация primary_nas/pool
6.16. Captive Portal (финблокировка)
Captive Portal Engine — единый движок порталов для перехвата трафика через walled-garden. Должник с отрицательным балансом не отрезается полностью, а перенаправляется на страницу «пополните баланс», сохраняя доступ к ЛК, банкам и госуслугам — это ускоряет возврат дебиторки и снижает нагрузку на поддержку.
Как проверить готовность портала, чем опасен аварийный режим и почему нельзя привязывать магистральный NAS к гостевому профилю.
flowchart TB CP["Captive Portal"] --> FIN["Финблокировка"] CP --> GST["Гостевые порталы"] CP --> PAY["Платежи"] CP --> ACL["Белые списки"] FIN --> RAD["RADIUS
walled-garden"] GST --> RAD ACL --> POOL["Пулы IP
и справочники"] PAY --> YK["Услуги
и ЮKassa"]
Раздел в админке: Настройки → Captive Portal
(/admin/settings/captive_portal/). Четыре вкладки:
- Финблокировка — профиль financial: блок-пул IP, RADIUS
Filter-Id, белый список (ACL-группа), URL заглушки + правила (аварийный режим «разрешить всем», разрыв сессии при долге, жёсткий REJECT), блок готовности профиля и сводка блокировок. - Гостевые порталы — список гостевых порталов турбаз: организация, турбаза, ссылка, состояние сети, гостей / онлайн, готовность анкеты. Кнопка «Настроить сеть» открывает боковую панель: блок-пул, Filter-Id, ACL, гостевые NAS, адаптер B (чужой MikroTik), платный доступ, свой домен и ящик рассылок.
- Платежи — продажи гостевого Wi-Fi: сегменты по статусам, период, конверсия и доля ошибок. Подробнее — ниже.
- Белые списки (ACL) — группы разрешённых хостов (банки, госуслуги, портал), доступных из walled-garden даже должнику; правила раскрываются прямо в списке.
Готовность профиля и проверка конфигурации
Включённый профиль ещё не значит работающий портал. Резолвер RADIUS считает
незаданными и пустое значение, и ноль: если не задан ни блок-пул, ни
Filter-Id, должник получает отказ авторизации вместо
страницы «пополните баланс». Вверху вкладки стоит список проверок, а если хоть одна
не пройдена — красная плашка «Captive Portal не работает».

Проверяется пять вещей: профиль включён, задан блок-пул, осмысленный
Filter-Id, у белого списка есть активные правила и режим жёсткого
REJECT не перекрывает профиль. У каждой непройденной проверки — кнопка
«Исправить», она подсвечивает нужное поле формы.
Кнопка «Проверить конфигурацию» идёт дальше и повторяет решение резолвера на живых данных: существует ли пул и остались ли в нём адреса, сколько активных правил в белом списке, совпадают ли резервные значения служебных настроек с профилем, отвечает ли страница-заглушка. Результат сохраняется с отметкой времени и автором — видно, когда портал проверяли последний раз.
flowchart LR A["Долг
b_negbal"] --> F{"Пул или
Filter-Id задан?"} F -->|"нет"| REJ["Отказ
авторизации"] F -->|"да"| WG["IP блок-пула
+ Filter-Id"] WG --> PAGE["«Пополните баланс»
+ белый список"] PAGE --> PAY["Оплата"] PAY --> OK["Снятие блока,
CoA, интернет"]
Аварийный режим «Разрешить интернет всем»
Переключатель на вкладке «Финблокировка» отключает все блокировки на уровне RADIUS — на случай аварии биллинга, когда клиентов нельзя оставить без связи. Это самая опасная настройка раздела: пока она включена, должники пользуются интернетом бесплатно.
flowchart LR ON["Включение
с подтверждением"] --> LOG["Записаны автор,
время и срок"] LOG --> WORK["Блокировки
не применяются"] WORK --> OFF["Выключение:
по сроку или кнопкой"]
- Включение требует подтверждения, в котором сразу написано, через сколько режим погаснет.
- Запоминается, кто и когда включил — плашка наверху страницы показывает это вместе со временем автоматического выключения и обратным отсчётом.
- Срок задаётся настройкой
BLOCK_ALLOW_ALL_AUTO_OFF_HOURS(по умолчанию 4 часа;0— не выключать автоматически). Гашение происходит на первом же запросе RADIUS после истечения, отдельная фоновая задача не нужна.
Как устроено
Движок построен на единой модели PortalProfile, рассчитанной на три типа
портала: financial (финблокировка должников), guest
(гостевой Wi-Fi турбаз — бесплатный и платный) и
paid (платные точки):
- RADIUS-резолвер (
radius_python/internet.py): при блокировке только за долг (b_negbal) возвращает не REJECT, аAccess-Acceptс атрибутамиFramed-IP-Address(из блок-пула) +Filter-Id— NAS заворачивает такого клиента в walled-garden. - Источник правды — профиль: при сохранении на странице параметры
дублируются в служебные настройки (
BLOCK_POOL_ID/BLOCK_FILTER_ID/BLOCK_PORTAL_URL), поэтому RADIUS и правила блокировок остаются согласованы. - Выход из блока: оплата → снятие блокировки + CoA Disconnect → при переавторизации клиент получает обычный интернет.
Организации и права доступа
Раздел относится к группе прав «Настройки · Инфраструктура» — по умолчанию его открывает только администратор. Изменение настроек закрыто той же проверкой, что и сама страница: сотрудник без права не сможет поменять параметры даже прямым запросом.
Данные скоупятся по организации клиента-турбазы: список порталов, статистика платежей и выгрузка CSV показывают только то, что относится к организациям сотрудника. Портал чужой организации не открывается и по прямой ссылке — отвечает так же, как несуществующий. В списке гостевых NAS доступно только оборудование этой организации.
Гостевой Wi-Fi портал для турбаз
На том же движке (PortalProfile тип guest) работает гостевой
Wi-Fi портал — инструмент для турбаз, кафе, отелей: гость подключается к Wi-Fi,
попадает на брендированную страницу, подтверждает телефон по SMS и заполняет анкету, после
чего получает интернет. Турбаза собирает легальную базу контактов с согласием
на рекламу и автоматически рассылает SMS-поздравления с днём рождения.

В таблице разведены два состояния: «Сеть» — привязан ли NAS (или работает адаптер B), и «Анкета» — готовы ли форма и текст согласия. Портал может собирать анкеты и при этом не открывать интернет — это видно сразу. Чип «Сеть не привязана» со счётчиком отбирает такие порталы, поиск ищет по турбазе, названию портала и имени NAS.

Подключение: услуга «Гостевой Wi-Fi портал» (system_type=12)
клиенту-турбазе (юр.лицо). При подключении автоматически создаётся портал с дефолтной анкетой
(телефон + дата рождения). На карточке клиента появляется вкладка «Гость wifi»
со статусом и ссылкой на портал.
- Captive-страница
/portal/<slug>/— брендированная (логотип, цвет, тексты турбазы), мобильная, самодостаточная. Flow: телефон → SMS-код → анкета → согласие на ПДн → доступ. - Конструктор анкеты — турбаза в своём ЛК (
/lk/guest-portal/) задаёт, какие поля собирать (имя, авто, тип отдыха и т.д.), брендинг, текст согласия и рассылки. - Два адаптера сети: A — наше оборудование (RADIUS guest-ветка + CoA-разблокировка по MAC); B — чужой MikroTik турбазы (hotspot login, разблокировку делает MikroTik сам — работает без нашего RADIUS). Адаптер выбирается в модалке «Настроить сеть».
- ДР-рассылки — Celery beat раз в сутки шлёт SMS гостям, у кого день рождения через N дней. Только гостям с согласием на рекламу (152-ФЗ), с защитой от повторной отправки.
Платный доступ к гостевой сети (продажа по QR)
Гостевой портал можно сделать платным: гость сканирует QR-наклейку, подтверждает телефон по SMS, выбирает тариф (например «100 ₽ — 3 часа»), оплачивает через ЮKassa и получает интернет на оплаченный срок. По истечении доступ автоматически отключается. Чек 54-ФЗ пробивает ЮKassa, выручка идёт на организацию-провайдера. Применение — платные точки в парках, на турбазах, на мероприятиях.
Поток гостя: сканирует QR → телефон + SMS-код → выбор тарифа → e-mail для чека → оплата картой → чек на почту → интернет на срок тарифа → по истечении снова на портал.
- Тарифы = услуги. Тариф доступа — обычная услуга
Usluga(system_type=12) в разделе Тарификация → Услуги: цена = «Сумма», длительность = поле «Длительность доступа» (часы/минуты). Новой тарифной сущности не вводится. К порталу тарифы привязываются галочками в модалке «Настроить сеть» (блок «Платный доступ»). - Чек 54-ФЗ — формируется ЮKassa по e-mail гостя (онлайн-касса ЮKassa); отдельная фискализация не нужна.
- Выручка — приходная финоперация на организацию-провайдера (по умолчанию основная организация), тип «Платный гостевой Wi-Fi». Лицевые счета клиентов не затрагиваются.
- Отсечка по времени — два механизма: NAS сам разрывает сессию по
Session-Timeout(остаток оплаченного времени) + страховочная задача раз в 5 минут. По истечении гость попадает обратно на портал оплаты. - Статистика — вкладка «Платежи» в разделе Captive Portal: сегменты по статусам, выручка и средний чек за выбранный период, конверсия, доля неудачных платежей, экспорт CSV.
Вкладка «Платежи»
Вкладка отвечает на вопрос «принимаются ли деньги прямо сейчас», а не просто показывает список. Сегменты вверху — счётчики по статусам: Все · Оплачены · Ожидают · Ошибки · Истекли · Возвраты; клик по сегменту фильтрует таблицу. Рядом период (30 дней / 90 дней / год / всё время), выбор портала и поиск по e-mail, телефону или MAC.

Показатели считаются по всей выборке периода, а не по видимой странице:
- Активных сейчас — гостей с непросроченным оплаченным доступом.
- Выручка за период и средний чек.
- Конверсия — доля оплаченных из всех попыток (оплаченные + ошибки + ожидающие).
- Доля ошибок: если она достигает 20 %, над таблицей появляется предупреждение с числом неудачных платежей — обычно это повод проверить ключ ЮKassa и тарифы портала.
p****@example.ru, 79177***96) и раскрываются по клику —
персональные данные не «светятся» на экране, когда рядом кто-то есть. Экспорт CSV
выгружает ровно то, что отобрано фильтрами, и только по доступным организациям.
Вкладка «Белые списки (ACL)»
Белый список — набор хостов, которые остаются доступны из walled-garden: личный кабинет, платёжные системы, банки, госуслуги. Правила раскрываются прямо в строке группы, рядом видно, в каком профиле группа используется, а группа без активных правил помечена красным.

Строка правила показывает адрес, комментарий и состояние. Выключенное правило не работает, даже если группа выбрана в профиле — именно так портал и оказывается «настроенным, но бесполезным». Полное редактирование — в справочнике ACL, карандаш ведёт сразу к нужной группе.
Гости в СОРМ и срок хранения данных
Публичный Wi-Fi отличается от домашнего интернета не только техникой:
постановления Правительства РФ №758 и №801 от
31.07.2014 требуют идентифицировать пользователя точки коллективного доступа и
хранить сведения о нём и об оказанных услугах связи. Гость не клиент —
договора с ним нет, — поэтому в выгрузку он попадает отдельными файлами, а не
в таблицу ABONENT, согласованную с куратором.
flowchart LR G["Гость
подтвердил номер"] --> U["GUEST_USER
кто пользовался"] G --> I["GUEST_IDENT
журнал идентификаций"] S["Сессия RADIUS"] --> SS["GUEST_SESSION
оказанные услуги"] U --> EXP["Выгрузка СОРМ
по конфигу"] I --> EXP SS --> EXP
| Файл | Что внутри | Источник |
|---|---|---|
GUEST_USER |
телефон и время его подтверждения, MAC, площадка и её владелец, первый и последний визит, число визитов, согласие на обработку данных, ФИО и e-mail — если анкета площадки их собирает | гости порталов |
GUEST_IDENT |
журнал подтверждений номера: когда запрошен код, когда подтверждён, IP и
MAC клиента, IP точки доступа. Неудачные попытки тоже видны
(RESULT = 0) |
OTP-сессии портала |
GUEST_SESSION |
сведения об оказанных услугах: начало и конец сессии, длительность, объём трафика, IP и MAC | сессии RADIUS по MAC гостя |
Файлы добавляются кнопкой «Гостевой Wi-Fi» на странице отчётов конфига СОРМ (Оборудование → СОРМ → Отчёты). Отдельной кнопкой, а не в общем наборе: гостевые порталы есть не у каждого оператора, а состав файлов согласуется с куратором отдельно.
GUEST_SESSION заполняется,
когда площадка работает на нашем оборудовании (адаптер A). При адаптере B
сессию держит MikroTik площадки и в биллинг она не попадает — факт доступа
виден в GUEST_USER по времени окончания доступа.
Сколько хранить
Две нормы тянут в разные стороны, и обе обязательны: №801 требует хранить
сведения не менее шести месяцев, а 152-ФЗ — не
дольше, чем нужно для цели обработки. Поэтому срок задан настройкой
GUEST_DATA_RETENTION_DAYS (по умолчанию 180 дней). Раз в сутки
задача удаляет гостей старше срока вместе с анкетами, согласиями и журналом
идентификаций; гостей с ещё действующим оплаченным доступом не трогает.
Значение 0 отключает удаление — на случай, когда есть основание
хранить дольше (запрос уполномоченных органов, спор по оплате).
С телефона
Раздел рассчитан на работу с телефона: таблицы превращаются в карточки с подписями, фильтры сворачиваются в строку «поиск + Фильтры» с нижним листом, кнопки действий подписаны и помещаются в строку, а панель настроек сети открывается боковой панелью.
live_…)
в Настройки → Платёжные системы и добавить домены ЮKassa
(yoomoney.ru, api.yookassa.ru) в белый список гостевого NAS — иначе
неоплаченный гость не сможет открыть страницу оплаты из walled-garden.