docs: design for the Electron offline/delta-sync engine (design only)
Adapts the mobile client's finalized, twice-reviewed JMAP delta-sync design (vncmail-native's docs/DELTA-SYNC-ENGINE-DESIGN.md, revision 3) to Electron's runtime rather than re-deriving JMAP sync theory. Every section is tagged [reused] / [adapted] / [new] so a reader can tell which is which; the protocol-level parts (three state machines, cursor provenance with branded types, error taxonomy, pinned reconcile sweep floor, I1-I13, F1-F49) are reused by citation, not restated. Three decisions were genuinely open here and are resolved with evidence: 1. Process placement: the engine + SQLite live in the standalone Next.js server process, on a worker thread. The per-account credentials are already there in httpOnly AES-GCM cookies, so nothing secret crosses a process boundary - and a Node process can put an Authorization header on a WebSocket upgrade, which is exactly what makes RFC 8887 push unreachable from the renderer today (lib/jmap/client.ts:6038-6059). Hosting it in main.ts was rejected because it can only be built by moving credentials into a process that currently holds none - the change that same comment explicitly declined. A WASM/OPFS renderer engine was rejected because it needs 'wasm-unsafe-eval' added to the product-wide CSP in proxy.ts, and its only encrypted backends are small third-party WASM builds. 2. SQLCipher ships on day one, via @signalapp/sqlcipher (N-API prebuilds, verified loading in Electron 43.2.0 in both process modes with no rebuild; real SQLCipher 4.10.0; encrypted header, wrong key rejected, FTS5 present; AGPL-3.0-only like this repo). The mobile design's plaintext-first phase existed only because Expo Go cannot load SQLCipher, and that constraint has no Electron analogue. node:sqlite is rejected (no encryption - PRAGMA key is a SILENT no-op that leaves the mailbox in cleartext - and stability 1.2/RC in the Node 24 that Electron 43 bundles); better-sqlite3-multiple-ciphers is rejected (Electron prebuilds stop at ABI 146, Electron 43 needs 148, so a C++ toolchain on every machine, and that lag recurs at every Electron major). 3. Keys use Electron's built-in safeStorage, not keytar, with a mandatory getSelectedStorageBackend() check: on Linux without a keyring, isEncryptionAvailable() returns true while using a public hardcoded password, which is worse than an honest failure. Also records what this repo has that the mobile one doesn't (a real Stalwart integration fixture, so the highest-value tests are cheap) and what it lacks (no /changes wrappers, no offline cache, no outbox - so v1 desktop offline is read-only by decision, and the mobile design's D1-D8 defects are not inherited). Everything not verifiable in this environment is flagged for a Stage A verify-first gate rather than presented as fact - notably whether an unsigned build keeps its macOS Keychain item across an electron-updater upgrade, and whether Next's output file tracing carries the native prebuilds into .next/standalone. No source file is touched by this commit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b15098a6eb
commit
46fc221f9e