Перейти к содержимому

Поддержка/тикеты

В проекте есть два канала поддержки:

  • внешняя ссылка SUPPORT_LINK, которая ведет пользователя в Telegram-чат, канал, форму или любой другой публичный URL;
  • встроенные тикеты Web App / Mini App, если включен SUPPORT_TICKETS_ENABLED.

Внешняя ссылка остается простым резервным каналом. Тикеты дают полноценный диалог внутри личного кабинета: пользователь создает обращение, видит историю ответов, получает счетчик непрочитанных сообщений, а администратор отвечает из админ-панели.

Раздел Поддержка появляется в Web App, когда SUPPORT_TICKETS_ENABLED=True. Пользователь может:

  • создать тикет с темой, категорией, приоритетом, текстом и/или изображением;
  • выбрать категорию billing, technical, account или other;
  • выбрать приоритет normal или high;
  • открыть список своих тикетов с фильтром по активным и всем обращениям;
  • отвечать в открытом тикете текстом и/или изображением и видеть ответы поддержки;
  • перейти по SUPPORT_LINK, если нужна внешняя поддержка.

Заблокированные пользователи не могут создавать тикеты и отвечать в них. Для пользователей показываются только обычные сообщения: внутренние заметки администраторов скрыты.

Сообщение пишется в том же визуальном редакторе, что и рассылки: жирный, курсив, подчёркнутый, зачёркнутый, моноширинный, блок кода, цитата и ссылка. Пользователю доступно только форматирование - без исходного HTML, шорткодов и кнопок. Ссылки, набранные обычным текстом, становятся кликабельными и в редакторе, и в чате, включая сообщения, написанные до появления редактора. Счётчик длины и лимит SUPPORT_TICKET_MAX_BODY_LENGTH считают видимый текст, а не разметку вокруг него.

