# План изменений: расписание напоминаний ## Цели 1. Добавить расписание для напоминаний: бот должен писать только в явно разрешенные часы. 2. По умолчанию разрешенное окно: с 07:00 до 23:00 по МСК. 3. Если пользователь сам написал заметку, следующий reminder должен быть отложен минимум на 1 час. ## План ### 1. Расширить конфиг - Добавить переменные в `.env.example` и `README.md`: - `REMINDER_START_HOUR` - `REMINDER_END_HOUR` - `REMINDER_TIMEZONE` - Значения по умолчанию: - `REMINDER_START_HOUR=7` - `REMINDER_END_HOUR=23` - `REMINDER_TIMEZONE=Europe/Moscow` - В `config.py` парсить часы как `int`, timezone через `zoneinfo.ZoneInfo`. ### 2. Изменить модель напоминаний - Сейчас `send_reminders()` просто спит случайное число секунд между min/max. - Нужно рассчитывать следующий момент отправки с учетом: - разрешенного окна времени; - случайного интервала `REMINDER_MIN_HOURS` / `REMINDER_MAX_HOURS`; - timezone; - ночного периода, когда отправка запрещена. ### 3. Добавить сброс после ручной заметки - В `main.py` после успешного `journal.append(...)` сообщать планировщику, что пользователь сам написал заметку. - Простой вариант: передать в `send_reminders()` общий объект состояния, например `ReminderScheduler` или `ReminderState`. - В состоянии хранить `last_manual_entry_at`. - При ручной записи следующий reminder должен быть не раньше `last_manual_entry_at + 1 hour`. ### 4. Сделать отдельную логику планирования - Минимально оставить `send_reminders()` в `modules/reminders.py`, но добавить функции: - `is_allowed_time(now, start_hour, end_hour)` - `next_window_start(now, start_hour, timezone)` - `calculate_next_reminder(...)` - Не усложнять классами без необходимости, но небольшой объект состояния между handler и background task может быть оправдан. ### 5. Учесть edge cases - Если сейчас ночь, следующий reminder переносится на 07:00 МСК. - Если случайный интервал попадает за 23:00, reminder переносится на следующее 07:00. - Если пользователь написал заметку в 22:30, минимальная задержка до 23:30, но окно уже закрыто, значит следующий reminder не раньше 07:00 следующего дня. - Если пользователь написал ночью, reminder не раньше max(`+1 hour`, ближайшее 07:00). - Если `REMINDER_START_HOUR >= REMINDER_END_HOUR`, лучше сразу падать с понятной ошибкой, чтобы не поддерживать ночные окна. ### 6. Обновить документацию - README на русском: описать новое окно отправки. - `.env.example`: добавить новые переменные. - При необходимости обновить `AGENTS.md`, чтобы зафиксировать новые env vars и правило про timezone. ### 7. Проверка - Запустить `uv run python -m compileall main.py config.py modules`. - Если добавятся чистые функции расчета времени, можно добавить тесты позже, но сейчас отдельной тестовой инфраструктуры нет. ## Лог реализации - Шаг 1: добавлены настройки `REMINDER_START_HOUR`, `REMINDER_END_HOUR`, `REMINDER_TIMEZONE` в `config.py`; часы валидируются как диапазон 0-23, окно должно быть start < end. - Шаг 2: в `modules/reminders.py` добавлен минимальный `ReminderState`, расчет следующего reminder с учетом окна времени и пробуждение sleep через `asyncio.Event` при ручной записи. - Шаг 3: `main.py` создает `ReminderState`, передает его в `send_reminders()` и вызывает `mark_manual_entry()` после успешного сохранения заметки. - Шаг 4: обновлены `.env.example`, `README.md` и `AGENTS.md` с новыми настройками окна напоминаний, timezone и правилом задержки после ручной заметки. - Проверка: `uv run python -m compileall main.py config.py modules` прошла успешно; `uv` создал локальную `.venv`, она игнорируется `.gitignore`.