chore(release): bump version to 1.7.0
Docs Check / Markdown lint (push) Failing after 25s
Build and Push Docker Image / build (push) Successful in 1m22s
Licence Check / Licence compatibility and copyright header verification (push) Failing after 1m8s
CI / Swagger Validation & Coverage (push) Successful in 1m51s
CI / Security audit (push) Successful in 2m2s
Docs Check / Mermaid diagram parse check (push) Successful in 2m11s
CI / Tests & coverage (push) Failing after 2m17s

- Increment version from 1.6.0 to 1.7.0 in package.json
- Add detailed CHANGELOG.md entry for Swagger UI & OpenAPI 3.1 documentation
- Update README.md version highlight to mention Swagger UI
- Add API Documentation System section (7.4) to ARCHITECTURE.md
- Add swagger-ui-express, swagger-jsdoc, yamljs, spectral-cli to Technology Stack
- Update High-Level Architecture diagram with Swagger UI node
- Update Request routing summary to include /api/swagger
- Update SECURITY.md: Threat Model, Rate Limits, and Supported Versions tables
This commit is contained in:
2026-05-21 13:35:31 +01:00
parent f3e1bd17fb
commit 1ed01d0ef0
5 changed files with 135 additions and 5 deletions
+77
View File
@@ -52,6 +52,7 @@ flowchart TB
status["Status Panel\n(Admin only)"]
history["History Tab"]
webhooks["Webhook Config"]
swagger["Swagger UI\n/api/swagger"]
end
subgraph Server["Express Server (:3001)"]
@@ -122,6 +123,7 @@ Express Server (:3001)
├── cookie-parser (HMAC-signed session cookie)
├── verifyCsrf (double-submit cookie, all state-changing /api routes except auth + webhook)
├── /api/swagger → Swagger UI (public, auth banner for testing)
├── /api/auth → login, logout, me, csrf
├── /api/webhook → [rate-limit] → [secret validation] → [payload validation]
│ → [replay check] → updateWebhookMetrics → processWebhookEvent
@@ -826,6 +828,72 @@ Related functions in `filters.js`:
Downloads are sorted by client order (matching the configuration order) and filtered by the selected client IDs.
### 7.4 API Documentation System
sofarr exposes interactive API documentation via **Swagger UI** at `/api/swagger`, using a hybrid documentation model that balances maintainability with consistency.
#### Architecture
```
server/openapi.yaml Central spec: base metadata, security schemes, reusable schemas
│ merge at runtime (swagger-jsdoc)
server/routes/*.js JSDoc @openapi comments per endpoint
│ serve (swagger-ui-express)
GET /api/swagger Swagger UI HTML (public, auth banner)
GET /api/swagger.json Merged OpenAPI 3.1 spec JSON
```
#### Central OpenAPI Specification (`server/openapi.yaml`)
The YAML file defines:
- **Base metadata** — `openapi: 3.1.0`, info, server URL, contact
- **Security schemes** — `CookieAuth` (`emby_user` cookie), `CsrfToken` (`X-CSRF-Token` header)
- **Component schemas** — `NormalizedDownload`, `DashboardPayload`, `ErrorResponse`, `BlocklistSearchRequest`, `WebhookPayload`, `HistoryItem`, `StatusResponse`
- **Path placeholders** — stub entries for every endpoint so JSDoc comments have a merge target
#### JSDoc `@openapi` Comments
Every route handler file contains JSDoc comments above each Express route definition:
```javascript
/**
* @openapi
* /api/auth/login:
* post:
* tags: [Authentication]
* summary: Authenticate with Emby
* ...
*/
router.post('/login', ...)
```
`swagger-jsdoc` scans `server/routes/**/*.js` and merges the YAML from these comments into the central spec at runtime.
#### Machine-Usable Extensions
For AI agents and automated tooling, every endpoint includes:
- **`x-code-samples`** — cURL, JavaScript fetch, and TypeScript examples
- **`x-integration-notes`** — Human-readable integration guidance embedded in descriptions
#### Coverage Validation
`tests/integration/swagger-coverage.test.js` (22 tests) validates:
- The YAML spec parses without errors
- Every Express route appears in the merged spec
- All examples are valid JSON
- Security schemes are correctly referenced (`CookieAuth`, `CsrfToken`)
- The Swagger UI endpoint returns `200`
#### CI/CD Integration
`.gitea/workflows/ci.yml` includes a "Swagger Validation & Coverage" job that:
- Lints `server/openapi.yaml` with `@stoplight/spectral-cli`
- Runs the coverage test suite on every push
---
## 8. Directory Structure
@@ -1056,6 +1124,15 @@ Each instance receives an `id` derived from `name` (or index if unnamed), used a
| `express-rate-limit` | 7.x | General, login, and webhook rate limiters |
| `cookie-parser` | 1.x | Signed cookie support (HMAC via `COOKIE_SECRET`) |
### API Documentation
| Package | Version | Purpose |
|---------|---------|---------|
| `swagger-ui-express` | 5.x | Serve interactive Swagger UI at `/api/swagger` |
| `swagger-jsdoc` | 6.x | Merge JSDoc `@openapi` comments with central YAML spec |
| `yamljs` | 0.3.x | Parse `server/openapi.yaml` at runtime for swagger-jsdoc |
| `@stoplight/spectral-cli` | 6.x (dev) | Lint OpenAPI spec for correctness in CI |
### Auth and Session
| Component | Technology | Details |
+48
View File
@@ -6,6 +6,54 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
---
## [1.7.0] - 2026-05-21
### Added
#### Swagger UI & OpenAPI 3.1 Documentation
- **Swagger UI at `/api/swagger`** — Interactive API documentation served via `swagger-ui-express`; publicly accessible with a custom authentication banner (`public/swagger-auth-banner.js`) that explains the cookie-based + CSRF-token authentication flow for testing endpoints directly in the browser.
- **OpenAPI 3.1 specification** — Central `server/openapi.yaml` file containing base metadata, security schemes (`CookieAuth`, `CsrfToken`), and reusable component schemas:
- `NormalizedDownload` — standardised download object returned by all PDCA clients
- `DashboardPayload` — SSE payload shape (`{ user, isAdmin, downloads, downloadClients }`)
- `ErrorResponse` — standard error envelope with redacted details
- `BlocklistSearchRequest` — payload for the admin blocklist-and-search operation
- `WebhookPayload` — Sonarr/Radarr webhook event structure
- `HistoryItem` — deduplicated history record with upgrade-availability flag
- `StatusResponse` — server metrics, polling timings, cache stats, and webhook metrics
- **Hybrid documentation approach** — Per-endpoint details are documented directly in route handler files (`server/routes/*.js`) using JSDoc `@openapi` comments. `swagger-jsdoc` merges these comments with the central YAML at runtime, keeping documentation close to the code while maintaining shared schemas in one place.
- **Comprehensive endpoint coverage** — All implemented endpoints are documented:
- Authentication: `POST /api/auth/login`, `GET /api/auth/me`, `GET /api/auth/csrf`, `POST /api/auth/logout`
- Dashboard: `GET /api/dashboard/stream` (SSE), `GET /api/dashboard/user-downloads` (deprecated), `GET /api/dashboard/cover-art`, `POST /api/dashboard/blocklist-search`
- Status: `GET /api/status`
- History: `GET /api/history/recent`
- Webhooks: `POST /api/webhook/sonarr`, `POST /api/webhook/radarr`
- Proxy routes: Sonarr, Radarr, SABnzbd, and Emby authenticated proxies
- Public health: `GET /health`, `GET /ready`
- **Machine-usable extensions** — Every documented endpoint includes:
- `x-code-samples` with cURL, JavaScript fetch, and TypeScript examples
- `x-integration-notes` section in descriptions for AI agents and automated tooling
- Realistic request/response examples and full JSON Schema definitions
- **Coverage validation test suite** — `tests/integration/swagger-coverage.test.js` (22 tests) validates that:
- The OpenAPI spec loads without YAML parse errors
- Every Express route appears in the merged spec
- All schema and response examples are valid JSON
- Required security schemes (`CookieAuth`, `CsrfToken`) are defined and referenced correctly
- The Swagger UI HTML endpoint (`GET /api/swagger`) returns `200`
- **CI/CD validation job** — Added "Swagger Validation & Coverage" job in `.gitea/workflows/ci.yml` that runs on every push:
- Lints `server/openapi.yaml` with `@stoplight/spectral-cli`
- Runs `npm test -- tests/integration/swagger-coverage.test.js` to verify coverage
### Changed
- **Dependencies added** — `swagger-ui-express` (^5.0.1), `swagger-jsdoc` (^6.2.8), `yamljs` (^0.3.0), and `@stoplight/spectral-cli` (^6.16.0 dev dependency) for OpenAPI generation, UI serving, and spec linting.
### Security
- **Swagger UI public access** — The Swagger UI endpoint (`/api/swagger`) is publicly accessible by design for convenience. All documented API endpoints still enforce authentication (`emby_user` cookie) and CSRF protection (`X-CSRF-Token` header for mutations) as before. The authentication banner in the UI explicitly instructs users to log in via `POST /api/auth/login` first before testing protected endpoints.
---
## [1.6.0] - 2026-05-21
### Added
+1 -1
View File
@@ -4,7 +4,7 @@
**sofarr** is a personal media download dashboard that aggregates and displays real-time download progress from all your media automation services. Named for the experience of checking what has downloaded "so far" while you wait comfortably on your "sofa" for Sonarr, Radarr, and your download clients to do their thing!
Version 1.5.x adds **real-time webhook integration**: Sonarr and Radarr can push events directly to sofarr, eliminating polling latency and automatically reducing background API calls when webhooks are active.
Version 1.7.x adds **interactive Swagger UI and OpenAPI 3.1 documentation** at `/api/swagger` — explore, test, and integrate with the full API using a hybrid YAML + JSDoc documentation system.
## What It Does
+8 -3
View File
@@ -4,9 +4,12 @@
| Version | Supported |
|---------|-----------|
| 1.4.x | ✅ Yes |
| 1.3.x | ✅ Yes |
| 1.2.x | ✅ Yes |
| 1.7.x | ✅ Yes |
| 1.6.x | ✅ Yes |
| 1.5.x | ✅ Yes |
| 1.4.x | ❌ No |
| 1.3.x | ❌ No |
| 1.2.x | ❌ No |
| 1.1.x | ❌ No |
| 1.0.x | ❌ No |
| < 1.0 | ❌ No |
@@ -41,6 +44,7 @@ users via Emby. The primary threat surface when exposed to the public internet:
| Webhook payload injection | `validatePayload()` allowlists 18 known event types; rejects non-object bodies and overlong fields |
| Webhook replay attacks | `isReplay()` tracks `(eventType, instanceName, date)` tuples for 5 minutes; duplicate events return `200 { duplicate: true }` without cache mutation |
| Webhook flood / DoS | Dedicated rate limiter: 60 requests/min per IP on `/api/webhook/*` |
| API documentation disclosure | Swagger UI at `/api/swagger` publicly exposes endpoint structure; mitigated by endpoint auth requirements and CSRF protection on all mutations |
---
@@ -161,6 +165,7 @@ server {
| `POST /api/auth/login` | 10 failed attempts per 15 min per IP |
| All `/api/*` routes | 300 requests per 15 min per IP |
| `POST /api/webhook/*` | 60 requests per 1 min per IP (webhook-specific limiter, stricter than general) |
| `GET /api/swagger` | No rate limit (public documentation) |
---
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "sofarr",
"version": "1.6.0",
"version": "1.7.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",
"main": "server/index.js",
"scripts": {