Этот бот проверяет текстовые сообщения пользователей по белому списку и пересылает разрешенные сообщения в указанный чат/группу.
Начиная с 1.1.0, бот по умолчанию говорит по-русски, показывает шаблон заявки,
различает причины отказа и имеет диагностический режим без запуска Telegram polling.
/start,/help,/template,/avtoдля пользовательского сценария.- Белый список числовых Telegram user ID из CSV.
- Понятный отказ для неизвестного пользователя и отдельный отказ для пользователя без данных отправителя.
- Защита от случайной пересылки коротких приветствий вместо заявки.
- Ответ на неподдерживаемые типы сообщений: фото, документы, стикеры, голосовые.
- Диагностика конфигурации через
telegram-resender doctor. - Проверка обязательных полей заявки и опциональное подтверждение перед пересылкой.
- Админские команды для статуса и перезагрузки whitelist без рестарта.
- Опциональные multi-route правила через
routes.json. - SQLite delivery/pending state, retry/backoff и идемпотентность по request id.
- Docker, docker-compose, systemd и health-check для production.
- Детерминированный формат пересылки с request id и временем заявки.
python -m venv .venv
.venv\Scripts\activate
pip install -e .[dev]
copy .env.example .env # Windows
# или: cp .env.example .env # Linux/macOS
telegram-resender doctor
telegram-resenderЕсли doctor сообщает об ошибке, заполните .env до запуска polling.
| Переменная | Обязательная | Описание |
|---|---|---|
TELEGRAM_RESENDER_BOT_TOKEN |
да | токен Telegram-бота |
TELEGRAM_RESENDER_FORWARD_CHAT_ID |
да | id чата/группы для пересылки |
TELEGRAM_RESENDER_WHITELIST_PATH |
нет | путь к whitelist.csv, по умолчанию whitelist.csv |
TELEGRAM_RESENDER_ROUTES_PATH |
нет | путь к JSON-файлу маршрутов |
TELEGRAM_RESENDER_LOCALE |
нет | ru или en, по умолчанию ru |
TELEGRAM_RESENDER_CONFIRM_BEFORE_FORWARD |
нет | true, чтобы показывать preview и ждать /confirm |
TELEGRAM_RESENDER_PENDING_REQUEST_TTL_SECONDS |
нет | срок жизни preview в секундах, по умолчанию 900 |
TELEGRAM_RESENDER_DELIVERY_LEASE_SECONDS |
нет | timeout stale-владельца доставки/подтверждения, по умолчанию 300 |
TELEGRAM_RESENDER_ADMIN_IDS |
нет | Telegram user id администраторов через запятую |
TELEGRAM_RESENDER_STORAGE_PATH |
нет | SQLite delivery/pending state, по умолчанию telegram_resender.sqlite3 |
TELEGRAM_RESENDER_DELIVERY_MAX_ATTEMPTS |
нет | попытки отправки в Telegram, по умолчанию 3 |
TELEGRAM_RESENDER_DELIVERY_RETRY_BACKOFF |
нет | базовая задержка retry в секундах |
TELEGRAM_RESENDER_LOG_LEVEL |
нет | DEBUG, INFO, WARNING, ERROR, CRITICAL |
TELEGRAM_RESENDER_LOG_FORMAT |
нет | TEXT или JSON, по умолчанию TEXT |
TELEGRAM_RESENDER_POLLING_TIMEOUT |
нет | таймаут polling, по умолчанию 30 |
TELEGRAM_RESENDER_REQUEST_ACCEPTED_MESSAGE |
нет | переопределение текста успешной заявки |
TELEGRAM_RESENDER_ACCESS_DENIED_MESSAGE |
нет | переопределение текста отказа неизвестному пользователю |
Формат whitelist (по одному неизменяемому числовому Telegram user ID в строке; ID можно узнать через /whoami):
123456789
987654321Пользователь может вызвать /template или /avto и отправить текст:
Объект/здание: Башня А
Дата и время прибытия: 12.06.2026 10:30
Автомобиль: Ford Focus
Госномер: А123ВС
Комментарий: встреча с отделом эксплуатации
Пока бот принимает только текст. Медиа и документы не пересылаются. Если заявка со служебным заголовком или preview превышает лимит Telegram, бот попросит сократить комментарий или другие поля.
Обязательные поля: объект/здание, дата и время прибытия, автомобиль, госномер.
Если включить TELEGRAM_RESENDER_CONFIRM_BEFORE_FORWARD=true, бот покажет preview
заявки и отправит ее администратору только после /confirm. Для нескольких preview
можно указать ID: /confirm <request_id> или /cancel <request_id>; команды без ID
относятся к последней заявке. Pending preview хранится в SQLite, переживает рестарт
процесса и истекает через настроенный TTL.
/whoamiпоказывает Telegram user id и chat id. Команда доступна всем, чтобы администратор мог узнать свой id для.env./admin_statusпоказывает версию, locale, целевой чат, размер whitelist, число администраторов и режим подтверждения./whitelist_countпоказывает текущий размер whitelist./reload_whitelistперечитывает CSV whitelist без рестарта процесса.
Все команды кроме /whoami доступны только id из TELEGRAM_RESENDER_ADMIN_IDS.
Если TELEGRAM_RESENDER_ROUTES_PATH не задан, бот использует один маршрут из
TELEGRAM_RESENDER_FORWARD_CHAT_ID. Для нескольких целей создайте JSON по образцу
routes.example.json:
{
"routes": [
{
"name": "tower-a",
"target_chat_id": -1002222222222,
"allowed_user_ids": [123456789],
"allowed_usernames": [],
"keywords_any": ["Башня А"],
"keywords_none": ["отмена"],
"template": "[{route}]\n{request}",
"enabled": true
}
]
}Заявка отправляется во все активные маршруты, где совпали пользователь и keyword-фильтры.
Для маршрутизации с контролем доступа используйте allowed_user_ids. Поле
allowed_usernames сохранено для миграционной совместимости, но Telegram username изменяем:
этот legacy-фильтр допустим только как незащитная метка поверх общего числового whitelist.
Если заданы оба поля, должны совпасть оба. Дубли JSON-ключей, пустые и некорректные
фильтры отклоняются при старте.
Если одному target chat соответствуют несколько правил, применяется первое совпавшее
правило из файла: одна заявка формирует один детерминированный payload на destination.
Бот ведет SQLite-журнал доставок. Для каждой пары request_id + target_chat_id
хранится статус pending, delivered или failed, отправитель и последняя ошибка.
Если такая пара уже доставлена, повторная обработка того же request id не отправит
сообщение второй раз.
Атомарный SQLite lease с owner/version также не дает параллельным handler-задачам
одновременно отправить одну пару. Stale lease можно занять заново после
TELEGRAM_RESENDER_DELIVERY_LEASE_SECONDS.
telegram-resender doctor --storage-check
telegram-resender health
telegram-resender export-requests --since 2026-06-12Docker:
copy .env.production.example .env.production
mkdir data
copy whitelist.example.csv data\whitelist.csv
docker compose up -d --buildDocker env template: .env.production.example. Для systemd
используйте deploy/telegram-resender.service вместе с
.env.systemd.example: оба используют
/opt/telegram-resender/data для изменяемых файлов.
cp .env.systemd.example /opt/telegram-resender/.env.productionДля production-логов включите:
TELEGRAM_RESENDER_LOG_FORMAT=JSON- Docker base image закреплен по digest в Dockerfile.
- Python runtime/dev/audit зависимости ставятся из hash-locked файлов
requirements*.lock. - GitHub Actions закреплены по commit SHA.
- Релизный workflow собирает wheel и sdist, публикует
SHA256SUMS.txtи GitHub provenance attestation. - Правила обновления зависимостей описаны в docs/DEPENDENCY_POLICY.md.
Проверка релизных артефактов:
sha256sum -c SHA256SUMS.txt
gh attestation verify telegram_resender-*.whl --repo krotname/TelegramResenderBot- Это bot-based intake/forwarding, не userbot.
- Бот не обходит protected/restricted Telegram-чаты.
- Медиа, документы, voice и polls пока не пересылаются как payload.
- Отправку в Telegram и следующий SQLite commit невозможно сделать одной атомарной операцией.
Если процесс завершится после приема сообщения Telegram, но до записи
delivered, возможна одна повторная отправка после истечения stale lease. - Отправка confirmation preview и публикация pending-строки в SQLite тоже не являются одной транзакцией. Сбой в узком промежутке может оставить видимый preview, который придется отправить заново. Pending публикуется после успешного ответа Telegram, поэтому неотправленный preview не заменяет более старую подтверждаемую заявку.
- Известные retry waits автоматически продлевают оба lease. Но отдельный Telegram API call,
зависший дольше
TELEGRAM_RESENDER_DELIVERY_LEASE_SECONDS, может быть занят заново; задавайте lease больше transport timeout текущего deployment. - AI rewrite/translate/digest не реализованы.
- Hosted SaaS, mobile app и web dashboard не входят в текущую self-hosted область.
tests/unit— чистые unit-тесты доменной логикиtests/integration— сборка сервиса и контура настроекtests/conversation— сценарии пользовательского диалогаtests/security— проверки безопасности конфигурации
Запуск:
pytest
ruff check .
mypy src testsПодробный UX/конкурентный аудит и план следующих версий: docs/ux-competitive-roadmap.ru.md.
Смотрите CONTRIBUTING.md и CODE_OF_CONDUCT.md.
Смотрите SECURITY.md и docs/DEPENDENCY_POLICY.md.