Feature: Sync Relay (Cloudflare Worker)
Feature: Sync Relay (Cloudflare Worker)
Status: Delivered
CAS: CAS-748
Delivered: 2026-04-26
Parent epic: CAS-171 Multi-Device Sync with E2E Encryption
What shipped
A Cloudflare Worker edge service that relays encrypted changesets between Casaconomy desktop clients. The relay is zero-knowledge by design: it stores and forwards opaque ciphertext blobs and cannot read payload content. All decryption happens on-device.
Architecture
Client A ──(push)──► Worker (edge, Cloudflare network) │ D1 SQLite (weur) ── R2 (weur) │Client B ──(pull)──► WorkerStorage:
- D1 —
changesets,devices,vaults,snapshotsmetadata tables - R2 — full snapshot blobs (large uploads, content-addressed)
Entry point: workers/sync-relay/src/index.ts
Zero-knowledge property
The relay enforces ZK at the server layer:
ciphertextfields are stored and forwarded verbatim — no decode, parse, or inspect- D1 text columns contain only opaque bytes (verified by ZK audit test suite)
- Nonces are treated as opaque identifiers, never inspected
- Static audit script (
scripts/check-zk-static.sh,npm run lint:zk) fails the build ifciphertextappears in console calls, decode paths, conditionals, or error strings
API
| Method | Path | Purpose |
|---|---|---|
| POST | /vaults/:id/changesets | Push a changeset |
| GET | /vaults/:id/changesets | Pull changesets (since cursor) |
| POST | /devices | Register a device keypair |
| GET | /devices/:id | Fetch device public key |
| POST | /vaults/:id/snapshots | Upload a full snapshot to R2 |
| GET | /vaults/:id/snapshots/latest | Fetch latest snapshot metadata |
Rate limiting is enforced per vault per IP. Devices authenticate via Ed25519 keypairs registered at pairing time.
Test suite (sub-task S6 / CAS-754)
- ZK audit tests: 4 ciphertext-canary probes (push response, D1 columns, pull response cross-field, nonce opacity) — prove ciphertext never escapes the relay
- E2E smoke: two-device cross-vault push/pull with sequence integrity and round-trip ciphertext fidelity
- Concurrent burst load: 20 parallel pushes + 20 parallel pulls across distinct vaults — all must return 2xx, no 5xx
- Static ZK grep audit: integrated into
npm run lint:zk
52 tests across 6 files pass. ZK static audit: PASSED.
Tauri client side
transport_http.rs was updated to align the PushRequest struct with the relay
API: added id, origin_device, origin_user, timestamp, operation_type,
entity, entity_id, schema_version, key_id, and nonce fields. Renamed
entity_type → entity to match the relay schema.
Sub-tasks delivered
| Identifier | Title |
|---|---|
| CAS-749 | S1 — D1 schema + wrangler config |
| CAS-750 | S2 — changeset push/pull handlers |
| CAS-751 | S3 — device registration + auth |
| CAS-752 | S4 — snapshot upload/fetch (R2) |
| CAS-753 | S5 — rate limiting + retention |
| CAS-754 | S6 — ZK audit test + E2E smoke + README |