Living Document Notice
Published 2026-09-17. The evolving architecture, revisions, and connected notes for this dispatch live in the Stax Digital Garden.
Sync Without a Central Authority
Summary
Centralized synchronization servers introduce severe architectural liabilities for personal note systems. When client devices must authenticate against a multitenant database backend, the central provider acquires plaintext access to document contents, detailed reading habits, and private relation graphs. Maintaining stateful central backends requires recurring subscription infrastructure, creating operational dependencies that threaten note access if the service provider shuts down.
FreeNext decouples document replication from central identity and database servers. By using dumb store-and-forward WebSocket relays, devices synchronize encrypted state changes without requiring the relay to interpret, authenticate, or inspect document contents.
Store-and-Forward Relay Topology
In this synchronization architecture, relays do not maintain accounts, tables, or document trees. They function strictly as blind mailboxes holding encrypted message packets addressed by cryptographic topic hashes.
+-------------------+ +-------------------+
| Client Node A | | Client Node B |
| (Laptop Vault) | | (Desktop Vault) |
+-------------------+ +-------------------+
\ /
\ Encrypted Packet (Topic Hash) / Pull / Subscribe
v v
+------------------------------------------------------+
| Dumb WebSocket Relay |
| - No user accounts or auth tables |
| - Ephemeral append-only ring buffer |
| - Payloads are opaque ciphertext blobs |
+------------------------------------------------------+
^ ^
/ \
/ Store-and-Forward \ Peer Gossip
+-------------------+ +-------------------+
| Client Node C | | Secondary Relay |
| (Mobile Device) | | (Self-Hosted) |
+-------------------+ +-------------------+
Relays maintain no persistent relational database. If a public relay goes offline, clients reconnect to any self-hosted or community relay without migrating accounts or losing state.
Comparison: Multitenant Backend vs. Blind Relays
The table below contrasts the characteristics of conventional cloud sync services with dumb relay replication.
| Operational Dimension | Multitenant Central Backend | Dumb Store-and-Forward Relay |
|---|---|---|
| Server Identity | Central user accounts, email/password | Ephemeral public keys, zero server accounts |
| Payload Visibility | Server inspects plaintext or structured JSON | End-to-end encrypted opaque byte arrays |
| Protocol Complexity | Stateful REST/GraphQL with schema models | Stateless pub/sub over simple WebSockets |
| Hosting Burden | Requires dedicated DB, Redis, and workers | Single binary executable consuming minimal RAM |
| Relay Substitution | Hardcoded vendor lock-in | Configurable list of interchangeable URLs |
| Data Retention | Indefinite persistence on central disks | Configurable TTL ring buffer (e.g., 7 days) |
Because clients retain complete local history, relays only need to store uncollected packets long enough for offline devices to reconnect and drain the queue.
Blind Sync Envelope and Client Implementation
Clients package mutations inside signed and encrypted envelopes before dispatching them over the wire:
// sync-client.ts: Blind relay subscriber and publisher
export interface EncryptedSyncEnvelope {
topicHash: string; // SHA-256 of vault shared secret
senderPubkey: string; // Ed25519 ephemeral identity
nonce: string; // Hex-encoded 24-byte initialization vector
ciphertext: string; // AES-GCM encrypted mutation payload
signature: string; // Cryptographic signature of payload
epochMs: number; // Timestamp used for replay filtering
}
export class BlindRelayClient {
private socket: WebSocket | null = null;
private subscriptions: Set<string> = new Set();
constructor(private relayUrl: string) {}
connect(): Promise<void> {
return new Promise((resolve, reject) => {
this.socket = new WebSocket(this.relayUrl);
this.socket.onopen = () => {
this.flushSubscriptions();
resolve();
};
this.socket.onerror = (err) => reject(err);
this.socket.onmessage = (event) => this.handleIncomingPacket(event.data);
});
}
subscribe(topicHash: string, onEnvelope: (env: EncryptedSyncEnvelope) => void): void {
this.subscriptions.add(topicHash);
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify({ type: 'SUB', topic: topicHash }));
}
}
publish(envelope: EncryptedSyncEnvelope): void {
if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
throw new Error('Cannot publish: relay socket is disconnected');
}
this.socket.send(JSON.stringify({
type: 'PUB',
topic: envelope.topicHash,
data: envelope,
}));
}
private flushSubscriptions(): void {
if (!this.socket) return;
for (const topic of this.subscriptions) {
this.socket.send(JSON.stringify({ type: 'SUB', topic }));
}
}
private handleIncomingPacket(rawMessage: string): void {
try {
const msg = JSON.parse(rawMessage);
if (msg.type === 'EVENT' && msg.data) {
this.dispatchToDecryptionPipeline(msg.data);
}
} catch (err) {
console.error('Failed to parse relay packet', err);
}
}
private dispatchToDecryptionPipeline(envelope: EncryptedSyncEnvelope): void {
// Decrypt locally using vault key, verifying signature prior to DB ingestion
}
}Treating transport servers as dumb relays ensures synchronization remains resilient against central platform deprecation while preserving complete data confidentiality.
- Directus Target: freenext
- Garden Source Reference: HAR-1001 - Harbor Headless Sync, BSN-1003 - Delta Mutation Transport, MOC - Data Liberation Workbenches, MOC - The Plain-Text Longevity Standard, MOC - Local-First Systems and Synchronization, MOC - Bosun PKM Tools, [BSN-1001 - Incremental Parsing with Tree-sitter](BSN-1001 - Incremental Parsing with Tree-sitter), [BSN-1002 - Deterministic Round-Trip Serialization](BSN-1002 - Deterministic Round-Trip Serialization)