Идея: near-realtime синк с Obsidian на мобильных через LiveSync (CouchDB), поверх git-sync #153

Open
opened 2026-06-24 05:36:38 +03:00 by Ghost · 0 comments

Идея: near-realtime синхронизация с Obsidian на мобильных через LiveSync (CouchDB), поверх git-sync

Контекст

В PR #119 (feat/git-sync, pulls/119) уже построен двусторонний синк страниц Docmost ↔ Markdown-vault поверх git. Идея — добавить near-realtime синк с Obsidian на телефонах (iOS/Android), не используя git как мобильный транспорт.

Почему не git на телефоне: obsidian-git на мобильных использует isomorphic-git, мейнтейнер сам не рекомендует его на телефоне (OutOfMemoryError на крупных хранилищах, нет фоновой синхронизации). Решение — Obsidian LiveSync (CouchDB/PouchDB): непрерывная репликация (правки за 1–2 сек), chunk-level авто-merge, E2EE, iOS/Android.

Ключевое наблюдение

Дорогую половину уже сделали в #119. Точка сопряжения движка с «внешним миром Markdown» — это папка vault (<GIT_SYNC_DATA_DIR>/<spaceId>, рабочее дерево ветки main). Движок уже принимает внешние правки файлов (ручные + внешний git push через HTTP-backend) на шаге push commit('local: working-tree changes'). Значит любой агент, пишущий в эту папку, автоматически участвует в синке — конвертер и GitSyncClient трогать не нужно. Производимая движком vault-папка уже является валидным Obsidian-vault (Markdown + папки + frontmatter-id).

Предлагаемая топология (минимум кода)

Obsidian (телефон, LiveSync continuous, E2EE)
   ⇅ CouchDB _changes feed (1–2 сек)
