> ## Documentation Index
> Fetch the complete documentation index at: https://omniflow-vpn.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Обязательная подписка на каналы

> Как требовать членство в каналах Telegram и какие правила не дают этому механизму наказывать людей несправедливо

Оператор может требовать от клиентов членства в одном или нескольких каналах
Telegram. Это маркетинговый механизм, и это единственное в Omniflow, что может
заблокировать платящего клиента по причине, не связанной с оплатой. Поэтому
каждая его часть обратима, сопровождается предварительным предупреждением и
поддаётся последующей проверке по журналу.

## Неизвестный ответ — это никогда не отсутствие

`getChatMember` может завершиться неудачей: Telegram недоступен, бот потерял
права администратора в канале, API ограничивает частоту запросов. Ничто из
этого не означает, что клиент вышел.

Неудавшаяся проверка записывает `unknown` — состояние, отличное от `absent`, и
оно ничего не блокирует. Если бы эти два состояния слились в одно, людей
блокировали бы из-за сбоя, и это тот режим отказа, который есть у данного
механизма и которого нет больше нигде в продукте.

Клиент, у которого вообще нет записи о членстве, находится в том же положении:
никто не установил, что он отсутствует, поэтому ничто не ограничивается.

## Два требования — два обещания

| Флаг | Что делает |
| - | - |
| `require_for_purchase` | Просит человека подписаться до оплаты |
| `require_for_activation` | Отбирает доступ у того, кто уже оплатил |

Они разделены, потому что это разные обещания. Заблокировать может только
требование при активации; ограничение покупки ни у кого ничего не отбирает.

Требование при покупке применяется на обеих поверхностях по одному правилу. Бот
проверяет его, когда клиент нажимает **Оплатить**, и спрашивает Telegram вживую,
если кэшированному ответу больше пяти минут. Веб-оформление проверяет его, когда
клиент нажимает **Подтвердить**, но у процесса API нет собственного транспорта
Telegram, поэтому он читает только подписки, записанные воркером: ответ старше
двадцати четырёх часов или его отсутствие — это *unknown*, а unknown никогда не
блокирует. Клиенту, которому веб отказал, показываются каналы с кнопкой
подписки для каждого; как только он подписался, следующий проход воркера — или
«Я подписался» в боте — записывает новое состояние, и подтверждение проходит.
Клиент без идентичности Telegram не может состоять в Telegram-канале, и его об
этом не просят.

## О выходе предупреждают до того, как он что-то стоит

Последовательность такова: compliant → warned → suspended, и она управляется
льготным периодом, который настраивает оператор.

Первая проверка, обнаружившая отсутствие клиента, предупреждает его и запускает
отсчёт. До истечения отсчёта не происходит ничего. Предупреждение срабатывает
один раз за эпизод, а не при каждой проверке, потому что ежедневное напоминание
подписаться на канал — это то, как клиент учится игнорировать бота.

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

Нулевой льготный период — законная конфигурация, и он блокирует сразу, но
предупреждение всё равно отправляется, потому что клиент, заблокированный без
предупреждения, — это клиент, который не может понять почему.

### Что получает клиент и что происходит на самом деле

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

Приостановка и восстановление не пишутся в Remnawave напрямую. Воркер ставит
fulfillment-операцию `disable` для каждого entitlement, чей оплаченный период
ещё не закончился, и `enable` для каждого, который Remnawave считает
отключённым, когда клиент возвращается, — под ключом идемпотентности, в котором
записаны entitlement и момент решения. Поэтому клиент, отключённый за выход из
канала, несёт ту же историю операций, что и отключённый оператором вручную, а
оператор, читающий журнал fulfillment, видит корреляцию `channel-gate`.
Entitlement, приостановленный оператором, не затрагивается: он выключен по
решению, которое повторная подписка отменять не должна. Состояние принуждения
записывается до попытки применить последствие, так что последствие, которое не
удалось поставить в очередь, повторяется следующим проходом, а не теряется.

## Повторная подписка восстанавливает доступ автоматически

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

`left_at` проставляется в момент, когда отсутствие замечено впервые, и
очищается при возвращении, поэтому льготный отсчёт ведётся от момента, когда
клиент действительно вышел, а не от момента, когда это заметил проход воркера.

## Исключения

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

Исключение фиксирует, кто его выдал и почему, потому что исключение, которое
никто не может объяснить, неотличимо от ошибки. Оно может иметь срок действия.

Исключение для заблокированного клиента восстанавливает его немедленно —
правило больше не применяется, а значит, не должно применяться и его следствие.
Отзыв исключения возвращает клиента в состояние `compliant`, а не сразу в
`suspended`: решает следующая проверка, и она предупреждает первой, как и для
всех остальных. Блокировка при отзыве отобрала бы доступ без всякого
уведомления.

## Кеширование и ограничение частоты запросов

Ответы о членстве кешируются на настраиваемое окно, по умолчанию шесть часов.
`getChatMember` ограничен по частоте запросов у третьей стороны, и повторный
опрос на каждом экране сделал бы бота медленнее для всех ради соблюдения
маркетингового правила.

Воркер перепроверяет ограниченными партиями, поэтому крупная установка
перепроверяется за много проходов, а не одним всплеском, из-за которого бота
начнут троттлить.

## Как это выключить

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

## Настройки

| Настройка | По умолчанию | Значение |
| - | - | - |
| `channel_grace_seconds` | 259200 (3 дня) | Сколько доступ сохраняется после выхода |
| `channel_recheck_seconds` | 21600 (6 часов) | Сколько времени ответу о членстве доверяют |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.