Files
TeleWave/docs/telegram-bot.md
T
Leonid Pershin 2b03e43a83
ci / build-backend (push) Successful in 2m38s
ci / build-frontend (push) Successful in 1m16s
ci / tests (push) Successful in 2m33s
ci / sonar (push) Successful in 3m48s
Add Telegram bot integration and related features
Implemented Telegram bot functionality, including settings management, subscriber tracking, and link generation for user interaction. Updated the backend to support new Telegram-related services and database entities. Enhanced the frontend to display Telegram options and allow users to open a chat with the bot. Localization strings were added for both English and Russian to support the new features. This integration aims to improve user engagement through Telegram notifications and interactions.
2026-07-31 07:58:18 +03:00

64 lines
6.5 KiB
Markdown

# Бот расписания в Telegram
Оповещения зрителю: «на канале началось шоу» и «скоро начнётся». Настраивается в админке
(вкладка «Телеграм»), подписки собирает сам зритель кнопками в чате.
## Что решено и почему
**Подписка только по одноразовому коду.** Кнопка «Открыть чат с ботом» на странице эфира выдаёт
ссылку `t.me/бот?start=КОД`; код живёт 15 минут, сгорает при первом использовании и привязывает
чат к учётной записи TeleWave. Анонимный бот («кто нашёл, тот и подписался») означал бы рассылку
неизвестно кому и невозможность отписать чат вместе с блокировкой пользователя. Ссылка выдаётся
по нажатию, а не лежит в разметке: в ней пропуск к чужим оповещениям.
**Два транспорта, переключателем.** `Polling` — сервер сам ходит за обновлениями: работает из-за
NAT и через прокси, и это единственный вариант там, где публичного адреса нет. `Webhook` — Telegram
стучится на наш HTTPS-эндпоинт: дешевле и быстрее, но требует доступного извне домена, и прокси
здесь не поможет — соединение устанавливает Telegram. Разговор с ботом при этом один и тот же:
оба транспорта приносят одинаковое обновление и разбираются общим кодом.
**Прокси — часть настроек, а не окружения.** HTTP или SOCKS5 с логином и паролем; клиент собирается
на каждый вызов, поэтому смена прокси не требует перезапуска контейнера. Кривой адрес — ошибка, а
не повод молча пойти напрямую: «работает в обход прокси» на канале, ради которого прокси и заводили,
хуже отказа.
**Секреты в базе, наружу не отдаются.** Токен и пароль прокси лежат открытым текстом: шифровать их
нечем — Data Protection в проекте сознательно не заводили (см. CLAUDE.md). Наружу уходит только
признак «задан», а пустое поле в форме означает «оставить как есть». Секрет вебхука генерируется
сам и проверяется заголовком `X-Telegram-Bot-Api-Secret-Token`: адрес рано или поздно окажется
в чужих логах, и без секрета туда постучится кто угодно.
**Проверка связи — на сохранении.** Настройки сразу спрашивают у Telegram `getMe`: неверный токен
или мёртвый прокси иначе всплыли бы через сутки молчания бота. Оттуда же приходит имя бота — без
него не собрать ссылку на чат, поэтому кнопка у зрителя появляется только после успешного контакта.
Вебхук ставится и снимается тем же сохранением: пока он стоит, Telegram не отдаёт обновления
опросом, и переключение режима без этого оставило бы бота немым.
## Оповещения
Считаются по материализованной ленте, а не по факту раздачи: лента и есть эфир, а ждать
подтверждения от плеера не от кого — зрителей может не быть вовсе.
- **Начало шоу** — на смену шоу, а не на каждую запись: четыре серии подряд это одна программа
в глазах зрителя, и четыре сообщения о ней читаются как спам.
- **Скоро в эфире** — за пять минут до следующей программы.
Граница разобранного (`TelegramSettings.NotifiedUntil`) двигается на каждом тике, даже когда
подписчиков нет: иначе первый же подписавшийся получил бы пачку сообщений про всё, что успело
пройти. Догон ограничен пятнадцатью минутами — после долгого простоя бот не станет пересказывать
вчерашний эфир.
## Меню в чате
`/start` с кодом привязывает чат и открывает меню; `/start` без кода — открывает меню уже
привязанному. Меню живёт **одним сообщением**: нажатие кнопки переписывает его на месте, иначе
чат заполняется одинаковыми «ваши подписки» после каждого клика. Кнопка — тумблер: повторное
нажатие снимает подписку. `/stop` останавливает рассылку, не стирая подписки: вернувшись, зритель
получит свои каналы, а не пустой список.
## Границы
- Бот не отвечает на произвольные вопросы и не показывает программу передач — только подписки.
- Групповые чаты не поддерживаются: подписка привязана к учётке, а в группе её владельца нет.
- Один чат — один подписчик; повторная привязка по новому коду меняет учётку, а не плодит копии.