Files

78 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasks: Потоковая синхронизация почты (IMAP IDLE) и онлайновая копия ящика
## Задачи
### Фаза 0: Подготовка и проверка авторизации
- [ ] 1. Установить/проверить `aioimaplib` (pip) — библиотека для IDLE-потока;
если не ставится — зафиксировать fallback на сырой socket.
(2026-09-15: `aioimaplib` НЕ установлен; на следующем шаге — решить
ставить или идти на сыром socket, т.к. imap_client.py уже это умеет.)
- [x] 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 с экспоненциальной паузой.
- [x] 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 нет)