Sync Protocol
The Niuton sync protocol uses a cursor-based delta synchronization approach for both structured data and files.
Data Sync Flow
┌─────────┐ ┌──────────┐
│ Client │ │ Server │
└────┬─────┘ └────┬─────┘
│ │
│ 1. GET /sync/data?action= │
│ initial_sync │
│ ─────────────────────────────────> │
│ {data: {...}, cursor: 100} │
│ <───────────────────────────────── │
│ │
│ ... time passes ... │
│ │
│ 2. GET /sync/data?action=delta │
│ &cursor=100 │
│ ─────────────────────────────────> │
│ {changes: [...], cursor: 105} │
│ <───────────────────────────────── │
│ │
│ 3. POST /sync/data?action=push │
│ {operations: [...]} │
│ ─────────────────────────────────> │
│ {results: [...], cursor: 108} │
│ <───────────────────────────────── │
│ │Cursor
The cursor is a monotonically increasing integer from the niuton_sync_log table. Each data change increments the cursor. The client stores the last known cursor and requests changes since that point.
Initial Sync
On first connection, the client performs an initial_sync to get all current data. This returns:
- All rows from synced tables (filtered by user ownership)
- Current cursor position
- Schema version
Delta Sync
Subsequent syncs use delta with the last cursor. The server returns only changes since that cursor:
- INSERT, UPDATE, DELETE operations
- Sensitive columns are stripped
- Changes are filtered by user ownership
Push
Client-side changes are pushed via push with an array of operations. The server:
- Validates each operation
- Applies changes to the database
- Logs changes to
niuton_sync_log - Returns per-operation results
- Returns new cursor position
Conflict Resolution
When the same record is modified on both client and server:
- Last write wins for data records
- Conflict copy for files (when
conflict_copyfeature flag is enabled)
File Sync Flow
┌─────────┐ ┌──────────┐
│ Client │ │ Server │
└────┬─────┘ └────┬─────┘
│ │
│ 1. GET /sync/files?action= │
│ manifest │
│ ─────────────────────────────────> │
│ {files: [{path, sha256, ...}]} │
│ <───────────────────────────────── │
│ │
│ 2. Compare local vs remote │
│ manifest │
│ │
│ 3. Download changed files │
│ GET /sync/files?action= │
│ download&path=... │
│ ─────────────────────────────────> │
│ <binary file> │
│ <───────────────────────────────── │
│ │
│ 4. Upload local changes │
│ POST /sync/files?action= │
│ upload&path=... │
│ ─────────────────────────────────> │
│ {ok: true} │
│ <───────────────────────────────── │
│ │Manifest
The manifest contains every file's path, size, SHA-256 checksum, and modification time. The client compares its local state against the manifest to determine:
- New server files — Download to local
- Modified server files — Download updated version
- New local files — Upload to server
- Modified local files — Upload updated version
- Deleted files — Apply deletion (with conflict detection)
Checksum Verification
Files are verified using SHA-256 checksums:
- Server includes
X-File-SHA256header in downloads - Client can verify integrity after download
- Upload integrity verified server-side
Rate Limits
| Endpoint | Limit |
|---|---|
initial_sync | 5/minute |
delta | 30/minute |
push (max 100 ops) | 30/minute |
manifest | 10/minute |
download | 120/minute |
upload | 60/minute |
delete | 60/minute |
mkdir | 30/minute |
move | 30/minute |