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

8.0 KiB
Raw Blame History

imap-realtime-sync Specification

ADDED Requirements

Requirement: REQ-IMAP-SYNC-001: Постоянное IMAP-соединение с IDLE

Система MUST поддерживать постоянное IMAP-соединение с почтовым сервером (mail.corpoffice.tech:143, STARTTLS) с использованием команды IDLE (поддерживается сервером, проверено в CAPABILITY), чтобы узнавать о новых письмах и изменениях в ящике мгновенно, без опроса по расписанию.

Scenario: Новое письмо появляется в INBOX

  • GIVEN сервис email-imap-stream запущен и держит IDLE-соединение с INBOX
  • WHEN в INBOX приходит новое письмо
  • THEN сервис получает уведомление * N EXISTS от сервера в течение секунд (не дольше таймаута IDLE) И инициирует архивацию письма

Scenario: IDLE-соединение обрывается

  • GIVEN IDLE-соединение активно
  • WHEN сервер закрывает соединение (таймаут/сбой)
  • THEN сервис автоматически переподключается и выполняет полный reconcile (синхронизацию изменений), чтобы не пропустить события, случившиеся во время обрыва

Requirement: REQ-IMAP-SYNC-002: Reconcile как страховка от пропущенных событий

Сервис MUST периодически (не реже 1 раза в 5 минут) выполнять reconcile — полную сверку состояния ящика с сервером (UID FETCH / STATUS), потому что IDLE не гарантирует доставку всех событий (особенно при длительных соединениях).

Scenario: Событие потеряно при обрыве

  • GIVEN сервис работал, но IDLE оборвался на 3 минуты, за это время письмо было перемещено пользователем
  • WHEN сервис переподключается и делает reconcile
  • THEN перемещение обнаруживается и фиксируется в ChangeLog

Requirement: REQ-IMAP-SYNC-003: Архивация без установки \Seen

Любое скачивание тела/вложений (по событию IDLE или reconcile) MUST NOT выставлять IMAP-флаг \Seen. Используется существующий fetch_attachments_imaplib() (BODY.PEEK[]) и чтение с --preview.

Scenario: Новое письмо архивируется по событию

  • GIVEN новое письмо в INBOX с флагами () (непрочитанное)
  • WHEN сервис по событию IDLE архивирует письмо
  • THEN на IMAP флаги письма остаются () (письмо остаётся непрочитанным)

Requirement: REQ-IMAP-SYNC-004: Онлайновая копия ящика

Система MUST вести онлайновую копию ящика в SQLite (mailbox_state): для каждого письма — текущий folder, UID, флаги, Message-ID, References/In-Reply-To, дата и время последнего изменения. Копия обновляется при каждом событии.

Scenario: Письмо перемещено пользователем

  • GIVEN письмо было в INBOX, пользователь переместил его в INBOX/Проекты
  • WHEN сервис получает событие пересмещения (MOVE/UIDPLUS или reconcile)
  • THEN в mailbox_state folder обновлён на INBOX/Проекты, в ChangeLog записано событие moved

Scenario: Письмо удалено пользователем

  • GIVEN письмо было в ящике
  • WHEN пользователь удаляет письмо (EXPUNGE/FLAGS \Deleted)
  • THEN в mailbox_state письмо помечается удалённым (soft-delete), в ChangeLog записано событие deleted; файл письма в архиве сохраняется

Requirement: REQ-IMAP-SYNC-005: Журнал изменений (ChangeLog)

Система MUST вести append-only журнал изменений (mailbox_events): каждое событие (added / moved / deleted / flag_changed / replied) с timestamp, folder, UID, Message-ID. Журнал служит источником истины для анализатора и RAG.

Scenario: Запись о новом письме

  • GIVEN сервис обнаружил новое письмо
  • WHEN письмо заархивировано
  • THEN в mailbox_events создана запись added с полным контекстом (UID, folder, Message-ID, timestamp)

Scenario: Запись об ответе

  • GIVEN пользователь ответил на письмо (флаг \Answered или новое письмо с In-Reply-To)
  • WHEN сервис видит изменение
  • THEN в ChangeLog записано событие replied (по References/In-Reply-To) или flag_changed (для \Answered)

Requirement: REQ-IMAP-SYNC-006: Анализатор изменений

Система MUST иметь отдельный процесс (email-change-analyzer), который читает ChangeLog и обновляет производные данные: online-копию, RAG-индексы, классификацию/обработчики. Анализатор работает по событиям (потоково), а не по расписанию.

Scenario: Новое письмо → классификация и обработчики

  • GIVEN в ChangeLog появилось событие added
  • WHEN анализатор обрабатывает событие
  • THEN запускается классификация (Qwen3:8b) и обработчики (urgent→TG, task→VTODO, meeting→VEVENT) — как сейчас, но по событию, без ожидания cron

Scenario: Письмо удалено → RAG-индексы

  • GIVEN в ChangeLog событие deleted
  • WHEN анализатор обрабатывает событие
  • THEN RAG/индекс помечает письмо удалённым (не удаляя файл) — при поиске агент может сказать «это письмо удалено пользователем»

Requirement: REQ-IMAP-SYNC-007: Управление как systemd-сервисами

Сервисы MUST работать как постоянные процессы под systemd (user units), автозапуск при логине, auto-restart при падении, логи в journald. Hermes cron остаётся как fallback-reconcile (страховка, если оба сервиса не работают).

Scenario: Сервис упал

  • GIVEN email-imap-stream.service запущен
  • WHEN процесс падает/убивается
  • THEN systemd перезапускает его автоматически (Restart=always), при старте — reconcile

Scenario: Оба сервиса не работают

  • GIVEN оба сервиса остановлены (например, после перезагрузки без автозапуска)
  • WHEN проходит 5 минут
  • THEN Hermes cron (fallback) запускает mail_archive.py — архивация не останавливается полностью