Verstak Sync Server — HTTP API, auth/pairing, device registry, vault operation log, blob upload/download, conflict handling
 
 
 
 
Go to file
mirivlad 487ede8e4f Document scoped ordered sync contract 2026-07-17 04:11:04 +08:00
build/bin server: add SMTP config, user management web pages, install script 2026-06-20 19:21:25 +08:00
cmd/server fix: wire main.go to actual server package, server now starts 2026-06-20 11:13:41 +08:00
docs/superpowers fix: isolate sync operations by user and vault 2026-07-10 03:13:17 +08:00
internal/server fix: hide internal server errors from clients 2026-07-14 22:00:24 +08:00
release-notes docs: add historical release notes 2026-07-15 07:50:17 +08:00
scripts docs: require human release notes 2026-07-15 07:42:02 +08:00
.gitignore build: package and publish sync server releases 2026-07-13 05:01:57 +08:00
AGENTS.md docs: add AGENTS.md with platform architecture rules 2026-06-16 11:53:20 +08:00
LICENSE docs: license sync server under AGPL 2026-07-12 23:06:33 +08:00
README.md Document scoped ordered sync contract 2026-07-17 04:11:04 +08:00
go.mod feat: add server core (server, config, schema) 2026-06-20 02:01:23 +08:00
go.sum feat: add server core (server, config, schema) 2026-06-20 02:01:23 +08:00
verstak-server.service docs: document sync server deployment backups 2026-06-29 03:33:21 +08:00

README.md

Verstak Sync Server

Standalone sync server for Verstak2 platform.

Overview

This server provides synchronization between devices running Verstak2. It handles:

  • Device registration and authentication
  • Vault-scoped, ordered operation-log relay with server sequence numbers
  • Optional blob endpoints, not used by the current bounded Desktop file sync
  • User management with email confirmation

Quick Start

# Build (produces binary at build/bin/verstak-sync-server)
./scripts/build.sh

# Run
./build/bin/verstak-sync-server --port 47732 --data ./server-data

# First run with admin user
./build/bin/verstak-sync-server --admin-user admin --admin-pass secret

Release packages

Build a Linux amd64 archive locally:

./scripts/release.sh v0.1.0-alpha.1

It runs the server build and tests, then writes release/verstak-sync-server-linux-amd64-<version>.tar.gz and SHA256SUMS. The archive contains the server binary, systemd service file and install script.

Publish those same assets to GitHub Releases:

./scripts/publish-github-release.sh v0.1.0-alpha.1

The publisher requires an authenticated gh CLI and a clean local main equal to origin/main. It creates and pushes an annotated tag when necessary, then creates or updates the GitHub Release.

Configuration

Flag Default Description
--port 47732 HTTP port
--data ./server-data Data directory
--admin-user Create admin user (first run)
--admin-pass Admin password (first run)

Production installs use:

  • binary: /opt/verstak-sync-server/verstak-sync-server;
  • data directory: /var/lib/verstak-sync-server;
  • port environment file: /etc/verstak-server/env;
  • service: verstak-server.

Install from a built binary:

./scripts/build.sh
sudo ./scripts/install.sh \
  --bin ./build/bin/verstak-sync-server \
  --port 47732 \
  --admin-user admin \
  --admin-pass 'change-this-password'

The install script creates a locked-down system user, initializes the data directory, writes /etc/verstak-server/env, installs the systemd unit, and starts the service.

Deployment

Run the service behind HTTPS in production. The sync server itself listens on plain HTTP; terminate TLS in a reverse proxy such as nginx, Caddy, or a platform load balancer, then forward to 127.0.0.1:47732.

Basic service operations:

sudo systemctl status verstak-server
sudo journalctl -u verstak-server -f
curl http://127.0.0.1:47732/api/v1/health

Change the listen port:

echo 'VERSTAK_PORT=47733' | sudo tee /etc/verstak-server/env
sudo systemctl restart verstak-server

Upgrade the binary:

./scripts/build.sh
sudo systemctl stop verstak-server
sudo install -m 755 ./build/bin/verstak-sync-server /opt/verstak-sync-server/verstak-sync-server
sudo systemctl start verstak-server

Keep --data stable across upgrades. The data directory is the durable relay log for connected devices; each Desktop vault remains the source of truth for its local-first files and workspace state.

