The big picture¶
Nessie is one FastAPI process. It answers the JSON API under /v1/… and also serves the UI's files straight from frontend/. The UI has no build step. The browser loads index.html, which loads js/main.js as an ES module, and the browser follows the imports from there. What you see in the editor is exactly what runs.
flowchart LR
subgraph Browser
UI["UI (frontend/)<br/>index.html + js/ modules"]
SW["Service worker<br/>sw.js"]
AUD["#lt;audio#gt; element"]
end
subgraph Server["Nessie server (app/)"]
API["FastAPI routes<br/>app/api/"]
SVC["Services and repositories<br/>app/services, app/repositories"]
MPV["mpv subprocess<br/>(the server's speakers)"]
end
DB[("Postgres")]
FILES[("Music files<br/>+ artwork store")]
EXT["MusicBrainz, Wikidata,<br/>Fanart.tv, Anthropic, Lidarr"]
UI -- "fetch /v1/..." --> SW --> API
AUD -- "GET /v1/library/tracks/{id}/stream" --> SW
API --> SVC --> DB
SVC --> FILES
SVC --> MPV
SVC --> EXT
Two UIs share the same API and data:
/is the current UI (internally called v3), the subject of this guide./v2/is the classic UI: one large script,frontend/v2/js/script_v2.js. It's kept working but isn't where new work goes.
Music can play in two places, and the UI treats them the same way:
- The server's speakers. The server runs
mpvand keeps the queue itself. The UI sends commands and polls the state. - This device. An
<audio>element in the browser streams files from the server. The queue lives in the page.
FastAPI also generates interactive API docs at /docs, built from the same code this guide describes. Use them to try calls by hand.