feat: классификация писем Qwen3:8b + обработчики (urgent→TG, task→VTODO, meeting→VEVENT)

- mail_archive.py: фикс вложений himalaya --dir → --downloads-dir; attachments/ только при has_attachment; идемпотентно
- email_classifier.py: Qwen3:8b (Ollama) → теги info/urgent/task/meeting в frontmatter email.md
- email_handlers.py: urgent→Telegram (Bot API+SOCKS5), task→Radicale VTODO, meeting→Radicale VEVENT; handled_* идемпотентность; --dry-run
- .gitignore: игнор *.env.bak*
- openspec: чейндж email-classification-handlers (в работе)
- STATUS/TODO/WALKTHROUGH: прогресс сессии, подводные камни Radicale (http.client, Depth:1, формат дат)
This commit is contained in:
2026-09-13 20:35:58 +00:00
parent 8ea022f5c0
commit 7550aff102
22 changed files with 1728 additions and 76 deletions
@@ -0,0 +1,83 @@
# Design: Убрать Vikunja, задачи через Radicale (VTODO)
## Context
- Radicale (CalDAV/CardDAV) развёрнут, календари Личный/Рабочий/Задачи на ФС.
Публично: cal.nixg.ru (Caddy vps02 → 10.8.0.2:5232).
- Vikunja развёрнут (compose `/opt/hermes/email-assistant/vikunja/`, контейнеры
`vikunja` + `vikunja-db` postgres, :3456), но админ/API-токен НЕ созданы —
это блокер для обработчика `task` в classification-чейндже.
- Календарь «Задачи» в Radicale уже существует (VTODO-совместимый).
- Android: jtx board синхронизирует VTODO по CalDAV через DAVx5.
## Goals / Non-Goals
**Goals:**
- Убрать Vikunja как лишнюю сущность.
- Задачи создаются через Radicale VTODO (календарь «Задачи»).
- Обработчик `task` в classification-чейндже пишет VTODO, не зависит от Vikunja.
- Обновить документацию/список задач.
**Non-Goals:**
- Не мигрируем данные из Vikunja (их там нет — сервис не администрирован).
- Не удаляем данные Radicale — только добавляем VTODO.
- Не трогаем Caddy, если tasks.nixg.ru ещё не настроен (только не настраивать).
## Decisions
### D1: Vikunja выводится из эксплуатации
Контейнеры `vikunja` и `vikunja-db` останавливаются и удаляются:
```bash
cd /opt/hermes/email-assistant/vikunja
docker compose down -v # или docker stop vikunja vikunja-db && docker rm ...
```
- Данные (volume `vikunja-db`) можно удалить (сервис не использовался),
либо сделать бэкап перед удалением (аккуратно — «не удалять данные
пользователя»). Решение: сделать копию volume/postgres-дампа на всякий случай,
затем удалить контейнеры; compose.yml/.env пометить deprecated или удалить
после подтверждения пользователя.
### D2: Обработчик task → Radicale VTODO
В чейндже `email-classification-handlers` обработчик `task` меняется с
«Vikunja API POST» на «Radicale CalDAV PUT VTODO»:
- URL: `https://cal.nixg.ru/estorozhenko/<urlencoded 'Задачи'>/<uid>.ics`
- Auth: Basic (estorozhenko:пароль Radicale)
- Body: VCALENDAR + VTODO (SUMMARY=тема, DESCRIPTION=ссылка на email.md,
при наличии даты — DTSTART/DUE)
- Пометить `handled_task: true` после успешного PUT (201/204)
- Идемпотентность: если `handled_task: true` — пропустить
### D3: tasks.nixg.ru
- Если reverse proxy уже настроен в Caddy — закомментировать/убрать.
- Если нет — не настраивать. Единственный домен: cal.nixg.ru.
### D4: Android — jtx board
Для задач (VTODO) используется jtx board, синхронизация через DAVx5 (Radicale).
В STATUS.md зафиксировать: «задачи = Radicale VTODO, jtx board».
### D5: Чейндж email-classification-handlers — правка
В `email-classification-handlers`:
- specs/email-handlers/spec.md: «Создание задачи в Vikunja» → «Создание задачи
в Radicale (VTODO)»
- design.md: убрать Vikunja-ветку, заменить на Radicale VTODO
- tasks.md: задача 3.3 (Vikunja API) → Radicale VTODO; задача 4.1 (админ Vikunja)
→ удалить
Это правки в активном чейндже — внести сразу.
## Risks / Trade-offs
- **Vikunja данные** — если в Vikunja что-то было создано, удаление volume потеряет
это. Митигирует: бэкап volume/postgres-дамп перед удалением.
- **VTODO-совместимость клиентов** — Radicale хранит VTODO как файлы, jtx board
их читает. Риск низкий (стандарт CalDAV).
- **Ссылка на email.md в DESCRIPTION** — на телефоне путь недоступен (локальный
диск), но виден в reason/задаче. Это ок: задача показывает тему + обоснование.
- **Уже развёрнутый Vikunja** — вывод из эксплуатации надо делать аккуратно,
с бэкапом и подтверждением (не удалять данные пользователя без спроса).
## Verification
1. `docker ps` — контейнеры vikunja/vikunja-db отсутствуют.
2. `curl -X PROPFIND https://cal.nixg.ru/estorozhenko/Задачи/` — календарь доступен.
3. Создать VTODO через обработчик → `curl GET .../Задачи/<uid>.ics` — VTODO есть.
4. `openspec validate remove-vikunja-use-radicale-tasks` — valid.