System context
Rendered from spec at76d46f3 (2026-10-25) · its source · Edit this page
Status: Accepted
What sits inside the system, what sits outside it, and where the boundaries fall.
The picture
flowchart TB
subgraph people[" "]
op([Operator])
hh([Household member])
end
subgraph host["The operator's machine"]
lf[lemonfiber<br/>CLI · TUI · web]
subgraph stack["lemonfiber-media-stack — Docker Compose"]
idx[Indexers<br/>Prowlarr · NZBHydra2]
dl[Download clients<br/>SABnzbd · qBittorrent]
vpn[Gluetun<br/>VPN + killswitch]
arr[Automation<br/>Sonarr · Radarr · Lidarr · Bindery]
lib[Library<br/>Jellyfin · Seerr · CWA · Audiobookshelf]
end
fs[(Data root<br/>downloads + media)]
end
subgraph outside["Third parties — not ours"]
prov[Usenet provider]
ind[Indexer services]
vpnp[VPN provider]
meta[Metadata sources]
reg[Container registry]
end
op -->|"sets up, runs,<br/>diagnoses"| lf
hh -->|"requests"| lib
hh -->|"watches"| lib
lf -->|"compose CLI: writes"| stack
lf -->|"Docker API: reads"| stack
lf -->|"REST: seeds + inspects"| stack
lf -->|"tests hardlinks,<br/>projects space"| fs
stack --> fs
dl -.->|"tunnelled"| vpn
vpn --> vpnp
idx --> ind
dl --> prov
arr --> meta
lf --> reg
Boundaries
Inside — ours to specify
lemonfiber and the stack definition. We choose the services, pin their
versions, define how they connect, and own every interaction between them.
Inside — ours to orchestrate, not to build
The 20 services. We don’t write Sonarr; we decide it’s included, how it’s configured, and what happens when it misbehaves. Its bugs are not ours, but its integration is entirely ours.
Outside — the operator’s
Usenet providers, indexers, VPN providers. lemonfiber can validate credentials and monitor capacity (C8), but cannot create accounts, and deliberately doesn’t recommend vendors (A1-R5).
Outside — infrastructure
Docker, the container registry, the operating system. Assumed present, verified at preflight, never installed on the operator’s behalf.
The two human actors
| Operator | Household member | |
|---|---|---|
| Touches | lemonfiber, occasionally a service admin UI | Seerr, Jellyfin |
| Accounts | Several — one per admin app | Exactly one — their Jellyfin login |
| Reaches | Loopback + LAN | LAN only |
| Knows lemonfiber exists | Yes | No |
The second column is a design constraint, not an observation. A household member who has to learn what lemonfiber is has been failed — G5 exists to give them one URL and nothing else.
Trust zones
flowchart LR
subgraph lo["Loopback — operator only"]
adm["*arrs · download clients<br/>lemonfiber control surface"]
end
subgraph lan["LAN — household"]
hhs["Jellyfin · Seerr<br/>CWA · Audiobookshelf"]
end
subgraph tun["VPN tunnel"]
tor["qBittorrent"]
end
subgraph pub["Public internet"]
ext["providers · indexers · registries"]
end
lo --> ext
lan --> ext
tor --> ext
Three properties this encodes:
- Admin surfaces are unreachable from the LAN — not obscure, unreachable (C6-R1). A household member cannot find qBittorrent because it isn’t listening on an address their device can route to.
- Household surfaces are LAN-bound deliberately. Loopback-only would make them useless from a television, which is the entire point of having them.
- Torrent traffic leaves only through the tunnel. Verified empirically by comparing observed egress, not assumed from configuration (C2-R1).
Data crossing the boundary
Everything lemonfiber itself sends outward, enumerable (G8-R3) and individually disableable (G8-R5):
| Destination | Purpose | Disableable |
|---|---|---|
| Container registry | Pull images, check versions | Only by not updating |
| Update endpoint | Is a newer lemonfiber available | Yes |
| IP echo service | Verify VPN egress | Yes — disables leak detection |
| Quality guide source | Sync profiles | Yes — disables preset sync |
No telemetry, no analytics, no installation identifier — enforced by a test,
not by intention (G8-R9).
Requests made by the services — indexer queries, metadata lookups — are theirs,
documented as such rather than claimed as ours (G8-R12).
An installed plugin adds a third kind: a request lemonfiber makes on the
plugin’s behalf, which is neither its own nor a service’s. Each is attributed
to the plugin that declared it, refusable on its own, and counted by the test
above (G8-R15–G8-R17). The four rows are what this table holds with nothing
installed, and that remains separately testable.
What is deliberately not in the picture
| Absent | Why |
|---|---|
| A lemonfiber server or cloud service | There isn’t one. Everything is local. |
| An account system | Nothing to sign up for. |
| Remote access | Deferred past 1.0; household access is LAN-only |
| A second host | A stack lives on one machine (B6-R10) |
Related
- component-model.md — inside the lemonfiber box
- data-flow.md — how content moves through it
- platform-matrix.md — how the host differs by OS
- C6 · G8