Skip to content

Principles

This document defines the product thesis, architectural boundaries, and non-negotiable principles for Synchro.

It is the highest-level source of truth for the new system. Lower-level specs must conform to it.

Synchro is an offline sync product for teams building serious native apps.

It is designed to beat current alternatives on:

  • extension-based server architecture instead of a separate sync tier
  • developer experience
  • lower adoption friction
  • predictable sync semantics
  • end-to-end synced CRUD
  • native client parity
  • performance through extension-side execution and deterministic sync scopes

Synchro is not a generic local-first substrate first. It is an opinionated sync product first.

The promise of Synchro is:

  • extension-based server execution close to the data
  • full synced CRUD for synced tables
  • thin, replaceable host adapters
  • native client engines with local SQLite on device
  • shared sync semantics across adapters through the Rust core
  • minimal required application schema changes
  • deterministic selective sync with explicit rebuild semantics

The system is composed of four layers:

  • extensions/synchro-core: shared deterministic sync semantics
  • extensions/synchro-pg: PostgreSQL extension that executes those semantics close to the data
  • api/go: one reference host layer that implements the contract over the extension
  • end clients: Swift, Kotlin, React Native

api/go is not an end client. It is one host layer.

All core sync semantics should live in the shared Rust core wherever possible.

That includes:

  • deterministic sync rules
  • conflict semantics
  • checksums
  • diffing and dedup logic
  • protocol-level semantic invariants

The PostgreSQL extension is the authoritative execution environment for server-side sync logic.

The system should prefer:

  • WAL/CDC-driven server-side change detection
  • extension-owned sync metadata
  • extension-side membership materialization
  • extension-side write application for synced CRUD

The system should not depend on a separate sync database or sync service database on the server.

api/go and future adapters should remain thin.

They may own:

  • transport
  • authentication integration
  • version gating
  • HTTP validation and translation

They should not own:

  • sync semantics
  • scope membership semantics
  • conflict resolution semantics
  • rebuild semantics
  • synced-table write semantics

Swift and Kotlin should be as thin as possible without becoming fake-thin.

They still need to own:

  • local SQLite integration
  • local change capture
  • local queueing
  • scheduling and retry orchestration
  • applying server-delivered state safely

They should not invent server sync semantics.

React Native should remain a thin bridge over the native clients, not a separate sync engine.

Synchro uses server-defined deterministic sync scopes.

The public abstraction is:

  • scope definition
  • scope instance
  • scope membership
  • scope checkpoint
  • scope rebuild

Clients do not define arbitrary replication queries.

The system should not use client-authored dynamic shape graphs or arbitrary client-side replication predicates as the primary sync model.

This section is normative. It defines the architectural rules. Detailed operational guidance and examples live in Scope modeling.

Scope membership must be deterministic and server-defined.

The server decides which rows belong to which scope instances.

The system should materialize membership and metadata so that:

  • pull is cheap
  • rebuild is explicit
  • per-scope cursor progression is explicit
  • checksums are explicit

A high number of scope instances is acceptable.

The true scaling danger is fanout:

  • for one changed row, how many scope instances must be updated or notified

The system must optimize for low fanout.

Shared or public data should prefer shared scopes with many subscribers.

The system should avoid duplicating shared rows into large numbers of private scopes unless there is a strong reason to do so.

Recommended pattern:

  • private rows in private scopes
  • shared rows in shared scopes
  • both may materialize into the same local table
  • bundled seeds export those same shared scopes, not seed-only variants

Example:

  • documents_user:{user_id} for user-owned documents
  • templates_public for public templates
  • templates_user:{user_id} for user-created templates

These are example names, not automatic assignments. The default identity scope is user:{user_id}. Custom private scopes require an explicit server-side grant, and shared scopes require registration. See Scope modeling.

The system should prefer one shared scope with many subscribers over copying the same shared rows into every private scope.

Shared scopes should be grouped by operational behavior, not only by visibility. One shared global scope is acceptable for small stable datasets that change together. Larger or more independently changing public datasets should use separate shared scopes.

The system must support advanced scope logic as an escape hatch.

Common cases should be handled by first-class structured configuration.

Advanced cases may use custom SQL.

Synchro owns row-level CRUD for synced tables end-to-end.

That includes:

  • create
  • update
  • delete
  • policy enforcement
  • conflict handling
  • canonical server response
  • resulting scope membership effects

Synchro does not attempt to own arbitrary business workflows or domain commands.

Business commands that are not row-level synced CRUD remain outside Synchro.

Configuration should live in SQL migrations in the consuming application’s database repo.

The preferred authoring model is:

  • structured Synchro SQL configuration for common cases
  • custom SQL escape hatches for advanced cases

The system should not use YAML or server-language config as the primary source of truth for sync semantics.

Synchro should require only extension-owned infrastructure tables on the server.

It should not require application teams to modify every application table as a prerequisite for adoption.

Minimal schema friction is a goal, but not at the cost of ambiguous or under-specified behavior.

The system should outperform alternatives by combining:

  • local SQLite on device
  • extension-side execution near the data
  • deterministic scopes
  • materialized membership
  • cheap incremental pull
  • scoped rebuild instead of broad destructive resync
  • no unnecessary extra network round trips for core sync logic

The system must explicitly optimize for:

  • low row-change fanout
  • cheap pull
  • efficient shared/public data handling
  • explicit rebuild costs

Synchro is intended to beat alternatives by being:

  • more complete than systems that stop at read sync and ask users to invent their own write API
  • more predictable than systems centered on arbitrary replication shapes
  • better for native mobile DX
  • better for thin adapter implementations
  • better for shared semantics across multiple adapters and client SDKs

Synchro is not trying to be:

  • a generic workflow engine
  • a client-defined arbitrary query replication system
  • a system whose main value is “bring your own backend write path”
  • a system whose semantics are inferred from implementation accidents instead of the release contract