Files
silo-server/DEVELOPMENT.md

4.7 KiB

Developing Silo

This document covers building, running, and contributing to the Silo server. If you just want to run Silo, see the README.

See CONTRIBUTING.md for contribution expectations, merge request guidance, and the policy for AI-assisted submissions.

Prerequisites

  • Go 1.26.4+
  • Node.js 22+ with pnpm 10.32.1
  • PostgreSQL 18 with pgvector
  • Redis
  • FFmpeg (for transcoding support)

Local Development

Local development remains intentionally separate from the deploy-oriented compose setup. Use docker-compose.yml for local services and the source-build workflow below.

# Create the local bootstrap configuration
cp .env.example .env
printf '\nSECRET_KEY=%s\nDATABASE_URL=%s\nREDIS_URL=%s\n' \
  "$(openssl rand -base64 48)" \
  'postgres://silo:silo@localhost:5432/silo?sslmode=disable' \
  'redis://localhost:6379' >> .env

# Start local PostgreSQL and Redis
docker compose up -d postgres redis

# Run the frontend dev server (hot reload, proxies API to :8090)
make dev-frontend

# Run the Go backend
make dev-backend

The template supplies a non-empty MEDIA_ROOT because Compose validates the whole file even when you start only PostgreSQL and Redis. Change it before testing libraries against real media.

If you are developing Silo and silo-plugin-sdk together, keep using the local go.work workspace. That workspace is a developer convenience only. CI and release builds run with GOWORK=off, so any new SDK helper used here must be pushed and tagged in silo-plugin-sdk before this repo can merge or release the change.

Plugin authors should start with docs/architecture/plugin-development.md, which covers the RPC plugin package format, generated proto workflow, SDK import paths, route and asset exposure, and auth or user-config integration points.

Make Targets

Target Description
make build Build frontend + Go binary
make frontend Build frontend only
make dev-frontend Vite dev server with HMR
make dev-backend Run Go backend (integrated mode)
make dev-proxy Run a standalone proxy node
make dev-transcode Run a standalone transcode node
make migrate-create NAME=add_thing Create a timestamped Goose SQL migration
make migrate-validate Validate Goose migration files without touching a database
make migrate-status Show Goose migration status using Silo's bootstrapping runner
make migrate-up Apply pending Goose migrations using Silo's bootstrapping runner
make clean Remove build artifacts

Database Migrations

PostgreSQL schema migrations are managed by Goose. Migration SQL files live in migrations/sql/ and use Goose annotations. Converted legacy migrations keep their original numeric versions so existing schema_versions rows can bootstrap cleanly into Goose without replaying old SQL. New migrations should be created with timestamped filenames:

make migrate-create NAME=add_thing
make migrate-validate

Do not run goose fix; timestamped migrations are the repository policy because they avoid version collisions across parallel PRs. The existing 001-style files are historical compatibility records, not the naming pattern for new work. Runtime migrations are applied by the integrated/API server only. Proxy and transcode modes never mutate schema. For existing installs, use make migrate-status and make migrate-up rather than invoking the Goose CLI directly; those targets copy legacy schema_versions rows into public.goose_db_version under the migration lock before reading or applying migrations. Set ENV_FILE=path/to/.env when the database URL should be read from a non-default env file.

Running Tests

# Go tests (uses testcontainers — Docker must be running)
go test ./...

# Frontend tests
cd web && pnpm test

Linting

# Go
golangci-lint run

# Frontend
cd web && pnpm run lint
cd web && pnpm run format:check

Project Structure

cmd/silo/       Entry point
internal/
  api/               HTTP router, handlers, middleware
  auth/              JWT authentication and sessions
  catalog/           Media item, episode, season repositories
  config/            YAML + env var configuration
  jellycompat/       Jellyfin/Emby protocol compatibility
  metadata/          Plugin-driven metadata matching and enrichment
  playback/          Direct play, remux, transcode session management
  scanner/           Media file discovery and FFProbe
  worker/            Background jobs (scan, match, reconcile)
web/                 React + TypeScript frontend (Vite, Tailwind, shadcn/ui)
migrations/sql/      Goose-managed PostgreSQL schema migrations