8.0 KiB
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_statefolder обновлён на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— архивация не останавливается полностью