Files
email-assistant/openspec/changes/imap-realtime-sync/tasks.md
T

6.4 KiB
Raw Blame History

Tasks: Потоковая синхронизация почты (IMAP IDLE) и онлайновая копия ящика

Задачи

Фаза 0: Подготовка и проверка авторизации

  • 1. Установить/проверить aioimaplib (pip) — библиотека для IDLE-потока; если не ставится — зафиксировать fallback на сырой socket. (2026-09-15: aioimaplib НЕ установлен; на следующем шаге — решить ставить или идти на сыром socket, т.к. imap_client.py уже это умеет.)
  • 2. Проверить авторизацию для stream-процесса: himalaya логинится успешно (эталон), чистый IMAP-скрипт — нет. Отработать AUTH=PLAIN (SASL-IR), формат login; зафиксировать рабочий вариант в коде. (Блокер — без него stream не запустится.) Выполнено 2026-09-15: создан scripts/imap_client.py с отдельной функцией imap_connect() (STARTTLS + LOGIN + re-try против rate-limit). Реальная проверка: LOGIN как e.storozhenko прошёл, fetch_attachments_imaplib через неё скачал Переместить стол.docx 1.1 МБ (UID 14200) без \Seen. Rate-limit Exchange: после серии быстрых попыток сервер молчит (timeout), поэтому в imap_connect() re-try с экспоненциальной паузой.
  • 2b. Логирование авторизации + метрики доступности/сессии: imap_log() пишет JSON-строки в /opt/hermes/email/logs/imap_client.log (conn_ok / conn_error / auth_ok / auth_failed / session_started / session_ended); imap_metrics() считает auth_success_rate, conn_error, sessions_active; imap_session — контекстный менеджер (гарантирует session_ended). Проверено: python3 imap_client.py --metrics показывает метрики. Пароль никогда не логируется. TODO (позже): полноценный мониторинг — Prometheus-формат/статус-эндпоинт для stream-сервиса, алерты при падении auth_success_rate / conn_error.

Фаза 1: Скелет сервиса imap_stream.py

  • 3. scripts/imap_stream.py: connect + STARTTLS + login; folder list (get_inbox_subfolders); SELECT INBOX; IDLE-цикл с обработкой untagged (EXISTS/EXPUNGE/FETCH FLAGS); reconnect при обрыве.
  • 4. Реализовать reconcile: UID FETCH новых писем (>last_uid) → событие added + архивация (переиспользовать mail_archive.py); сравнение FLAGS → flag_changed; отсутствие после EXPUNGE → deleted (soft).
  • 5. SQLite schema: mailbox_state + mailbox_events (ChangeLog) — создать /opt/hermes/email/state/mailbox.db, функции init/insert/read.

Фаза 2: Change Analyzer

  • 6. scripts/change_analyzer.py: чтение mailbox_events от offset; на added — классификация (email_classifier) + обработчики (email_handlers); на moved/deleted/flag_changed — обновление mailbox_state, RAG-метка. Уведомления в ЛС Telegram уже проверены живьём (2026-09-15): письмо 3216 помечено urgent → доставка в private chat 281328953 (kpa39l), msg_id=60, подтверждено пользователем. Для ЛС нужен явный TELEGRAM_CHAT_ID=281328953 (дефолт в email_handlers.py — канал @dedinit_vesti).
  • 7. Обработка replied: \Answered или новое письмо с In-Reply-To на известный Message-ID → событие replied; обновить thread в state.

Фаза 3: systemd и интеграция

  • 8. systemd user units (email-imap-stream.service, email-change-analyzer.service), автозапуск; проверка auto-restart.
  • 9. Hermes cron mail-archive-every-5min → fallback (идемпотентен с stream; не дублирует). Проверить, что при работающем stream cron не архивирует повторно (last_uid / state).
  • 10. Живой тест: новое письмо (отправить себе/ждущее), перемещение (через IMAP MOVE/клиент), удаление, ответ — всё фиксируется в ChangeLog и mailbox_state; \Seen не ставится (проверка флагов до/после).

Фаза 4: Документация и доводка

  • 11. STATUS.md / README / WALKTHROUGH: сервисы, порты (нет новых внешних), как смотреть ChangeLog (sqlite3 mailbox.db 'select * from mailbox_events'), как перезапускать.
  • 12. RAG-интеграция (опционально, Фаза 2 проекта): индексация событий ChangeLog в Qdrant — чтобы агент мог ответить «что случилось с письмом».

Верификация

  • systemctl --user status email-imap-stream email-change-analyzer — active (running)
  • sqlite3 /opt/hermes/email/state/mailbox.db 'select count(*) from mailbox_state' — растёт
  • sqlite3 ... 'select event, count(*) from mailbox_events group by event' — есть added/moved/deleted/flag_changed
  • Новое письмо в INBOX → архив появляется в течение ~1-2 мин (не 5)
  • Перемещение письма в клиенте → в mailbox_state folder обновлён, в ChangeLog moved
  • Удаление письма → deleted в ChangeLog, файл email.md на месте (soft-delete)
  • Ответ → replied или flag_changed (\Answered)
  • Флаги непрочитанного письма на IMAP после архивации: () → () (Seen нет)