В админ-панели тикеты доступны в разделе Коммуникации -> Поддержка. Доступ проверяется так же, как и для остальных /api/admin/*: нужна Web App-сессия пользователя, чей Telegram ID указан в ADMIN_IDS.

Администратор может:

  • видеть сводку по открытым, ожидающим ответа, закрытым и непрочитанным тикетам;
  • фильтровать обращения по статусу, приоритету, категории и назначенному администратору;
  • искать по теме, username, имени и email пользователя;
  • сортировать по обновлению, созданию или важности;
  • отвечать пользователю, менять статус, категорию, приоритет и исполнителя;
  • оставлять внутренние заметки, которые видны только администраторам;
  • открыть карточку пользователя и видеть контекст подписки: тариф, статус, остаток времени, обычный и premium-трафик.

Ответ пишется в том же редакторе, что и рассылка, и дополнительно даёт:

  • переключатель исходного HTML;
  • шорткоды персонализации - те же, что в рассылках. Они подставляются один раз, в момент отправки, и в тикете хранится уже готовый текст, поэтому админ и пользователь видят одно и то же сообщение;
  • меню Вставить с быстрыми ссылками для этого пользователя: {config_link} (ссылка на подписку для импорта в приложение), {miniapp_link} (личный кабинет в Mini App) и {install_link} (персональная инструкция по установке);
  • до четырёх кнопок под сообщением - ссылка, промокод в боте, промокод в Mini App или экран Mini App. Кнопки показываются в чате и добавляются в Telegram-уведомление об ответе. Внутренняя заметка кнопок не несёт: она не доходит до пользователя.
  • вложение одного изображения, выбранного через диалог или перетащенного из проводника. Изображения доступны и во внутренних заметках, но никогда не показываются пользователю вместе с ними.

Сообщения хранятся в подмножестве HTML, которое понимает Telegram (b i u s code a pre blockquote); всё остальное при сохранении превращается в обычный текст, а ссылки допускают только схемы http, https, tg и mailto.

Статусы тикета: open, awaiting_user, awaiting_admin, resolved, closed. При создании тикет сразу получает статус awaiting_admin; ответ пользователя переводит незакрытый тикет в awaiting_admin, ответ администратора - в awaiting_user. Закрытые статусы считаются resolved и closed.

Новые тикеты и ответы пользователя могут отправляться в Telegram-уведомления администраторам и в лог-чат. Для отдельного топика поддержки используйте LOG_SUPPORT_THREAD_ID; если он пустой, сообщения идут в общий LOG_THREAD_ID/чат по настройкам логирования.

Повторные уведомления по одному непрочитанному тикету ограничиваются cooldown-настройками, чтобы не заспамить админов:

  • SUPPORT_ADMIN_NOTIFICATION_COOLDOWN_SECONDS - пауза для Telegram/log уведомлений;
  • SUPPORT_ADMIN_EMAIL_COOLDOWN_SECONDS - пауза для email-уведомлений.

Telegram-уведомления администраторам и в лог-чат по умолчанию включены и управляются через SUPPORT_ADMIN_TELEGRAM_NOTIFICATIONS_ENABLED. Email-уведомления по умолчанию выключены и включаются через SUPPORT_ADMIN_EMAIL_NOTIFICATIONS_ENABLED=True. Письма отправляются только администраторам из ADMIN_IDS, у которых в базе есть email. Для отправки нужен рабочий SMTP-конфиг из раздела «Способы входа».

Ответ администратора и закрытие тикета дополнительно отправляются пользователю в Telegram, если у него есть Telegram-аккаунт, и на email, если он привязан.

Изображение отправляется отдельным фото в Telegram и встраивается в HTML-письмо. Текст остаётся отдельным сообщением, поэтому сохраняются полный лимит Telegram на текст и кнопки под ним. Сообщение может состоять только из изображения.

Переменная Назначение
SUPPORT_LINK Внешняя HTTP(S)-ссылка поддержки. Для Telegram можно указать @username, t.me/username или полную https://t.me/username; сокращённые варианты автоматически приводятся к полной HTTPS-ссылке. Показывается в боте и Web App как быстрый способ связаться с командой.
SUPPORT_TICKETS_ENABLED Включает раздел тикетов в Mini App и разрешает создание обращений.
SUPPORT_TICKET_MAX_BODY_LENGTH Максимальная длина сообщения тикета.
SUPPORT_TICKET_MAX_SUBJECT_LENGTH Максимальная длина темы тикета.
SUPPORT_TICKET_RATE_LIMIT_PER_HOUR Сколько новых тикетов пользователь может создать за час; 0 отключает лимит.
SUPPORT_MESSAGE_RATE_LIMIT_PER_MINUTE Сколько сообщений в тикетах пользователь может отправить за минуту; 0 отключает лимит. По умолчанию 10.
SUPPORT_IMAGE_RATE_LIMIT_PER_DAY Сколько изображений в тикетах пользователь может отправить за сутки; 0 отключает лимит. По умолчанию 20.
LOG_SUPPORT Включает Telegram/log уведомления по тикетам поддержки.
LOG_SUPPORT_THREAD_ID Необязательный ID топика в лог-чате для сообщений поддержки.
SUPPORT_ADMIN_TELEGRAM_NOTIFICATIONS_ENABLED Включает Telegram/log уведомления администраторам о новых тикетах и ответах пользователей. По умолчанию true.
SUPPORT_ADMIN_EMAIL_NOTIFICATIONS_ENABLED Включает email-уведомления администраторам о новых тикетах и ответах пользователей.
SUPPORT_ADMIN_NOTIFICATION_COOLDOWN_SECONDS Минимальная пауза между повторными Telegram/log уведомлениями по одному непрочитанному тикету.
SUPPORT_ADMIN_EMAIL_COOLDOWN_SECONDS Минимальная пауза между повторными email-уведомлениями по одному непрочитанному тикету.

Все эти параметры описаны в env-vars.md. Основной рекомендуемый способ менять их - админка Система -> Настройки -> Поддержка; значения применяются как override поверх .env.

Пользовательские маршруты:

  • GET /api/support/tickets - список тикетов пользователя;
  • POST /api/support/tickets - создать тикет;
  • GET /api/support/tickets/{id} - открыть тикет;
  • POST /api/support/tickets/{id}/messages - отправить ответ;
  • GET /api/support/images/{image_id} - получить изображение из доступного пользователю невнутреннего сообщения;
  • POST /api/support/tickets/{id}/read - отметить сообщения прочитанными;
  • GET /api/support/unread - счетчик непрочитанных ответов поддержки.

Админские маршруты находятся под /api/admin/support/*: список, карточка тикета, ответ, изменение статуса/приоритета/категории/исполнителя, отметка прочитанного и статистика.

Данные хранятся в таблицах support_tickets, support_ticket_messages и message_images; миграция применяется автоматически сервисом migrate при docker compose up -d --build.

Принимается одно изображение JPEG, PNG или WebP до 8 МБ и 16 мегапикселей. Сервер не доверяет имени файла и MIME-типу: файл полностью декодируется Pillow, анимация и повреждённые/неподдерживаемые форматы отклоняются, EXIF и другие метаданные удаляются, разрешение ограничивается 2560 px, после чего создаётся новая статичная WebP-копия. На диске копии лежат в data/message-images по SHA-256 и физически дедуплицируются; в БД каждое вложение получает отдельный случайный ID. Пользовательский маршрут проверяет принадлежность изображения тикету и скрывает вложения внутренних заметок. Ответы запрещают MIME-sniffing и публичное кеширование.

У сообщения есть body_format (text или html) и buttons - готовые кнопки в виде JSON. Сообщения, написанные до появления редактора, остаются text и читаются буквально: разметка в них не «оживает» задним числом.