Backup And Restore

Back up the full data directory while the service is stopped. It contains:

  • server.db - SQLite database with users, devices, operations, SMTP settings, and blob metadata;
  • config.yml - admin user configuration;
  • blobs/ - content-addressed blob files.

Create a backup:

sudo systemctl stop verstak-server
sudo tar --xattrs --acls -czf verstak-sync-backup-$(date +%Y%m%d-%H%M%S).tar.gz \
  -C /var/lib verstak-sync-server
sudo systemctl start verstak-server

Restore onto a fresh host or after data loss:

sudo systemctl stop verstak-server
sudo mv /var/lib/verstak-sync-server /var/lib/verstak-sync-server.broken.$(date +%Y%m%d-%H%M%S) 2>/dev/null || true
sudo tar --xattrs --acls -xzf verstak-sync-backup-YYYYMMDD-HHMMSS.tar.gz -C /var/lib
sudo chown -R verstak:verstak /var/lib/verstak-sync-server
sudo chmod 750 /var/lib/verstak-sync-server
sudo systemctl start verstak-server
curl http://127.0.0.1:${VERSTAK_PORT:-47732}/api/v1/health

After restore, connected desktop clients keep their existing device tokens. If a backup is older than some client changes, those clients may need to run sync again so unpushed local operations are re-sent.

Architecture

cmd/server/          - Entry point
internal/server/     - Server implementation
  - server.go        - Core server logic
  - routes.go        - HTTP routing
  - handlers_api.go  - Sync, client, health, and blob handlers
  - handlers_auth.go - User auth API handlers
  - handlers_admin.go - Admin web/API handlers
  - schema.go        - Database schema

API Endpoints

Desktop sync client:

  • POST /api/client/pair - Pair a desktop client with username/password and its persistent vault_id, then return a device token
  • POST /api/auth/test - Validate username/password from the desktop client
  • GET /api/client/me - Return current authenticated client/device details
  • POST /api/client/revoke-current - Revoke the current desktop device token
  • POST /api/client/revoke-device - Revoke another device owned by the same user
  • POST /api/v1/sync/push - Push local operations to the server operation log
  • POST /api/v1/sync/pull - Pull operations since a server sequence number
  • POST /api/v1/blobs/ - Store a multipart file blob and return its SHA-256 hash
  • GET /api/v1/blobs/{sha256} - Download a stored blob by SHA-256 hash

User API:

  • POST /api/v1/auth/register - Register a user
  • GET /api/v1/auth/confirm?token=... - Confirm email
  • POST /api/v1/auth/login - User login
  • POST /api/v1/auth/forgot - Request password reset
  • POST /api/v1/auth/reset - Reset password
  • GET /api/v1/user/devices - List devices for the current user session

Operational endpoints:

  • GET /api/v1/health - Server health and basic storage status
  • /admin/... - Admin web UI and admin JSON endpoints
  • /register, /login, /dashboard, /forgot, /reset, /logout - User web UI

Sync operations are generic records with entity_type, entity_id, op_type, payload_json, device_id, and sequencing metadata. A pairing token is bound to one user and vault. The server derives the stored device ID and operation scope from that token, ignores a caller-supplied device_id for authorization, and returns only operations and cursors from the authenticated user/vault. Operations are returned in increasing server_sequence; clients must stop at the first operation they cannot apply and retry that sequence later. The server does not merge files, resolve conflicts, or create replacement names.

The desktop pairing payload may supply an existing vault_id to add a new empty local vault to that remote scope. The server treats that value only as a scope selector: reconciliation, conflict detection, snapshots, and durable workspace identity remain Desktop-core responsibilities. Current Desktop core uses bounded inline file payloads (text or base64 up to 8 MB) and workspace operations (create, rename, trash, restore). Blob transport, quotas, pull pagination, and operation retention are a later milestone; the existing blob endpoints must not be interpreted as enabled Desktop large-file sync.

New device enrollment requires a non-empty vault_id. The legacy: prefix is reserved for server-side migration of older records and cannot be selected by new clients.

Development

# Run tests
go test ./...

# Build for production
CGO_ENABLED=1 go build -o verstak-sync-server ./cmd/server

License

Copyright © 2026 Verstak contributors. Licensed under GNU AGPLv3 or later.