Files
arr/PRODUCT.md
Miguel Palhas ab4f95b166
ci / web (push) Successful in 32s
ci / rust (push) Successful in 3m26s
e2e / e2e (push) Failing after 5m2s
ci / image (push) Successful in 4m1s
feat(dl): replace Transmission with qBittorrent
qBittorrent's add call answers `Ok.` and nothing else — no hash, no name,
no duplicate signal — so arr derives the v1 infohash from the magnet or the
`.torrent` bytes before the call and looks the torrent up by it. That also
drops Transmission's numeric torrent id: the hash is the only identity now.

The reaper needs "stopped because a share limit was reached", and
qBittorrent's state field cannot tell that apart from a hand-paused torrent.
So the ratio and idle counters are checked against the limits arr set, and a
torrent stopped by a global limit reads as still seeding rather than being
deleted.

The WebUI needs a login, so `ARR_QBITTORRENT_USERNAME` and
`ARR_QBITTORRENT_PASSWORD` join the env-only secrets; leaving both unset is
valid for an instance that whitelists arr's subnet.

Verified against qBittorrent 5 (WebAPI 2.15.1) in a container: it rejects
`setShareLimits` without `shareLimitAction`, which 4.x ignores, so it is
always sent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 18:13:50 +01:00

3.5 KiB

Product

All facts below are drawn from DESIGN.md and the issue tracker; none were confirmed in an interview (the driving session mandated autonomous operation). Items marked (inferred) are best-effort readings, not user-approved.

Platform

web

Stack

Vite + TypeScript SPA, no framework (fixed by DESIGN.md §11: web/ is a Vite + TypeScript SPA embedded in the Rust binary via include_dir; the reference project ~/tea/maestro is framework-free vanilla TS).

Users

A single household's operator (the person who runs the media stack) and, via filtered views, a small set of family members. Used on a self-hosted LAN/VPN, mostly desktop, sometimes phone. The operator's job: decide what media is wanted, watch it get sourced, and resolve the queue items that need a human call (no-PT-source queue, waivers, manual grabs).

Product Purpose

One service replacing Radarr, Sonarr and later Bazarr: decide what you want, find it, fetch it, put it somewhere Jellyfin can read. Success is a 20-40 MB single binary doing what five .NET services do at 600-900 MB — with a UI whose manual-search view is actually usable.

Positioning

Policy engine classifies every release candidate before the human sees it. The UI shows decisions (eligible / waived / rejected, with the killing rule named), not raw release-name dumps. Radarr cannot truthfully claim this; its manual search buries the decision under the release name column.

Operating Context

  • Self-hosted behind VPN + Authelia; the app itself has no auth layer.
  • API-first: the SPA is one client of the OpenAPI-described HTTP API, no privileged path.
  • Coexists with Prowlarr (indexers), qBittorrent (downloads), Jellyfin (playback), Jellyseerr (requests), ntfy (notifications).

Capabilities and Constraints

  • Phase 1 (now): skeleton only — health endpoint, embedded empty SPA shell with one page rendering GET /api/health.
  • Phase 5 brings the real UI: unified search (§9.2), manual search buckets (§9.3), library views, queues.
  • The manual-search view is the reason the UI exists; §9.3 fixes chip-based columns, three buckets, secondary release names. Future tokens/components must serve dense, scannable, chip-heavy tabular data.
  • CI gate: biome ci web/ and tsc -b --noEmit; target under 5 min total.
  • Bundle is embedded at compile time; no CDN, no external assets at runtime (inferred from the include_dir + single-binary requirement).

Brand Commitments

Name: arr, lowercase. No logo, no committed palette or typography yet (inferred: nothing visual exists in the repo). Voice of DESIGN.md is terse, technical, anti-noise — the UI should read the same way.

Evidence on Hand

  • DESIGN.md — the contract, including §9.2/§9.3 UI specs.
  • ~/tea/maestro — reference for repo/web mechanics, not visual identity.
  • No screenshots, no user testimonials, no existing UI. Nothing to fabricate.

Product Principles

  • Decisions over data: surface the classification, keep the raw evidence one expand away.
  • Quiet by default: default views show only what needs attention; everything satisfied collapses (mirrors §4.2 and §9.5's notification restraint).
  • Density with fixed structure: chips and fixed-width columns, never horizontal scroll.
  • One surface of truth: the API; the UI never has a privileged path.

Accessibility & Inclusion

No product-specific requirement established. Household includes a pre-reader child, but the child consumes Jellyfin, not this UI (inferred).