Files
email-assistant/openspec/changes/contacts-caldav-server/proposal.md
T

70 lines
4.9 KiB
Markdown

# Proposal: CardDAV-сервер для синхронизации контактов
## Why
Сейчас контакты, извлечённые LLM из подписей писем, лежат только в файлах
`/opt/hermes/email/contacts/{contacts.json, contacts.vcf, index.json}` и никуда
не синхронизируются. Чтобы пользоваться ими на телефоне (Android) и в других
клиентах, нужен CardDAV-сервер с адресными книгами, куда контакты пишутся
сразу при извлечении.
Почему CardDAV, а не просто наличие .vcf: нативный Android (DAVx5) и
большинство клиентов умеют только CardDAV-протокол. Отдельный файл .vcf на
диске никто не читает.
## What Changes
1. **Radicale расширяется на CardDAV** — это тот же сервис Radicale (:5232),
который уже развёрнут для CalDAV (календарь). Radicale из коробки умеет
CardDAV (addressbook collections). Нужно только:
- создать адресную книгу (например `Контакты`) в коллекциях Radicale
- проверить CardDAV-endpoint (`/estorozhenko/Контакты/`)
2. **Контакты пишутся сразу в карточки** — contacts_extractor.py после
извлечения и дедупликации пишет/обновляет vCard в Radicale через
CardDAV PUT, а не только в локальные файлы:
- на каждый контакт — один `.vcf` в адресной книге
- при обновлении контакта — PUT с новым ETag
- удаление контакта, которого больше нет в базе — DELETE (опционально, см. design)
3. **Двусторонний синк** — правки, сделанные с телефона (DAVx5) в адресной
книге, синхронизируются обратно в `contacts.json`:
- изменённые карточки → обновление контакта
- новые карточки → новые контакты
- удалённые карточки → soft-delete (`deleted: true`) в базе
- конфликт (изменено и в почте, и на телефоне) → приоритет телефону,
локальная версия сохраняется в лог, данные не теряются
4. **Локальная база contacts.json** остаётся источником истины (дедупликация,
трекинг processed_uids) и хранит состояние синка (ETag карточки).
## Capabilities
### New Capabilities
- `contacts/carddav-sync`: Синхронизация извлечённых из почты контактов
в CardDAV-сервер (Radicale) — создание/обновление/удаление vCard-карточек,
доступных клиентам (DAVx5 на Android и др.)
### Modified Capabilities
<!-- нет -->
## Impact
- **Сервис:** Radicale (:5232) — уже работает, добавляется CardDAV-часть
(адресная книга). Новых портов нет.
- **Скрипт:** `scripts/contacts_extractor.py` — добавляется синк в Radicale
(PUT/DELETE vCard), появляется зависимость от CardDAV-клиента/HTTP.
- **Данные:** контакты синхронизируются на сервер; конфликты при
параллельном редактировании на телефоне решаются по ETag (см. design).
- **Документация:** обновить README/STATUS (как подключить адресную книгу
на Android, порты).
- **Риски:** двусторонний синк требует разрешения конфликтов (в change —
приоритет телефону + лог локальной версии, см. REQ-011).
## Rollback
1. Отключить синк: убрать шаг синка в `contacts_extractor.py` (флаг
`--no-caldav` / откат коммита) — локальные файлы и база не затрагиваются.
2. Удалить адресную книгу из Radicale: `rm -rf
/opt/hermes/email-assistant/radicale/data/collections/collection-root/estorozhenko/Контакты`
(или через DAVx5).
3. Radicale сам не откатывается — он как был, так и остаётся (CalDAV
календарь продолжает работать).
4. Данные локально не теряются: contacts.json/contacts.vcf остаются.