# Project Context This file is the canonical project context for AI agents working on Transmission Manager. Read it before making changes, and keep it updated whenever project purpose, architecture, APIs, file roles, workflows, constraints, or implementation patterns change. ## Purpose Transmission Manager is a lightweight local/LAN web app for viewing and managing torrents from a Transmission RPC daemon. The product goal is a fast, clean, dark-mode SPA that feels modern while remaining simple to build, deploy, and inspect. The app is intentionally small: one Go binary serves both the API and embedded frontend assets. The frontend is vanilla JavaScript, HTML, and CSS, with no package manager, no compile step, and no JS framework. ## Technology Stack - Go module: `transmission-manager` - Go version: `1.24` - Backend dependencies: standard library only - Frontend dependencies: none - Static assets: embedded with Go `embed` - Runtime port: `8080` - Docker build: `golang:1.24-alpine` builder, `alpine:latest` runtime - Runtime RPC configuration: `TRANSMISSION_URL`, `TRANSMISSION_RPC_USERNAME`, and `TRANSMISSION_RPC_PASSWORD` ## Repository Organization - `main.go`: backend entrypoint. Owns the HTTP server, embedded static file serving, environment-driven Transmission RPC client configuration, session-ID handshake, connection warning page, JSON helpers, and API routes. - `web/index.html`: SPA shell. Defines the header, stats pills, filter input, sort buttons, list container, empty state, error state, footer, and script/style links. - `web/icon.svg`: editable vector source for the app icon. - `web/icon.png`: reusable raster app icon used by the SPA header and browser tab. - `web/app.js`: frontend application logic. Owns state, polling, fetch helpers, formatting, torrent classification, sorting, keyed DOM reconciliation, pause/resume actions, and event wiring. - `web/styles.css`: all styling. Owns dark theme variables, layout, cards, badges, progress bars, action buttons, empty/error states, and responsive rules. - `go.mod`: Go module declaration. - `Dockerfile`: multi-stage production build. - `README.md`: public project documentation, configuration guide, and deployment instructions. - `AGENTS.md`: quick-start guide for coding agents. It must point agents back to this file. ## Backend Architecture The backend uses `net/http` with a single `http.ServeMux`. It exposes: - `GET /api/torrents`: sends Transmission `torrent-get` with the required torrent fields and returns the RPC `arguments` JSON directly. - `GET /api/stats`: sends Transmission `session-stats` and returns the RPC `arguments` JSON directly. - `POST /api/torrents/{id}/pause`: validates a positive numeric torrent id and sends `torrent-stop`. - `POST /api/torrents/{id}/resume`: validates a positive numeric torrent id and sends queue-respecting `torrent-start`. - `/`: checks the Transmission connection and serves a warning page with the connection error when setup fails; otherwise serves embedded files from `web/`. Transmission RPC calls must reuse the existing `Client.rpc` path so session-ID handling is consistent. The session ID is cached in `Client.sessionID` and guarded by `sync.Mutex`. API errors return JSON with an `error` string. Invalid torrent action methods should return `405`; invalid ids should return `400`; unknown action paths should return `404`; Transmission failures should return `502`. ## Transmission RPC Model The RPC endpoint is configured via `TRANSMISSION_URL` (which must be set). `TRANSMISSION_RPC_USERNAME` and `TRANSMISSION_RPC_PASSWORD` are optional; unset, empty, or literal `null` values mean no credential value. When either credential has a value, the backend sends HTTP Basic Auth on RPC requests. Transmission usually rejects the first request or an expired session with HTTP `409` and a fresh `X-Transmission-Session-Id` header. Correct behavior is to drain and close the response body, cache the new session ID, and retry the same JSON request once. Torrent list requests should include: ```text id, name, totalSize, downloadedEver, uploadedEver, uploadRatio, percentDone, status, eta, error, errorString, doneDate, isFinished, rateDownload, rateUpload, peersConnected, peersGettingFromUs, peersSendingToUs, availability, peers ``` Peer objects are expected to include `address`, `clientName`, `progress`, `isDownloadingFrom`, `isUploadingTo`, `rateToClient`, and `rateToPeer` when available. The UI definition of "peers at 100%" is an absolute count of `peers[]` entries whose `progress === 1.0`. Do not reinterpret it as a percentage of connected peers. The UI availability value comes from Transmission's `availability` per-piece array. Render and sort it as a complete-copy estimate, treating `-1` entries as pieces available locally. ## Frontend Architecture The frontend is a single page with module-level state in `web/app.js`. It polls on a user-selectable interval, defaults to 3 seconds, and fetches torrents and stats in parallel. Important patterns: - Polling must not create an F5-style visual refresh. Use keyed DOM reconciliation by torrent id. - Existing torrent cards should be updated in place. Create DOM only for new torrents, move existing nodes when sort order changes, and remove nodes only for hidden or removed torrents. - Keep `syncInFlight` / queued-sync behavior or equivalent protection so requests do not overlap. - Preserve filter input focus and local UI state during polling. - Action buttons are delegated from the torrent list. Pause/resume requests show pending text, disable the clicked button, then trigger an immediate sync on success. - Action failures should be shown inline on the card without clearing the list. Current sort keys: - `status`: default. Orders by status rank, then progress, then name. - `name` - `progress` - `ratio` - `size` - `speed`: orders by combined download and upload speed descending, then download speed, upload speed, and name. - `availability`: orders by computed availability descending, then progress, then name. ## UI And Design Rules - Dark mode only. - Use CSS variables from `:root` for theme values. - Keep the aesthetic modern, compact, and clean: dark background, subtle borders, cyan/purple accent, small badges, smooth progress bars. - Cards should have subtle hover effects and stable layout. - Card entrance animation should apply only to newly inserted cards, not every poll. - The app must remain usable on mobile and desktop. - Long torrent names must truncate with ellipsis rather than breaking layout. ## Implementation Rules - Do not add external Go dependencies. - Do not add frontend dependencies, bundlers, or transpilation. - Do not add auth unless explicitly requested. - Do not add CI/CD, GitHub Actions, or repository setup. - Keep changes scoped to the app files unless the user asks for broader project work. - Prefer small helper functions over new abstractions unless duplication or complexity justifies the abstraction. - Format Go with `gofmt` when the tool is available. - Use frontend formatting helpers for human-readable sizes, speeds, ratios, dates, percentages, and ETA. - Keep comments sparse and useful; avoid narrating obvious code. - Use ASCII in new documentation unless there is a specific reason to use non-ASCII characters. ## Verification Preferred checks: ```powershell gofmt -w main.go go test ./... node --check web\app.js git diff --check docker build . ```