Skip to content

Ignat1990/ReminderBot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Reminder Bot

Телеграм-бот-напоминалка на Spring Boot. Пользователь пишет /add, бот спрашивает текст и время, а дальше сам присылает напоминание в нужный момент — с кнопками "готово" / "удалить" прямо в сообщении.

Делал как второй пет-проект после shop-бэкенда, чтобы закрыть то, что туда не влезло: работу с Telegram Bot API, FSM для многошагового диалога и persistent-джобы для отложенных уведомлений.

Стек

Слой Технология
Язык / рантайм Java 17, Spring Boot 3.2
Telegram API TelegramBots 9.5.0 — модульная библиотека (telegrambots-longpolling + telegrambots-client + telegrambots-meta), long polling
БД PostgreSQL + Spring Data JPA + Flyway
Состояние диалога Redis (FSM с TTL)
Отложенные напоминания Spring ThreadPoolTaskScheduler
Инфраструктура Docker + Docker Compose (app + postgres + redis)

Как это работает

Бот работает через long polling, не вебхук — не нужен домен и TLS-сертификат, поднимается локально одной командой. Все апдейты от Telegram идут через TelegramUpdateDispatcher: команды (/start, /add, /list...) роутятся по имени, а обычный текст — по текущему состоянию диалога (FSM), которое лежит в Redis (session:{chatId}).

Update ──▶ TelegramUpdateDispatcher
              ├─ команда (/add, /list...) ──▶ соответствующий CommandHandler
              ├─ callback (кнопка)        ──▶ CallbackQueryHandler
              └─ обычный текст            ──▶ смотрим BotState в Redis
                                                 ├─ AWAITING_TASK_TEXT ──▶ AddTaskHandler.onTaskText
                                                 └─ AWAITING_TASK_TIME ──▶ AddTaskHandler.onTaskTime

/add — это три шага: спросили текст → спросили время → сохранили задачу в Postgres и поставили job в ThreadPoolTaskScheduler на нужный момент.

Отдельный нюанс: ScheduledFuture живут только в памяти процесса — при рестарте бота все запланированные джобы теряются. Поэтому ReminderSchedulerService при старте перечитывает из базы все PENDING-задачи с due_at в будущем и пересоздаёт джобы — без этого шага активные напоминания после любого деплоя молча пропадали бы.

Запуск

cp .env.example .env   # вписать токен от @BotFather в BOT_TOKEN
docker compose up --build

Поднимутся: приложение (:8081), PostgreSQL (:5432), Redis (:6379).

Без реального BOT_TOKEN приложение всё равно поднимется и пройдёт все тесты — удобно для CI. Просто long polling не запустится, в логах будет warning: BOT_TOKEN не задан — бот не запущен.

Локально без Docker

mvn spring-boot:run

Нужен свой Postgres и Redis на портах из application.yml (или переопредели через переменные окружения DB_HOST, DB_PORT, REDIS_HOST, REDIS_PORT).

Переменные окружения

Переменная Обязательна По умолчанию Что это
BOT_TOKEN да (для реального запуска) токен от @BotFather
BOT_USERNAME нет username бота без @, для справки
DB_HOST / DB_PORT нет localhost / 5432 Postgres
DB_NAME / DB_USER / DB_PASSWORD нет reminderbot / reminderbot / reminderbot Postgres
REDIS_HOST / REDIS_PORT нет localhost / 6379 Redis

Команды бота

Команда Что делает
/start регистрация чата в базе, приветствие со списком команд
/add добавить напоминание — бот спросит текст, потом время
/list активные напоминания, каждое с кнопками ✅ "готово" / 🗑 "удалить"
/cancel прервать текущий диалог (например, если начал /add и передумал)
/help список команд + формат времени

Формат времени при добавлении:

  • относительный — 10m (через 10 минут), 2h, 1d
  • абсолютный — 2026-07-05 18:00 (зона Europe/Vilnius захардкожена, см. ограничения ниже)

Структура проекта

config/     — Spring-конфигурация: бин TelegramClient, Redis-сериализация, scheduler
security/   — (нет — у бота нет HTTP API, аутентификация не нужна)
entity/     — AppUser, Task, TaskStatus
repository/ — Spring Data JPA поверх Postgres
fsm/        — BotState, UserSession, SessionService (Redis)
bot/        — диспетчер апдейтов, обработчики команд, клавиатуры, отправка сообщений
service/    — UserService, TaskService, ReminderSchedulerService
util/       — DateTimeParser

Что не доделано / roadmap

  • Вебхук как альтернатива long polling — не добавлял, для пет-проекта overkill (нужен публичный HTTPS с валидным сертификатом).
  • Таймзона пользователя — поле app_users.timezone в базе уже есть, но DateTimeParser его пока не читает: у всех время интерпретируется как Europe/Vilnius.
  • Пагинация в /list отсутствует — если у пользователя накопится полсотни напоминаний, бот честно зафлудит чат полусотней сообщений подряд.
  • Повторная отправка — если TelegramApiException вылетит при отправке напоминания (сеть, бот заблокирован пользователем и т.п.), ReminderSchedulerService просто залогирует ошибку, retry нет.
  • Тесты — только контекстный тест на подъём приложения; юнит-тестов на DateTimeParser и переходы FSM нет.

Известные грабли при сборке (уже исправлено, но конкретно из-за этого стека)

Если собираешь на свежей JDK (21+), а особенно на самых новых (23+), можешь упереться в несовместимость версий транзитивных зависимостей, которые spring-boot-starter-parent подтягивает по умолчанию, — они не успевают за новыми JDK:

  • Lombok — старая managed-версия падает на новых javac с ExceptionInInitializerError / TypeTag :: UNKNOWN. В pom.xml версия зафиксирована явно через <lombok.version>.
  • Mockito / Byte Buddy — managed-версии не умеют мокать классы на самых новых JDK (Java XX is not supported by the current version of Byte Buddy). Обе версии зафиксированы явно (<mockito.version>, <byte-buddy.version>).
  • TelegramBots 9.x — библиотека в 9.x прошла крупный рефакторинг вслед за Telegram Bot API 7.0+ (Message переехал в подпакет objects.message, CallbackQuery.getMessage() теперь возвращает MaybeInaccessibleMessage, а не Message). Если после обновления версии библиотеки что-то не компилируется — первым делом смотри How To Update в документации авторов, там описаны все breaking changes по версиям.

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

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors