Селфхостед Telegram-бот напоминаний. Разовые и периодические напоминания создаются кнопками (без запоминания синтаксиса команд), работает в личке и в группах, умеет тегать выбранных участников чата, ограничивает доступ через allowlist и по желанию подчищает служебный мусор в чате.
Всё состояние живёт в одном файле SQLite. При перезапуске бот восстанавливает запланированные задачи из БД, так что напоминания не теряются.
- Разовые напоминания — «напомни 31.12 в 18:00».
- Периодические напоминания:
- каждый день в заданное время;
- по выбранным дням недели (Пн/Ср/Пт и т.п.);
- каждые N дней с датой старта;
- каждое N-е число месяца (в т.ч. «последний день месяца»; если в месяце нет 29/30/31-го — сработает в последний день);
- каждый год в заданную дату — для дней рождения и памятных дат (29.02 в невисокосные годы срабатывает 28.02).
- Догон после простоя: если бот был выключен в момент срабатывания (рестарт, пересоздание контейнера), при старте он дошлёт пропущенные напоминания с пометкой — в пределах окна
CATCHUP_WINDOW_HOURS. - Кнопочный визард — весь процесс создания идёт через инлайн-кнопки, с возможностью в любой момент ввести дату/время/число вручную сообщением.
- Работа в группах — при срабатывании бот тегает адресатов. Кому напоминать, выбирается из участников чата (всех сразу или конкретных людей). В личке адресат всегда сам пользователь.
- Список и редактирование —
/listпоказывает активные напоминания, у каждого кнопки «Изменить» (время / текст / адресаты) и «Удалить» (с подтверждением). Разовые и «каждые N дней» можно сдвигать на ±N дней без пересоздания: у разовых двигается дата, у периодических — вся сетка, с якорем на ближайшее срабатывание (после «+7» следующее придёт на 7 дней позже, дальше каждые N дней от него). - Форматирование текста — жирный, курсив, ссылки из вашего сообщения сохраняются и приходят в напоминании.
- Контроль доступа — админы задаются в
.env, остальным доступ выдаётся через allowlist (командами или reply’ем на сообщение человека). - Авточистка чата (опционально) — удаляет системные сообщения и служебную переписку с ботом, оставляя сами сработавшие напоминания и обычные сообщения людей.
- Устойчивость — источник правды это SQLite; после рестарта/пересборки задачи планируются заново из БД.
| Команда | Кто может | Что делает |
|---|---|---|
/remind |
allowlist | Запустить визард создания напоминания |
/list |
allowlist | Показать активные напоминания (с кнопками изменить/удалить) |
/del <id> |
allowlist | Удалить напоминание по номеру |
/whoami |
allowlist | Показать свой ID и роль |
/start, /help |
все | Краткая справка |
/cancel |
— | Прервать создание/редактирование |
/allow <id> [пометка] |
админ | Дать доступ (можно reply’ем на сообщение) |
/disallow <id> |
админ | Забрать доступ |
/allowlist |
админ | Кто имеет доступ |
/cleanup on|off |
админ | Включить/выключить авточистку чата |
Чтобы команды показывались в списке по кнопке «☰ Меню» рядом с полем ввода и подсказывались при наборе /, добавьте их через @BotFather: команда /setcommands, затем выбрать бота и прислать список в формате команда - описание (без слэша, по одной на строку).
Удобный набор для обычного пользователя:
remind - создать напоминание
list - мои напоминания
del - удалить напоминание по id
whoami - мой ID и роль
help - справка
Админские команды в общее меню добавлять не обязательно — они и так работают. Если хочется, можно добавить и их, но учтите, что меню одно на всех и остальные пользователи их тоже увидят (толку от них без прав админа не будет):
allow - выдать доступ
disallow - забрать доступ
allowlist - список доступа
cleanup - авточистка чата on/off
Набор — дело вкуса: можно вписать все команды, только основные или вообще пропустить этот шаг, бот работает и без меню.
Наберите /remind и дальше идите по кнопкам:
- Тип — разовое или периодическое.
- Когда:
- разовое → день (Сегодня / Завтра / +N / своя дата) и время;
- периодическое → частота (каждый день / по дням недели / каждые N дней / каждое число месяца / каждый год), затем при необходимости дни недели, дату старта, число месяца или дату года, и время.
- Текст — пришлите сообщением (форматирование сохраняется).
- Кому (только в группах) — выберите одного, нескольких или всех.
На шагах с датой/временем/числом можно нажать «своё» и ввести значение вручную: дата — ДД.ММ или ДД.ММ.ГГГГ (понимает и свободные формы вроде «3 июля», «завтра»), время — ЧЧ:ММ. Если год не указан и дата уже прошла, берётся следующий год.
Визард сам отменяется после 10 минут бездействия, черновик при этом удаляется.
Из-за ограничений Telegram есть пара моментов с первым контактом:
- В личке. Бот не может написать пользователю первым — человек должен сам начать диалог с ботом (нажать Start / отправить любое сообщение). В этом боте напоминания в личке и так приходят тому, кто их создал, а создать их можно только написав боту, так что активация происходит сама собой.
- В группе. Чтобы человек появился в списке «кому напоминать», бот должен его хотя бы раз «увидеть». Просто молчаливого присутствия в группе недостаточно. Надёжные способы отметиться: выполнить
/start,/whoamiили/remind. Если у бота не отключён режим приватности (Privacy Mode в @BotFather, включён по умолчанию), обычные сообщения участников он не получает и в список они не попадут — тогда человеку нужно либо выполнить одну из команд выше, либо ответить реплаем на сообщение бота / упомянуть его. Как вариант — отключить Privacy Mode у @BotFather, чтобы бот видел всех пишущих в группе.
Изначально пользоваться ботом могут только админы из ADMIN_IDS. Чтобы пустить остальных, админ добавляет их в allowlist: /allow 123456789 Вася или ответом /allow на сообщение нужного человека. Свой ID можно узнать командой /whoami.
Скопируйте пример окружения и заполните своими значениями:
cp .env.example .envПеременные:
| Переменная | Обяз. | По умолчанию | Описание |
|---|---|---|---|
BOT_TOKEN |
да | — | Токен от @BotFather |
ADMIN_IDS |
желательно | пусто | ID админов через запятую. Только они правят allowlist — впишите хотя бы свой ID, иначе управлять доступом будет некому |
TZ |
нет | Europe/Moscow |
Таймзона по умолчанию (имя из tz database) |
DB_PATH |
нет | reminders.db |
Путь к файлу БД (в docker-compose переопределяется на /data/reminders.db) |
CLEANUP |
нет | off |
Авточистка по умолчанию (on/off). Переключается в каждом чате командой /cleanup |
CATCHUP_WINDOW_HOURS |
нет | 24 |
Догон после простоя: досылать пропущенные напоминания не старше этого окна (часов), с пометкой. 0 — отключить. Разовые, пропущенные за пределами окна, деактивируются |
Нужен Python 3.12+.
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # и заполнить BOT_TOKEN, ADMIN_IDS
python bot.pyФайл БД (reminders.db) создастся автоматически рядом с ботом.
cp .env.example .env # заполнить BOT_TOKEN, ADMIN_IDS
docker compose up -d --build
docker compose logs -f # смотреть логи
docker compose down # остановитьБД хранится в ./data на хосте (том смонтирован в /data внутри контейнера), поэтому переживает пересборку образа. Путь к БД в compose уже переопределён на /data/reminders.db.
docker build -t tickd .
docker run -d --name tickd \
--env-file .env \
-e DB_PATH=/data/reminders.db \
-v "$(pwd)/data:/data" \
--restart unless-stopped \
tickdКогда включена (/cleanup on), бот удаляет:
- системные сообщения (кто вошёл/вышел, смена фото/темы и т.п.) — примерно через 30 секунд;
- служебную переписку с ботом (команды, подтверждения, списки, шаги визарда) — примерно через 5 минут.
Сработавшие напоминания и обычные сообщения людей не трогаются.
Настройка своя для каждого чата и хранится в БД. Чтобы бот мог удалять чужие сообщения в группе, дайте ему право «Удаление сообщений» в настройках группы.
Проект разбит на небольшие модули:
| Модуль | Ответственность |
|---|---|
bot.py |
Точка входа: сборка приложения, регистрация хендлеров, обработка ошибок |
config.py |
Переменные окружения, константы, логирование |
db.py |
Подключение к SQLite, схема, миграции, учёт участников |
drafts.py |
CRUD напоминаний и черновиков |
access.py |
Allowlist и декораторы доступа (restricted, admin_only) |
cleanup.py |
Авточистка и служебная отправка сообщений |
keyboards.py |
Инлайн-клавиатуры и UI-хелперы |
formatting.py |
Отображение напоминаний |
scheduler.py |
Планирование и срабатывание задач (JobQueue) |
commands.py |
Простые команды, allowlist, фоновые хендлеры |
wizard.py |
Визард создания (ConversationHandler) |
edit.py |
Удаление и редактирование из /list |
Хранилище — SQLite. При старте restore_jobs перечитывает активные напоминания и заново ставит их в планировщик, поэтому перезапуск бота ничего не теряет. Кроме того, при каждом планировании в БД записывается расчётное время следующего срабатывания (next_run_at): если при старте оно оказалось в прошлом — значит, срабатывание пришлось на простой, и бот дошлёт его с пометкой «пропущено во время простоя» (свежее окна CATCHUP_WINDOW_HOURS; протухшие разовые деактивируются).
Стек: python-telegram-bot 21.6 (с job-queue), dateparser, python-dotenv.