CouchDB (Docker, за HTTPS-прокси, CORS: app://obsidian.md, capacitor://localhost, http://localhost)
   ⇅ livesync-bridge (sidecar: peer "couchdb" ⇄ peer "storage")
vault-папка <GIT_SYNC_DATA_DIR>/<spaceId>   ← это и есть Obsidian-vault
   ⇅ существующий движок git-sync (cycle.ts: PULL/PUSH)
Docmost (Postgres + Yjs) — источник истины

Git остаётся производным зеркалом/версионированием на сервере, телефон в git не ходит. Для движка livesync-bridge — это просто «ещё один редактор файлов в vault», неотличимый от человека, правящего main.

Что надо дописать в gitmost (немного, по образцу settings.gitSync)

  1. Координация двух писателей в рабочее дерево (единственный нетривиальный момент): движок при PULL переключает ветки docmostmain; если мост читает дерево в этот момент — гонка. Решение по образцу того, как HTTP-backend трактует внешний git push: дать мосту отдельны��, привязанный к main каталог (export-dir или git-worktree), который оркестратор синхронизирует с рабочим деревом под тем же per-space Redis-локом.
  2. Per-space тоггл settings.couchSync.enabled — копия паттерна settings.gitSync (DTO/Service/Repo/CASL + Switch в форме спейса).
  3. ENV-блок COUCH_SYNC_* (URL CouchDB, креды, passphrase E2EE) в EnvironmentService — по образцу GIT_SYNC_*.
  4. Генератор конфига livesync-bridge: при включении синка на спейсе эмитить/обновлять JSON-пиры (couchdb = БД спейса, storage = export-dir спейса).
  5. Деплой: в docker-compose.yml добавить couchdb + livesync-bridge + HTTPS-прокси (Caddy/Nginx/Tailscale) с CORS под мобильные origins; single-node CouchDB с поднятым max_document_size.

Сквозные вопросы (большинство уже закрыто в #119)

  • Конфликты — два домена, оба покрыты: телефон↔телефон решает LiveSync (chunk-merge); vault↔Docmost решает существующий 3-way-merge движка (baseMarkdown = last-pushed).
  • id-линчпин: frontmatter-id уже есть; нужно лишь не дать пользователю удалять его в Obsidian.
  • Вложения/картинки: в v1 едут ссылками внутри контента; маппинг бинарников LiveSync ↔ Docmost-attachments — вне scope v1.
  • Массовые удаления: первичная репликация на телефон может выглядеть как массовое удаление; delete-cap движка уже защищает Docmost.
  • HTTPS/CORS/CouchDB: ops-слой, не код gitmost.

Альтернатива (тяжёлая, на потом)

Нативный CouchDB-транспорт внутри git-sync-модуля (CouchVault/CouchDataSource вместо VaultGit): gitmost сам пишет в CouchDB в формате LiveSync (file-entry + h:-чанки, content-defined chunking, E2EE), телефоны реплицируют напрямую — без файлов и sidecar. Плюс: единый домен конфликтов. Минус: большой объём работы и сопровождение эволюционирующего wire-формата LiveSync; хрупко. Рекомендуется только если sidecar окажется операционно болезненным.

Фазы

  • Э1 (без кода): CouchDB + HTTPS + CORS, livesync-bridge sidecar на уже производимую vault-папку одного спейса, Obsidian LiveSync на десктоп + 2 телефона. Проверить near-realtime и round-trip.
  • Э2 (код по образцу gitSync): тоггл couchSync + ENV + генератор bridge-конфига + координация писателей + docker-compose.
  • Э3 (опц.): оценить нативный CouchVault.

Ссылки

## Идея: near-realtime синхронизация с Obsidian на мобильных через LiveSync (CouchDB), поверх git-sync ### Контекст В PR #119 (`feat/git-sync`, [pulls/119](https://gitea.vvzvlad.xyz/vvzvlad/gitmost/pulls/119)) уже построен двусторонний синк страниц Docmost ↔ Markdown-vault поверх git. Идея — добавить near-realtime синк с Obsidian на телефонах (iOS/Android), **не используя git как мобильный транспорт**. Почему не git на телефоне: `obsidian-git` на мобильных использует isomorphic-git, мейнтейнер сам не рекомендует его на телефоне (OutOfMemoryError на крупных хранилищах, нет фоновой синхронизации). Решение — **Obsidian LiveSync** (CouchDB/PouchDB): непрерывная репликация (правки за 1–2 сек), chunk-level авто-merge, E2EE, iOS/Android. ### Ключевое наблюдение Дорогую половину уже сделали в #119. Точка сопряжения движка с «внешним миром Markdown» — это **папка vault** (`<GIT_SYNC_DATA_DIR>/<spaceId>`, рабочее дерево ветки `main`). Движок уже принимает внешние правки файлов (ручные + внешний `git push` через HTTP-backend) на шаге push `commit('local: working-tree changes')`. Значит **любой агент, пишущий в эту папку, автоматически участвует в синке** — конвертер и `GitSyncClient` трогать не нужно. Производимая движком vault-папка уже является валидным Obsidian-vault (Markdown + папки + frontmatter-id). ### Предлагаемая топология (минимум кода) ``` Obsidian (телефон, LiveSync continuous, E2EE) ⇅ CouchDB _changes feed (1–2 сек) CouchDB (Docker, за HTTPS-прокси, CORS: app://obsidian.md, capacitor://localhost, http://localhost) ⇅ livesync-bridge (sidecar: peer "couchdb" ⇄ peer "storage") vault-папка <GIT_SYNC_DATA_DIR>/<spaceId> ← это и есть Obsidian-vault ⇅ существующий движок git-sync (cycle.ts: PULL/PUSH) Docmost (Postgres + Yjs) — источник истины ``` Git остаётся производным зеркалом/версионированием на сервере, телефон в git не ходит. Для движка `livesync-bridge` — это просто «ещё один редактор файлов в vault», неотличимый от человека, правящего `main`. ### Что надо дописать в gitmost (немного, по образцу `settings.gitSync`) 1. **Координация двух писателей в рабочее дерево** (единственный нетривиальный момент): движок при PULL переключает ветки `docmost`↔`main`; если мост читает дерево в этот момент — гонка. Решение по образцу того, как HTTP-backend трактует внешний `git push`: дать мосту отдельны��, привязанный к `main` каталог (export-dir или git-worktree), который оркестратор синхронизирует с рабочим деревом **под тем же per-space Redis-локом**. 2. **Per-space тоггл** `settings.couchSync.enabled` — копия паттерна `settings.gitSync` (DTO/Service/Repo/CASL + Switch в форме спейса). 3. **ENV-блок** `COUCH_SYNC_*` (URL CouchDB, креды, passphrase E2EE) в `EnvironmentService` — по образцу `GIT_SYNC_*`. 4. **Генератор конфига** `livesync-bridge`: при включении синка на спейсе эмитить/обновлять JSON-пиры (`couchdb` = БД спейса, `storage` = export-dir спейса). 5. **Деплой**: в `docker-compose.yml` добавить `couchdb` + `livesync-bridge` + HTTPS-прокси (Caddy/Nginx/Tailscale) с CORS под мобильные origins; single-node CouchDB с поднятым `max_document_size`. ### Сквозные вопросы (большинство уже закрыто в #119) - **Конфликты — два домена, оба покрыты:** телефон↔телефон решает LiveSync (chunk-merge); vault↔Docmost решает существующий 3-way-merge движка (`baseMarkdown` = last-pushed). - **id-линчпин:** frontmatter-id уже есть; нужно лишь не дать пользователю удалять его в Obsidian. - **Вложения/картинки:** в v1 едут ссылками внутри контента; маппинг бинарников LiveSync ↔ Docmost-attachments — вне scope v1. - **Массовые удаления:** первичная репликация на телефон может выглядеть как массовое удаление; delete-cap движка уже защищает Docmost. - **HTTPS/CORS/CouchDB:** ops-слой, не код gitmost. ### Альтернатива (тяжёлая, на потом) Нативный CouchDB-транспорт внутри git-sync-модуля (`CouchVault`/`CouchDataSource` вместо `VaultGit`): gitmost сам пишет в CouchDB в формате LiveSync (file-entry + `h:`-чанки, content-defined chunking, E2EE), телефоны реплицируют напрямую — без файлов и sidecar. Плюс: единый домен конфликтов. Минус: большой объём работы и сопровождение эволюционирующего wire-формата LiveSync; хрупко. Рекомендуется только если sidecar окажется операционно болезненным. ### Фазы - **Э1 (без кода):** CouchDB + HTTPS + CORS, `livesync-bridge` sidecar на уже производимую vault-папку одного спейса, Obsidian LiveSync на десктоп + 2 телефона. Проверить near-realtime и round-trip. - **Э2 (код по образцу gitSync):** тоггл `couchSync` + ENV + генератор bridge-конфига + координация писателей + docker-compose. - **Э3 (опц.):** оценить нативный `CouchVault`. ### Ссылки - [vrtmrz/livesync-bridge](https://github.com/vrtmrz/livesync-bridge) — headless двунаправленный мост CouchDB ⇄ ФС (peers `couchdb`/`storage`, E2EE) - [vrtmrz/obsidian-livesync](https://github.com/vrtmrz/obsidian-livesync) - [vrtmrz/filesystem-livesync](https://github.com/vrtmrz/filesystem-livesync) - [ecstatic-pirate/obsidian-git-livesync](https://github.com/ecstatic-pirate/obsidian-git-livesync) — git→CouchDB по post-receive (односторонний) - [CouchDB Synchronization (DeepWiki)](https://deepwiki.com/vrtmrz/obsidian-livesync/3.1-couchdb-synchronization)
Ghost added the idea label 2026-06-24 05:37:36 +03:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: vvzvlad/gitmost#153