2026-07-24 15:15:19 -04:00
|
|
|
# Silo Server
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
Go backend for Silo: API contracts, auth/session, catalog/scanner/playback services, database
|
|
|
|
|
migrations, Jellyfin compatibility, and the host-side plugin runtime. `cmd/silo` is the
|
|
|
|
|
entrypoint, backend code is under `internal/` by domain, the React frontend is `web/src/`.
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
This repository is a VERY EARLY WIP. Proposing sweeping changes that improve long-term
|
|
|
|
|
maintainability is encouraged.
|
2026-05-24 19:58:22 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
## Priorities
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
Performance and reliability first. Keep behavior predictable under load and during failures —
|
|
|
|
|
session restarts, reconnects, partial streams. When a tradeoff is forced, choose correctness and
|
|
|
|
|
robustness over short-term convenience.
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
Put new code in the package that owns the behavior rather than in a catch-all helper. Prefer
|
|
|
|
|
extracting shared logic over duplicating it, and prefer changing existing code over bolting a
|
|
|
|
|
local workaround onto it.
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-25 15:07:42 +00:00
|
|
|
## Non-goals
|
|
|
|
|
|
|
|
|
|
Most of this codebase's scope is open; a short list is permanently closed. Read
|
|
|
|
|
[docs/non-goals.md](docs/non-goals.md) before proposing or implementing in those areas.
|
|
|
|
|
|
|
|
|
|
**Live TV, OTA/DVB tuners, IPTV, EPG/XMLTV, DVR, and `.strm` remote-URL shortcuts will not be
|
|
|
|
|
accepted** — not in core, not as a plugin, not in a client. The first-party clients ship on the
|
|
|
|
|
Apple and Google stores, and a server that plays arbitrary remote stream URLs puts the whole
|
|
|
|
|
client suite at risk. This is settled product direction, not a design problem to solve; do not
|
|
|
|
|
write code for it, and say so plainly if asked.
|
|
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
## Gotchas
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
**Migrations.** New DB changes are Goose SQL migrations in `migrations/sql/`, created with
|
|
|
|
|
`make migrate-create NAME=add_thing` so they get timestamped filenames. Never run `goose fix`,
|
|
|
|
|
and never create paired `.up.sql` / `.down.sql` files. Legacy converted migrations deliberately
|
|
|
|
|
keep their original numeric versions so existing `schema_versions` rows bootstrap cleanly — do
|
|
|
|
|
not renumber them.
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
**Encrypted settings.** Encrypted `server_settings` rows are GCM-bound to their key name.
|
|
|
|
|
Renaming a row in SQL makes its value undecryptable.
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
**Profiles vs accounts.** Login accounts (`users`) are separate from household profiles; several
|
|
|
|
|
profiles on one account share a `user_id`. A profile's `is_primary` marks the household parent,
|
|
|
|
|
which is *not* the server-wide `admin` role on the account.
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
**Docs hygiene.** Files under `docs/superpowers/{specs,plans}/` must not contain local absolute
|
|
|
|
|
filesystem paths or transient worktree IDs — use repository-relative paths and wording like
|
|
|
|
|
"Commands assume the repository root is the cwd." `make verify-local-paths` enforces this.
|
2026-05-23 12:31:08 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
**Dev frontend against a remote backend.** Set `VITE_API_PROXY_TARGET` in `web/.env.local` before
|
|
|
|
|
`make dev-frontend`; the frontend calls relative `/api` URLs that Vite proxies.
|
2026-05-23 12:31:08 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
**Working from a plan.** When implementing from an attached plan, don't edit the plan file.
|
2026-05-23 12:31:08 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
## Multi-repo
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
Sibling repos are usually checked out side-by-side in the same parent directory.
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
- `silo-android` — Android phone and TV clients.
|
|
|
|
|
- `silo-apple` — iOS, tvOS, and macOS clients.
|
|
|
|
|
- `silo-plugin-sdk` — public plugin SDK, protobuf contracts, generated plugin API, manifest
|
|
|
|
|
helpers, runtime bootstrap.
|
|
|
|
|
- `silo-plugins` — central plugin catalog / repository manifest.
|
|
|
|
|
- First-party plugins (`silo-plugin-metadata-tmdb`, `silo-plugin-metadata-tvdb`, …) each have
|
|
|
|
|
their own repo.
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
Client-visible changes to API, auth, playback, session, library, or metadata behavior usually
|
|
|
|
|
need follow-up in both client repos — prefer coordinated multi-repo changes over leaving a
|
|
|
|
|
platform behind. When a task mentions plugins, work out first whether it belongs here, in the
|
|
|
|
|
SDK, in the catalog, or in a specific plugin repo.
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
## Building and verifying
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-30 10:52:41 -04:00
|
|
|
`make build`, `make dev-backend`, `make dev-frontend`, `make lint`, `make test`, `make migrate-status`
|
|
|
|
|
/ `make migrate-up` — read the `Makefile` for the rest. Local services:
|
2026-07-24 15:15:19 -04:00
|
|
|
`docker compose up -d postgres redis`.
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-30 10:52:41 -04:00
|
|
|
`make test-go` runs the whole Go suite. A Go test that cannot pass yet carries a `t.Skip` and the
|
|
|
|
|
reason in its own source, not an entry in a Makefile variable. `make test-web` still skips the
|
|
|
|
|
files in `WEBTEST_KNOWN_FAILURES`, which predate the CI gate; that list may only shrink — delete an
|
|
|
|
|
entry together with its fix, and never add to it to make a new change pass.
|
|
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
Before opening a merge request:
|
2026-05-22 20:26:11 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
```bash
|
|
|
|
|
make lint
|
2026-07-30 10:52:41 -04:00
|
|
|
make test
|
2026-07-24 15:15:19 -04:00
|
|
|
cd web && pnpm run lint && pnpm run format:check
|
|
|
|
|
make verify-local-paths
|
|
|
|
|
```
|
2026-06-12 18:43:23 -04:00
|
|
|
|
2026-07-30 10:52:41 -04:00
|
|
|
`.github/workflows/ci.yml` runs these on every pull request, with one difference worth knowing:
|
|
|
|
|
`make lint` runs `golangci-lint` over the whole tree, while CI runs it with `--new-from-merge-base`
|
|
|
|
|
so only the lines a branch touched have to be clean. The repo does not pass a full run today, so
|
|
|
|
|
expect local output to include findings that are not yours and that CI will not fail on. Do not add
|
|
|
|
|
to them.
|
|
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
Go stays `gofmt`/`goimports` clean; the frontend follows `web/.prettierrc`.
|
2026-07-23 14:36:54 -04:00
|
|
|
|
2026-07-25 05:16:19 +00:00
|
|
|
## Skills
|
|
|
|
|
|
|
|
|
|
Task-specific guides live in `.claude/skills/`, also reachable as `.agents/skills/` for agents
|
|
|
|
|
that look there. Read the one that matches the task instead of working from this file alone.
|
|
|
|
|
|
|
|
|
|
They share one config file: copy `.silo-dev.env.example` to `.silo-dev.env` and fill in how to
|
|
|
|
|
reach your Silo deployment — URL, SSH target, database, an account to debug with. That file is
|
|
|
|
|
gitignored and is the only place hosts, passwords, and tokens belong. `scripts/silo-dev doctor`
|
|
|
|
|
checks it end to end.
|
2026-07-23 14:36:54 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
## v1 API rules
|
2026-07-23 14:36:54 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
Additive-only within `/api/v1`:
|
2026-07-23 14:36:54 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
- Never rename or remove a response field, change a field's type, or repurpose a status code on
|
|
|
|
|
an existing endpoint.
|
|
|
|
|
- New functionality adds new fields or endpoints. Removals go through the Deprecation/Sunset
|
|
|
|
|
header flow only.
|
|
|
|
|
- New features expose capability endpoints for feature detection rather than relying on version
|
|
|
|
|
sniffing. Contract strategy and tooling: issue #135.
|
2026-07-23 14:36:54 -04:00
|
|
|
|
2026-07-30 10:52:41 -04:00
|
|
|
Treat this as binding. The one exception: `/api/v1` is not locked yet, so a removal taken before
|
|
|
|
|
lock is in scope — but only when it is recorded in the pre-lock removals table in
|
|
|
|
|
[docs/architecture/v1-scope.md](docs/architecture/v1-scope.md) and ships before the lock. Assume
|
|
|
|
|
any removal not listed there is a mistake.
|
|
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
## Pull requests
|
2026-07-23 14:36:54 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
Conventional Commit subjects (`feat(playback): add realtime session hub`). One concern per PR.
|
|
|
|
|
Explain the problem, why this approach, the linked issue/spec/plan, and risks or follow-up work.
|
|
|
|
|
Include screenshots or recordings for UI changes. Link the capability epic or sub-issue the PR
|
|
|
|
|
serves (`Part of #NNN`) — PRs with no linked scope item get questioned at review. For non-trivial
|
|
|
|
|
work, open an issue or discussion first; this codebase moves quickly.
|
2026-07-23 14:36:54 -04:00
|
|
|
|
2026-07-24 15:15:19 -04:00
|
|
|
AI-use disclosure is required in the PR body. If you are an AI agent contributing on behalf of a
|
|
|
|
|
non-maintainer, follow [docs/ai-contributions.md](docs/ai-contributions.md) — it has the required
|
|
|
|
|
disclosure block and the evidence standard.
|