go-oversync

Server

The server treats registered PostgreSQL business tables as authoritative state.

Runtime Tables

Authoritative replication state:

Transport/session state:

Write Path

One push session, one committed bundle, and one WithinSyncBundle(...) transaction belong to exactly one user_id. If application logic needs to affect multiple users, split that work into separate per-user transactions or bundles.

ScopeManager callback rules

ScopeManager.ExecWrite(...) runs direct PostgreSQL SQL inside one captured transaction.

Important rules:

ScopeManager.ExecWrite(...) is meant for writes that must later become visible through sync. It is not a generic helper for arbitrary unregistered business transactions.

Safe pattern examples:

_, err := scopeMgr.ExecWrite(ctx, scopeID, oversync.ScopeWriteOptions{
	WriterID: "admin-panel",
}, func(tx pgx.Tx) error {
	_, err := tx.Exec(ctx, `
		INSERT INTO business.users (id, name, email)
		VALUES ($1, $2, $3)
	`, userID, "Ada", "ada@example.com")
	return err
})
_, err := scopeMgr.ExecWrite(ctx, scopeID, oversync.ScopeWriteOptions{
	WriterID: "admin-panel",
}, func(tx pgx.Tx) error {
	_, err := tx.Exec(ctx, `
		UPDATE business.users
		SET name = $3
		WHERE _sync_scope_id = $1
		  AND id = $2
	`, scopeID, userID, "Ada Updated")
	return err
})

Writer IDs

ScopeManager takes a host-provided WriterID, which maps directly to the existing per-scope source_id sequencing model.

Guidance:

Business idempotency

ScopeManager owns sync-stream correctness, not business-command idempotency.

If the host app needs exactly-once semantics for domain operations such as:

that idempotency must be implemented by the application, not by oversync.

First-connect lifecycle

POST /sync/connect resolves the client lifecycle without asking the app to choose between “upload local” and “replace local”:

retry_later is a normal connect outcome, not an auth failure. Clients should retry after the server-provided backoff.

Once a scope reaches INITIALIZED, remote remains authoritative for this feature set until some future explicit reset feature exists.

Registered Table DDL Requirements

Registered PostgreSQL tables must satisfy these rules before bootstrap:

Bootstrap validates these requirements and fails closed with an UnsupportedSchemaError if the registered schema is outside the supported envelope.

Read Path

Auth Contract

The handlers expect the caller to authenticate first and place oversync.Actor{UserID, SourceID} into request context. The runtime does not require any specific auth stack. The built-in transport helper is oversync.ActorMiddleware(...), which reads Oversync-Source-ID after host authentication has already established trusted user_id in request context. _sync_scope_id is derived from Actor.UserID, enforced only on the authoritative PostgreSQL side, and excluded from client-visible payloads, conflicts, pulls, and snapshots.