Files
bookorbit/client
neon 33952322f2 feat(settings): add Prowlarr and SABnzbd support (#1416)
* feat(settings): add SABnzbd download client

Support API-key authentication, NZB uploads, queue monitoring, reconciliation, and completed-download imports through SABnzbd.

Expose the client in request settings and validate its required category and credentials.

Ref #1312

* feat(settings): add Prowlarr indexer management

Manage synchronized torrent and Usenet sources through a shared Prowlarr connection.

Ref #1312

* fix(settings): correct SABnzbd adoption and managed search retries

Address four defects found in review of the Prowlarr and SABnzbd work.

SABnzbd keeps a failed job in its history until somebody clears it, and BookOrbit removes a client
download only on an explicit action. Because the client key is a stable digest, re-grabbing the same
release adopted that dead history entry, never uploaded the NZB, and failed instantly and forever.
Adopt only an entry that is not already failed; a queue entry still wins, so a fresh upload reports
correctly.

The category-expansion retry reused the title-and-author query, making it strictly narrower on text
than the title-only attempt that had just returned nothing. A release matching only a title-only
search with expanded categories was therefore unreachable. Drop the author there so each rung of the
ladder is genuinely broader than the last.

Changing the download client type through the create form's select bypassed the picker's handler, so
a username typed for qBittorrent was still sent when SABnzbd was chosen. The server stores it, the
API-key form hides it, and it can no longer be edited away. Watch the credential kind instead, so
both controls clear it.

Finally, a swallowed managed-release refresh failure left nothing behind at all; give it its own
fail log while still reporting the original refusal to the caller.

* fix(requests): cast managed search health flags to boolean

The bulk search-health update bound each case branch as an untyped
parameter, so Postgres could not resolve it against the boolean column.
Cast every branch explicitly and assert the cast in the repository test.

* fix(requests): close review gaps in Prowlarr and SABnzbd support

Inventory the eight indexer-manager routes so the authorization matrix
probes them, resolve a managed indexer without reading its manager's
whole source list, keep an unreadable credential out of the test-failed
mapping, translate manager error codes, and show per-source search
health. Documents Prowlarr connections in docs/BOOK_REQUESTS.md.

* i18n(client): keep the retired sources empty-state key

Dropping bodyOneWay from en.json forced pruning it from five Crowdin
target catalogs, which the localization policy check rejects outright.
Leave the now-unused key in place; nothing validates unreferenced
English source keys, so Crowdin can retire it on its own schedule.

* db: regenerate the SABnzbd and Prowlarr migration onto main

Rebasing collided with main's own 0091 and 0092, which left this branch's
two migrations on disk with no journal entry referencing them. Drop both
and regenerate a single migration on main's lineage; the three affected
tables are schema-identical to the pre-rebase snapshot.
2026-09-20 18:38:36 -06:00
..

BookOrbit - Client

Vue 3 SPA built with Vite and Tailwind CSS v4.

Running

From the repo root: pnpm dev (starts both server and client).

Client only: pnpm dev (from this directory). Runs at http://localhost:5173.

The Vite dev server proxies /api and /socket.io requests to the backend at localhost:3000.

IDE setup

  • VS Code: Install the Vue (Official) extension. Disable Vetur if installed.
  • WebStorm / IntelliJ: Vue support is built in. Enable TypeScript service for .vue files.
  • Browser: Install Vue.js devtools and enable Custom Object Formatters in DevTools settings.

Project layout

src/
├── features/           Feature modules (one folder per domain)
│   ├── auth/           Login, registration, password reset
│   ├── book/           Book detail, covers, metadata
│   ├── library/        Library management
│   ├── collection/     Book collections
│   ├── smart-scope/           Saved search views
│   ├── scanner/        Scan progress UI
│   ├── reader/         Book reader (epub, pdf, cbz)
│   ├── settings/       User settings
│   └── admin/          Admin panel (users, roles, settings)
├── components/         Shared components (header, sidebar, icons)
│   └── ui/             Reusable UI primitives (button, dialog, etc.)
├── composables/        Global composables
├── views/              Route-level page components
├── router/             Vue Router config and guards
├── lib/                Utilities (api client, helpers)
├── stores/             Pinia stores (theme only - prefer composables)
└── assets/             CSS, fonts, static assets

Testing

pnpm test:unit          # run unit tests
pnpm test:cov           # run unit tests with coverage

Key conventions

  • All components use <script setup lang="ts"> (Composition API only).
  • Feature state lives in composables (features/<name>/composables/use*.ts), not global stores.
  • HTTP calls use the native fetch API via src/lib/api.ts.
  • Styling with Tailwind CSS v4 utility classes. Theme tokens are CSS variables in src/assets/main.css.
  • Icons from @lucide/vue only.
  • Shared types imported from @bookorbit/types.