Hub Overview
Architecture and internals of the Valvet hub
The hub is the central management server. It is a single Rust binary built with Axum that serves the web UI, REST API, WebSocket endpoint, and SSE event stream — all on a single port.
Components
Web UI
A React single-page application embedded in the binary at build time via tower_http::services::ServeDir. The frontend communicates exclusively through the REST API.
REST API
All endpoints live under /api/v1/. Authentication uses JWT access tokens (15-minute expiry) sent as Bearer tokens, plus HTTP-only refresh cookies (30-day expiry) for silent renewal.
WebSocket Server
Nodes connect to /api/v1/ws with a short-lived WebSocket token (60-second expiry, rotated regularly). The hub dispatches commands (backup, restore, prune, check, stats) and receives results over this channel.
SSE Event Stream
The UI subscribes to /api/v1/events for live updates — job progress, node status changes, backup completions. This eliminates polling and keeps the dashboard current.
Scheduler
Plans with cron expressions are evaluated on a timer. When a plan’s cron matches, the hub creates a job and dispatches it to the target node.
Database
SQLite in WAL mode provides concurrent read access with single-writer semantics. Migrations run automatically on startup and are idempotent (safe to re-run).
Data Flow
Browser ──REST/SSE──> Hub ──WebSocket──> Node ──restic──> Repository
- User action in the UI triggers a REST API call
- Hub validates, records the job in SQLite, and sends a WebSocket command to the node
- Node executes restic and streams progress back over WebSocket
- Hub updates SQLite and broadcasts SSE events
- UI reacts to SSE events and refreshes relevant data