Deployment

Components

  • svitrio-api — the main Go API (:8080): /admin/*, /auth/*, public content, sitemap, /healthz. A static distroless binary (pure-Go SQLite).

  • svitrio-portal-api — an isolated customer-portal API (:8081, /portal/*). A separate process on purpose: operator routes are never mounted, so a customer principal can’t reach them. Shares the same DB.

  • admin SPA — the SvelteKit operator console, built static and served by nginx, pointed at the API via VITE_SVITRIO_API at build time.

  • database — SQLite by default (a file on a volume); Turso built-in; Postgres/Neon via a plugin build.

Build note: the API depends on a sibling gate-go/ repo, so the Docker build context is the parent dir holding both svitrio/ and gate-go/.

cd /path/to/repos    # holds svitrio/ and gate-go/
docker build -f svitrio/deploy/Dockerfile.api -t <registry>/svitrio-api .

Bare-metal

cd api && go build -o bin/svitrio-api ./cmd/svitrio-api
cd ../admin && pnpm install && pnpm build   # pnpm, not npm

export SVITRIO_JWT_SECRET=$(openssl rand -hex 32)
export SVITRIO_SECRETS_KEY=$(openssl rand -base64 32)
export SVITRIO_DB=/var/lib/svitrio/svitrio.db
./bin/svitrio-api                 # migrations run automatically on boot

Serve the admin SPA and the API behind a reverse proxy on separate hosts (admin. and api.).

Kubernetes

Apply deploy/k8s/* in order: namespace → secret (created imperatively, never from placeholders) → config/PVC/deployments/ingress. TLS via cert-manager (a letsencrypt ClusterIssuer; DNS-01 for a wildcart). The API stays at 1 replica with a Recreate strategy while on SQLite (an RWO volume can’t be held by two pods).

Svitrio also ships a per-tenant SaaS model (deploy/tenant/provision.sh) that stamps out a dedicated namespaced instance per customer sized by plan — reuse the pattern, swap the images/hosts/registry for your own.

First operator

There is no seed script: deploy, open the admin, request a magic link for your email and follow it — the first registered user is auto-promoted to seed + operator. Then register a passkey. Upgrades are rebuild-and-restart; migrations are forward-only and idempotent, but back up the database first.