feat(desktop): two-way cloud sync with mobile and web

Rewrites the desktop mirror as services/sync/SyncEngine: a persistent
outbox, per-account server-clock keyset cursors with paging, pulls that never
overwrite unsent local edits, deletions both ways through sync_tombstones and
per-row failure isolation. It now covers history titles and favorites,
dictionary, every meeting's memos and documents, memo tags, user commands and
dictation/meeting templates, and registers the desktop as a device that the
phone can disconnect.

Fixes shipped defects: the first pull after sign-in fetched nothing, only
the first meeting's children were pushed, team meetings leaked into the
personal database and lost team_id on re-push, and Realtime never connected
because Electron's Node 20 has no global WebSocket (ws is now the transport).
Anonymous local-mode records are imported into the first account that signs
in. The settings sync section is translated and shows pending/rejected
changes; synced screens reload on app:dataChanged.
This commit is contained in:
Yun Chan 2026-09-27 14:04:49 +09:00
parent b5c9ff9f31
commit 0a4f5aee64
49 changed files with 3940 additions and 1033 deletions

View file

@ -522,5 +522,24 @@
"settings.captionRefine.desc": "Локальный ИИ исправляет пробелы, пунктуацию и ослышки в готовых субтитрах по соседним строкам.",
"settings.captionModel": "Модель живых субтитров",
"settings.captionModel.same": "Как для диктовки",
"settings.captionModel.desc": "Живые субтитры распознаются отдельной моделью, которая загружается вместе с моделью диктовки."
"settings.captionModel.desc": "Живые субтитры распознаются отдельной моделью, которая загружается вместе с моделью диктовки.",
"history.favorite": "В избранное",
"history.unfavorite": "Убрать из избранного",
"cloudSync.title": "Облачная синхронизация",
"cloudSync.description": "Синхронизирует историю, словарь, встречи, теги, команды и шаблоны с мобильным приложением и вебом. Удаление на одном устройстве удаляет везде.",
"cloudSync.signIn": "Войти",
"cloudSync.signedInAs": "Вы вошли как {{email}}",
"cloudSync.noEmail": "нет почты",
"cloudSync.lastSync": "Последняя синхронизация: {{time}}",
"cloudSync.never": "ещё нет",
"cloudSync.upToDate": "Все изменения отправлены",
"cloudSync.pending": "Ожидают отправки: {{count}}",
"cloudSync.failed": "Сервер отклонил изменений: {{count}} — «Синхронизировать» повторит попытку",
"cloudSync.syncNow": "Синхронизировать",
"cloudSync.syncing": "Синхронизация…",
"cloudSync.signOut": "Выйти",
"cloudSync.browserPending": "Завершите вход в браузере.",
"cloudSync.signedOut": "Вы вышли. Записи на этом компьютере сохранены.",
"cloudSync.done": "Синхронизация завершена (применено: {{count}})",
"cloudSync.doneWithErrors": "Синхронизация завершена (применено: {{count}}, ошибок: {{errors}} — повтор при следующей синхронизации)"
}