Imported from boxfrommars/calendar_bot (
AGENTS.md). Install upstream withnpx skills add boxfrommars/calendar_bot. Copyright stays with the author.
calendar-bot
Приложение на Python 3.14+ для личных Telegram-расписаний. Требования размещения
находятся в DEPLOYMENT.md; их серверную реализацию ведёт leucothea-administrator.
Инварианты
- AI возвращает структуру события; приложение проверяет её и автоматически сохраняет новые события вместе с напоминаниями. Весь список из одного сообщения записывать атомарно и без дублей при повторной обработке. Изменения существующих событий и удаление требуют подтверждения; старые черновики не сохранять автоматически. Не добавлять модели прямой доступ к БД или инструментам изменения расписания.
- Проверять
ALLOWED_USER_IDSдо AI и операций с пользовательскими данными. Пустой список никому не даёт доступ. Каждая операция с событием, исключением или карточкой проверяет владельца и версию; callback data не является доверием. - Настройки по умолчанию: напоминания
[15, 5, 1], сводка09:00, пустые дни пропускаются. Часовой пояс выбирает пользователь. - Время отправки хранить в UTC, повторы — в местном времени с IANA-поясом.
Текущее время передавать через clock; календарную арифметику держать в
domain.py. Не брать часовой пояс сервера как пользовательский. - Изменения событий и очереди атомарны. Не отправлять уведомления из старой версии после подтверждённой отмены. Не заменять постоянную очередь таймерами в памяти и не обещать exactly-once на границе SQLite/Telegram.
- Исключение привязано к исходной дате вхождения. При изменении серии сохранять переносы и отмены; прошлые вхождения не переписывать.
- SQLite-схема меняется только явными миграциями с увеличением версии. Согласованная копия — SQLite backup API, не копирование живого файла.
- Runtime использует один polling-процесс и один файл БД. Остановка должна
явно вызывать
Dispatcher.stop_polling()и завершать polling, обработчики и фонового работника до закрытия соединений. Одна отменаstart_polling()оставляет внутренние задачи aiogram работающими. - Разделять успех
getUpdatesи прогресс попыток polling. Пустой ответ — успех; ошибка запроса — прогресс для watchdog, но не успех для health. Не перезапускать приложение из-за длительной сетевой аварии, пока продолжаются повторы aiogram. Периоды считать по монотонным часам. Watchdog обслуживать из основного event loop, без независимого фонового пингера, который может скрыть зависание. healthчитает только технический снимок и существующий OS-lock текущего запуска, не вызывает API, не открывает SQLite и не создаёт файлы. Health-состояние и идентификатор владельца lock воспроизводимы, не являются данными календаря.- Шаблоны сообщений и правила оформления держать в
presentation.py. Использовать aiogramText,Bold,Italic,Codeи Telegram entities с явнымparse_mode=None. Названия и ответы модели передавать буквальным текстом; не интерполировать их в HTML/Markdown и не парсить как разметку. Позиции entities и длину сообщений считать в UTF-16. Сводки делить по целым строкам с запасом до лимита Telegram.notifications.partsсохраняет JSON-массив строк; оформление добавляется при отправке по структуре сообщения, включая старые части. Не сбрасыватьpart_indexи не редактировать историю переписки. - Не читать и не печатать
.env, секреты, пользовательские БД и backup. В исключениях внешних SDK могут быть токены и текст запросов: логировать безопасный тип/код ошибки, не исходное тело ответа. ОшибкиGetUpdatesнаблюдать request middleware вpolling.py; не включать исходные логи aiogram ради диагностики polling.
Проверки
Из активного виртуального окружения:
python -m unittest discover -s tests -q
ruff check calendar_bot tests
ruff format --check calendar_bot tests
Для изменений времени, очереди, БД или интерфейса использовать соответствующие
тесты с управляемыми часами и подставными API. Тесты не должны обращаться в сеть
или зависеть от пользовательских секретов. Живые проверки Telegram проводить
только отдельным тестовым токеном. calendar_bot.evaluation — отдельная платная
проверка OpenAI, не часть обычного набора.
Production-зависимости фиксируются в requirements.txt с хешами; исходные
ограничения — requirements.in. Целевая версия Python — 3.14; она же указана в
.python-version и настройках Ruff. После изменения зависимостей пересоздать
lock для Python 3.14 и проверить установку и тесты на этой версии.
Не менять lock вручную и не поддерживать совместимость с Python младше 3.14.
Документация
Обновлять затронутую документацию в том же изменении:
README.md— назначение, поведение, структура, локальная настройка и разработка.DEPLOYMENT.md— runtime, зависимости, конфигурация, writable-потребности, постоянные данные, lifecycle hooks, миграции, внешнее поведение и rollback.AGENTS.md— устойчивые правила репозитория.
DEPLOYMENT.md следует актуальному templates/deployment-handoff.md из
leucothea-administrator. Держать в нём требования приложения и проверяемые
результаты: пути относительные либо через переменные окружения, без конкретных
хостов, серверных путей, пользователей ОС и команд развёртывания. Первичную
инициализацию пустой БД и миграции существующих данных описывать отдельно от
воспроизводимых lifecycle hooks.
Для правок только документации проверять ссылки, заявленные команды и соответствие исходникам; использовать безопасные автономные проверки по необходимости. Не запускать рабочий бот, платную evaluation и миграции пользовательской БД ради проверки документации.
