Complete technical reference for the Synkronus server component.
Want to get a server running quickly? See the Synkronus Quickstart guide for a simple Docker/Podman setup with automated TLS provisioning.
IT / production hosting? See Server Architecture for IT and Security reference.
Synkronus is a robust synchronization API server built with Go. It provides RESTful endpoints for data synchronization, app bundle management, attachment handling, user management, and form specifications. The server uses PostgreSQL for data storage and JWT for authentication.
Production deployments should pin a release tag rather than :latest:
ghcr.io/opendataensemble/synkronus:v1.1.1
Images are published on GitHub Container Registry for each ODE release.
synkronus/
├── cmd/synkronus/ # Application entry point
├── internal/ # Private application code
│ ├── api/ # API definition and OpenAPI integration
│ ├── handlers/ # HTTP request handlers
│ ├── models/ # Domain models
│ ├── repository/ # Data access layer
│ └── services/ # Business logic
└── pkg/ # Public libraries
├── auth/ # Authentication utilities
├── database/ # Database connection and migrations
├── logger/ # Structured logging
├── middleware/ # HTTP middleware
└── openapi/ # OpenAPI generated code
| Variable | Description | Example |
|---|---|---|
JWT_SECRET |
Secret key for JWT signing (generate with openssl rand -base64 32) |
AbCd1234= |
DB_CONNECTION |
PostgreSQL connection string | postgres://user:pass@localhost:5432/synkronus |
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
HTTP server port |
LOG_LEVEL |
info |
Logging level: debug, info, warn, error |
MAX_VERSIONS_KEPT |
5 |
Number of app bundle versions to retain |
ADMIN_USERNAME |
admin |
Initial admin username |
ADMIN_PASSWORD |
admin |
Initial admin password (change after first login!) |
PostgreSQL Requirements:
uuid-ossp extension enabledExample connection string:
postgres://synkronus_user:[email protected]:5432/synkronus?sslmode=require
Parameters:
sslmode=require - Enforce SSLsslmode=disable - No SSL (local dev only)connect_timeout=10 - Connection timeout in secondsThe server stores files at <data_root>/app-bundle/ and <data_root>/attachments/:
/app/data/ # Data root (from binary location)
├── app-bundle/
│ ├── active/ # Active app bundle
│ │ ├── forms/
│ │ │ ├── household.json
│ │ │ └── hh_person.json
│ │ ├── question_types/
│ │ └── metadata.json
│ └── versions/ # Historical versions
│ ├── 1.0.0/
│ ├── 0.9.0/
│ └── ...
└── attachments/ # Observation attachments (photos, files)
├── obs-123-photo.jpg
├── obs-456-audio.m4a
└── ...
Docker Volume Mount:
volumes:
- synkronus_data:/app/data # Single volume containing all mutable data
Directory Permissions (Docker):
synkronus (uid=1000, gid=1000)1000:1000sudo chown -R 1000:1000 /host/path/to/datachange_id cursorAuthenticate user and receive JWT token.
Request:
{
"username": "user",
"password": "password"
}
Response:
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresIn": 3600
}
Refresh expired JWT token.
Request:
{
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}
Pull changes from server.
Request:
{
"clientId": "client-123",
"currentVersion": 100,
"schemaTypes": ["survey", "visit"]
}
Response:
{
"changes": {
"observations": [...]
},
"timestamp": 150
}
Push changes to server.
Request:
{
"clientId": "client-123",
"changes": {
"observations": [...]
}
}
Response:
{
"timestamp": 150,
"conflicts": []
}
Get current app bundle manifest.
Response:
{
"version": "20250114-123456",
"files": [...],
"hash": "abc123..."
}
/app-bundle/download/{path}Download app bundle file.
Path Parameters:
path: File path within bundleUpload new app bundle (admin only).
Request: Multipart form with bundle file
Response:
{
"version": "20250114-123456",
"manifest": {...}
}
List all app bundle versions.
Switch active bundle version (admin only).
Get attachment manifest.
Query Parameters:
since: Timestamp to get changes since/attachments/{id}Download attachment file.
Upload attachment (multipart form).
/formspecs/{formType}/{version}Get form specification.
Path Parameters:
formType: Form type identifierversion: Form versionCreate form specification (admin only).
List all users (admin only).
Create new user (admin only).
/users/{username}Get user details.
/users/{username}Update user (admin only).
/users/{username}Delete user (admin only).
Export observations as Parquet ZIP.
Query Parameters:
format: Export format (parquet, json, csv)| Variable | Description | Default | Required |
|---|---|---|---|
PORT |
HTTP server port | 8080 |
No |
DB_CONNECTION |
PostgreSQL connection string | - | Yes |
JWT_SECRET |
Secret for JWT signing | - | Yes |
LOG_LEVEL |
Logging level (debug, info, warn, error) | info |
No |
APP_BUNDLE_PATH |
Directory for app bundles | ./data/app-bundles |
No |
MAX_VERSIONS_KEPT |
Maximum bundle versions to keep | 5 |
No |
ADMIN_USERNAME |
Initial admin username | admin |
No |
ADMIN_PASSWORD |
Initial admin password | admin |
No |
PORT=8080
DB_CONNECTION=postgres://user:password@localhost:5432/synkronus?sslmode=disable
JWT_SECRET=your-secret-key-change-this-in-production
LOG_LEVEL=info
APP_BUNDLE_PATH=./data/app-bundles
MAX_VERSIONS_KEPT=5
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin
| Column | Type | Description |
|---|---|---|
id |
UUID | Primary key |
form_type |
VARCHAR | Form type identifier |
data |
JSONB | Observation data |
created_at |
TIMESTAMP | Creation timestamp |
updated_at |
TIMESTAMP | Last update timestamp |
deleted |
BOOLEAN | Soft delete flag |
version |
INTEGER | Version number (auto-increment) |
| Column | Type | Description |
|---|---|---|
id |
UUID | Primary key |
username |
VARCHAR | Unique username |
password_hash |
VARCHAR | Hashed password |
role |
VARCHAR | User role (read-only, read-write, admin) |
created_at |
TIMESTAMP | Creation timestamp |
| Column | Type | Description |
|---|---|---|
version |
VARCHAR | Version identifier |
is_active |
BOOLEAN | Active version flag |
created_at |
TIMESTAMP | Creation timestamp |
/sync/pull/sync/pushConflicts are detected when:
Resolution strategy:
See Deployment Guide for complete deployment instructions.
docker compose up -d
curl http://localhost:8080/health
Returns OK if server is healthy.
Structured logging with levels:
Key metrics to monitor:
Database Connection Errors:
Authentication Failures:
Sync Failures:
The API supports versioning via the x-api-version header:
x-api-version: 1.0.0
Version negotiation allows clients to request specific API versions.