chore: bump version to 1.6.0, update CHANGELOG and ARCHITECTURE docs
Build and Push Docker Image / build (push) Successful in 48s
CI / Security audit (push) Successful in 1m23s
Docs Check / Markdown lint (push) Successful in 1m10s
CI / Tests & coverage (push) Successful in 1m47s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 1m18s
Docs Check / Mermaid diagram parse check (push) Successful in 1m44s
Build and Push Docker Image / build (push) Successful in 48s
CI / Security audit (push) Successful in 1m23s
Docs Check / Markdown lint (push) Successful in 1m10s
CI / Tests & coverage (push) Successful in 1m47s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 1m18s
Docs Check / Mermaid diagram parse check (push) Successful in 1m44s
This commit is contained in:
+7
-5
@@ -85,7 +85,7 @@ flowchart TB
|
|||||||
|
|
||||||
login -->|"POST /api/auth/login"| auth_r
|
login -->|"POST /api/auth/login"| auth_r
|
||||||
dash -->|"GET /api/dashboard/stream (SSE)"| dash_r
|
dash -->|"GET /api/dashboard/stream (SSE)"| dash_r
|
||||||
status -->|"GET /api/status/status"| stat_r
|
status -->|"GET /api/status"| stat_r
|
||||||
history -->|"GET /api/history/recent"| hist_r
|
history -->|"GET /api/history/recent"| hist_r
|
||||||
|
|
||||||
auth_r --> tokenstore
|
auth_r --> tokenstore
|
||||||
@@ -452,10 +452,10 @@ Every `POLL_INTERVAL` ms the poller fetches all services in parallel:
|
|||||||
| SABnzbd History | `GET /api?mode=history` | `limit=10` |
|
| SABnzbd History | `GET /api?mode=history` | `limit=10` |
|
||||||
| Sonarr Tags | `GET /api/v3/tag` | — |
|
| Sonarr Tags | `GET /api/v3/tag` | — |
|
||||||
| Sonarr Queue | `GET /api/v3/queue` | `includeSeries=true`, `includeEpisode=true` |
|
| Sonarr Queue | `GET /api/v3/queue` | `includeSeries=true`, `includeEpisode=true` |
|
||||||
| Sonarr History | `GET /api/v3/history` | `pageSize=10`, `includeEpisode=true` |
|
| Sonarr History | `GET /api/v3/history` | `pageSize=50`, `includeEpisode=true` |
|
||||||
| Radarr Tags | `GET /api/v3/tag` | — |
|
| Radarr Tags | `GET /api/v3/tag` | — |
|
||||||
| Radarr Queue | `GET /api/v3/queue` | `includeMovie=true` |
|
| Radarr Queue | `GET /api/v3/queue` | `includeMovie=true` |
|
||||||
| Radarr History | `GET /api/v3/history` | `pageSize=10` |
|
| Radarr History | `GET /api/v3/history` | `pageSize=50` |
|
||||||
| qBittorrent | `GET /api/v2/sync/maindata?rid=N` | Fallback: `GET /api/v2/torrents/info` |
|
| qBittorrent | `GET /api/v2/sync/maindata?rid=N` | Fallback: `GET /api/v2/torrents/info` |
|
||||||
|
|
||||||
Results are stored in `MemoryCache` under `poll:*` keys with TTL `POLL_INTERVAL × 3`. Per-task timings are recorded in `lastPollTimings` for the admin status panel.
|
Results are stored in `MemoryCache` under `poll:*` keys with TTL `POLL_INTERVAL × 3`. Per-task timings are recorded in `lastPollTimings` for the admin status panel.
|
||||||
@@ -718,7 +718,9 @@ DownloadClient (abstract — server/clients/DownloadClient.js)
|
|||||||
|
|
||||||
### 7.2 Queue & History Processing
|
### 7.2 Queue & History Processing
|
||||||
|
|
||||||
**`server/utils/historyFetcher.js`** fetches history records from all Sonarr/Radarr instances for a configurable date window. Results are cached under `history:sonarr` / `history:radarr` for 5 minutes. Exports `classifySonarrEvent` / `classifyRadarrEvent` (returns `'imported'` | `'failed'` | `'other'`) and `invalidateHistoryCache`.
|
**`server/utils/historyFetcher.js`** fetches history records from all Sonarr/Radarr instances for a configurable date window. Results are cached under `history:sonarr` / `history:radarr` for 5 minutes. Exports `classifySonarrEvent` / `classifyRadarrEvent` (returns `'imported'` | `'failed'` | `'other'`), `invalidateHistoryCache`, and `onHistoryUpdate` / `emitHistoryUpdate` for SSE staging.
|
||||||
|
|
||||||
|
**Staged loading** — the fetcher returns up to `INITIAL_PAGE_SIZE` (100) records immediately from the cache or a quick fetch. If fewer than `MAX_TOTAL_RECORDS` (1,000) are present, a background fetch of up to `MAX_PAGES` (10) is triggered automatically. As the background fetch completes, `emitHistoryUpdate()` notifies all registered subscribers, which causes the SSE layer to push a `history-update` frame to every connected browser. The frontend (`client/src/ui/history.js`) listens for these events and re-renders the "Recently Completed" tab incrementally.
|
||||||
|
|
||||||
**`server/routes/history.js`** (`GET /api/history/recent`) returns recently completed (imported or failed) downloads filtered for the authenticated user. Supports `?days=N` (default `RECENT_COMPLETED_DAYS`, capped at 90) and `?showAll=true` for admins. Results are sorted newest first.
|
**`server/routes/history.js`** (`GET /api/history/recent`) returns recently completed (imported or failed) downloads filtered for the authenticated user. Supports `?days=N` (default `RECENT_COMPLETED_DAYS`, capped at 90) and `?showAll=true` for admins. Results are sorted newest first.
|
||||||
|
|
||||||
@@ -844,7 +846,7 @@ sofarr/
|
|||||||
│ ├── routes/
|
│ ├── routes/
|
||||||
│ │ ├── auth.js POST /login, GET /me, GET /csrf, POST /logout
|
│ │ ├── auth.js POST /login, GET /me, GET /csrf, POST /logout
|
||||||
│ │ ├── dashboard.js SSE /stream, /user-downloads, /blocklist-search
|
│ │ ├── dashboard.js SSE /stream, /user-downloads, /blocklist-search
|
||||||
│ │ ├── status.js GET /api/status/status — admin server/polling/webhook status
|
│ │ ├── status.js GET /api/status — admin server/polling/webhook status
|
||||||
│ │ ├── history.js GET /api/history/recent
|
│ │ ├── history.js GET /api/history/recent
|
||||||
│ │ ├── webhook.js POST /api/webhook/sonarr|radarr
|
│ │ ├── webhook.js POST /api/webhook/sonarr|radarr
|
||||||
│ │ ├── sonarr.js Sonarr API proxy + webhook management
|
│ │ ├── sonarr.js Sonarr API proxy + webhook management
|
||||||
|
|||||||
@@ -6,6 +6,52 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [1.6.0] - 2026-05-21
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Staged history loading with SSE push** — history data from Sonarr/Radarr is now fetched in stages; `history-update` SSE events push incremental results to the dashboard so the "Recently Completed" tab populates without waiting for the full fetch.
|
||||||
|
- **Frontend unit tests** — added Vitest + jsdom test suite covering `client/src/` modules (formatters, storage, state).
|
||||||
|
- **Comprehensive tests for staged history loading** — backend tests verify the new background-fetch behaviour, cache TTL handling, and SSE emission.
|
||||||
|
- **Integration test coverage** — new integration and unit tests for `dashboard`, `emby`, `sonarr`, `radarr`, and `sabnzbd` routes.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Technical-debt remediation — service extraction** — extracted matching and assembly logic from the monolithic `dashboard.js` (~1,360 lines → ~284 lines) into dedicated, testable services:
|
||||||
|
- `DownloadMatcher.js` — SABnzbd slot / torrent → *arr record matching
|
||||||
|
- `DownloadAssembler.js` — cover-art, episode, link, blocklist-eligibility helpers
|
||||||
|
- `DownloadBuilder.js` — orchestrator that reads the cache snapshot and builds the final user-facing download list
|
||||||
|
- `TagMatcher.js` — tag extraction, sanitisation, and user-ownership matching
|
||||||
|
- `WebhookStatus.js` — webhook configuration status aggregation
|
||||||
|
- **Frontend architecture** — migrated from a monolithic `public/app.js` to vanilla ES modules under `client/src/`, bundled by Vite into `public/app.js`.
|
||||||
|
- **History pagination** — replaced custom date-based cursor pagination with the retriever's built-in pagination (`pageSize=100`, up to 10 pages / 1,000 records total). Eliminates the 40-second response-time regression seen with large histories.
|
||||||
|
- **Status endpoint path** — admin status route moved from `/api/status/status` to `/api/status` for consistency with the router mount point.
|
||||||
|
- **Background-fetch safety** — the poller no longer overwrites the cache with empty data when a background history fetch fails or returns no records.
|
||||||
|
- **SABnzbd progress calculation** — progress is now computed from `slot.mb` and `slot.mbleft` / `slot.mbmissing` because the SABnzbd queue API does not expose a `percentage` field.
|
||||||
|
- **Speed formatting consistency** — `updateDownloadCard()` now calls `formatSpeed()` so all speed values display with uniform units (B/s, KB/s, MB/s, GB/s).
|
||||||
|
- **Status-panel error handling** — the panel now surfaces error messages (e.g. `403` for non-admin users) instead of showing a blank box.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **CSRF token reference errors** — fixed `ReferenceError` bugs in `api.js`, `auth.js`, and the blocklist handler where `csrfToken` and `currentUser` were accessed as bare variables instead of via the shared `state` object.
|
||||||
|
- **Logout button** — fixed undefined variable references in `handleLogoutClick` that prevented the logout flow from completing.
|
||||||
|
- **Missing progress bar for SABnzbd** — SABnzbd downloads now render a correct progress bar instead of showing `undefined%`.
|
||||||
|
- **Status route 404** — corrected the Express router mount so `GET /api/status` responds instead of returning HTML 404.
|
||||||
|
- **Status button DOM ID** — fixed element-ID mismatch (`status-btn` vs `status-toggle`) that prevented the admin status button from toggling the panel.
|
||||||
|
- **Tab selection** — fixed tab switching to use `data-tab` attributes after the DOM IDs were removed during the ES-module migration.
|
||||||
|
- **CSP violations and `ignoreAvailable` reference error** — resolved frontend CSP compliance issues and a missing-variable error in the history tab.
|
||||||
|
- **Docker client-build stage** — removed `client/` from `.dockerignore` so the multi-stage Dockerfile can run the Vite build during image creation.
|
||||||
|
- **Unmatched torrent exclusion** — torrents that cannot be matched to a Sonarr/Radarr record are now correctly omitted from the download display.
|
||||||
|
- **Blocklist button CSRF** — fixed a `ReferenceError` that occurred when a non-admin user clicked the blocklist button.
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
- **Unmatched torrents are no longer displayed** — torrents that do not match a Sonarr/Radarr queue or history record are excluded from the dashboard. Users who previously saw direct torrent-client downloads will no longer see them unless the *arr services track the item.
|
||||||
|
- **Frontend build process changed** — the monolithic `public/app.js` source file has been replaced by a Vite build from `client/src/`. Any custom deployment scripts that copy or modify `public/app.js` directly must be updated to run `npm run build` (or use the provided Dockerfile, which already does this).
|
||||||
|
- **Status API endpoint path changed** — the admin status endpoint moved from `/api/status/status` to `/api/status`. External integrations, monitoring checks, or scripts hitting the old path will receive `404`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [1.5.5] - 2026-05-20
|
## [1.5.5] - 2026-05-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sofarr",
|
"name": "sofarr",
|
||||||
"version": "1.5.5",
|
"version": "1.6.0",
|
||||||
"description": "A personal media download dashboard that shows your downloads 'so far' while you relax on the sofa waiting for your *arr services to finish",
|
"description": "A personal media download dashboard that shows your downloads 'so far' while you relax on the sofa waiting for your *arr services to finish",
|
||||||
"main": "server/index.js",
|
"main": "server/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Reference in New Issue
Block a user