docs(api): document unified tunable system settings endpoints
The scattered scan-settings JSON routes are superseded by the new admin-only /api/system/settings pair backed by the SettingsRegistry (introduced in885f6d8/bc47450). - Rewrite system/settings.md around GET/PUT /api/system/settings: SettingEntry metadata shape (type, min/max, requires_restart, category, group, is_default), type-aware validation rules, and the full tunable-setting catalog (scanner, general, security, api, sync, performance) with defaults, ranges, and restart requirements - Note the legacy /api/libraries/scan-settings routes as back-compat only (they now refresh the registry cache on write) - Add system/config.md for GET/PUT /api/system/config: raw key/value system configuration (e.g. base_url), including validation notes and guidance to prefer the typed settings endpoint for registry keys
This commit is contained in:
@@ -0,0 +1,77 @@
|
|||||||
|
# System Config API
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Raw key/value system configuration storage (backed by the `system_config` table). Unlike the typed [System Settings API](settings.md), this endpoint reads and writes arbitrary config keys as plain strings — including keys without registry metadata, such as `base_url`.
|
||||||
|
|
||||||
|
**Base URL**: `/api/system`
|
||||||
|
**Authentication**: Admin JWT token required
|
||||||
|
**Content-Type**: `application/json`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
### Get System Configuration
|
||||||
|
|
||||||
|
Retrieve all system configuration entries as a flat key/value map.
|
||||||
|
|
||||||
|
**Endpoint**: `GET /api/system/config`
|
||||||
|
|
||||||
|
**Authentication**: Admin role required
|
||||||
|
|
||||||
|
**Response**: **200 OK**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"base_url": "http://192.168.1.100:8765",
|
||||||
|
"default_timezone": "America/New_York"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET https://bookhoard.example.com/api/system/config \
|
||||||
|
-H "Authorization: Bearer <admin_token>"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Update System Configuration
|
||||||
|
|
||||||
|
Update one or more config values.
|
||||||
|
|
||||||
|
**Endpoint**: `PUT /api/system/config`
|
||||||
|
|
||||||
|
**Authentication**: Admin role required
|
||||||
|
|
||||||
|
**Request Body**: a flat map of keys to string values. Only the supplied keys are updated.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"base_url": "https://bookhoard.example.com"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Validation**: values for known keys are validated where applicable — for example, `default_timezone` must be a valid IANA timezone (`time.LoadLocation`); invalid values return `400` without persisting.
|
||||||
|
|
||||||
|
**Response**: **200 OK** on success; `400` (invalid value/format), `401`, `403`, `500` on failure.
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X PUT https://bookhoard.example.com/api/system/config \
|
||||||
|
-H "Authorization: Bearer <admin_token>" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"base_url": "https://bookhoard.example.com"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** settings that appear in the typed settings registry (e.g. `default_timezone`) are better managed through [`PUT /api/system/settings`](settings.md), which also returns metadata and reload hints. Writes through either endpoint refresh the shared registry cache.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Endpoints
|
||||||
|
|
||||||
|
- [System Settings API](settings.md) — typed, validated tunable settings with metadata
|
||||||
|
- `GET /api/devices/:id/sidecar` — device setup config derived from system config (see [Devices API](../devices/))
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
# System Scan Settings API
|
# System Settings API
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The System Scan Settings API allows administrators to configure system-wide scan settings that apply to all libraries. These settings control the automatic scanning behavior for the entire Bookhoard system.
|
The System Settings API is the canonical way to read and write Bookhoard's tunable system settings (scanning, security, rate limits, sync, performance, and defaults). Every setting carries full metadata — type, range, category, description, and whether a restart is required — so the admin UI (and API clients) can render and validate settings generically.
|
||||||
|
|
||||||
**Base URL**: `/api/libraries`
|
**Base URL**: `/api/system`
|
||||||
**Authentication**: Admin JWT token required
|
**Authentication**: Admin JWT token required
|
||||||
**Content-Type**: `application/json`
|
**Content-Type**: `application/json`
|
||||||
|
|
||||||
@@ -12,49 +12,61 @@ The System Scan Settings API allows administrators to configure system-wide scan
|
|||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
### Get System Scan Settings
|
### List All Settings
|
||||||
|
|
||||||
Retrieve the current system-wide scan settings.
|
Retrieve every known tunable setting with its current value and metadata.
|
||||||
|
|
||||||
**Endpoint**: `GET /api/libraries/scan-settings`
|
**Endpoint**: `GET /api/system/settings`
|
||||||
|
|
||||||
**Authentication**: Admin role required
|
**Authentication**: Admin role required
|
||||||
|
|
||||||
**Response**:
|
**Response**: **200 OK**
|
||||||
|
|
||||||
- **200 OK**: Returns current scan settings
|
|
||||||
- **401 Unauthorized**: Invalid or missing authentication
|
|
||||||
- **403 Forbidden**: User does not have admin role
|
|
||||||
- **500 Internal Server Error**: Server error
|
|
||||||
|
|
||||||
**Response Body**:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
[
|
||||||
"scan_poll_interval_seconds": 60,
|
{
|
||||||
"auto_scan_enabled": true
|
"key": "scan_poll_interval_seconds",
|
||||||
}
|
"value": "60",
|
||||||
|
"type": "int",
|
||||||
|
"min": "1",
|
||||||
|
"max": "3600",
|
||||||
|
"requires_restart": false,
|
||||||
|
"category": "scanner",
|
||||||
|
"group": "Scanning",
|
||||||
|
"description": "How often to scan all libraries (seconds)",
|
||||||
|
"is_default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
**Fields**:
|
**Entry fields**:
|
||||||
|
|
||||||
- `scan_poll_interval_seconds` (integer): How often to poll for file changes in seconds (1-3600)
|
| Field | Type | Description |
|
||||||
- `auto_scan_enabled` (boolean): Whether auto-scanning is enabled system-wide
|
| ------------------ | ------- | -------------------------------------------------------- |
|
||||||
|
| `key` | string | Setting identifier (stable API name) |
|
||||||
|
| `value` | string | Current value (validated/clamped by the registry) |
|
||||||
|
| `type` | string | `int`, `bool`, or `string` |
|
||||||
|
| `min` / `max` | string | Range bounds for `int` settings (omitted otherwise) |
|
||||||
|
| `requires_restart` | boolean | Change takes effect only after a server restart |
|
||||||
|
| `category` | string | Coarse area: `scanner`, `security`, `api`, `sync`, `performance`, `general` |
|
||||||
|
| `group` | string | Sub-section shown in the admin UI |
|
||||||
|
| `description` | string | Human-readable description |
|
||||||
|
| `is_default` | boolean | True when the current value equals the compiled default |
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X GET https://bookhoard.example.com/api/libraries/scan-settings \
|
curl -X GET https://bookhoard.example.com/api/system/settings \
|
||||||
-H "Authorization: Bearer <admin_token>"
|
-H "Authorization: Bearer <admin_token>"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Update System Scan Settings
|
### Update a Setting
|
||||||
|
|
||||||
Update the system-wide scan settings.
|
Validate, persist, and reload a single setting.
|
||||||
|
|
||||||
**Endpoint**: `PUT /api/libraries/scan-settings`
|
**Endpoint**: `PUT /api/system/settings`
|
||||||
|
|
||||||
**Authentication**: Admin role required
|
**Authentication**: Admin role required
|
||||||
|
|
||||||
@@ -62,128 +74,123 @@ Update the system-wide scan settings.
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scan_poll_interval_seconds": 30,
|
"key": "scan_poll_interval_seconds",
|
||||||
"auto_scan_enabled": true
|
"value": "30"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Fields**:
|
| Field | Type | Required | Description |
|
||||||
|
| ------- | ------ | -------- | ------------------------------- |
|
||||||
|
| `key` | string | Yes | Setting key (from the list) |
|
||||||
|
| `value` | string | Yes | New value, as a string |
|
||||||
|
|
||||||
- `scan_poll_interval_seconds` (integer, required): How often to poll for file changes in seconds
|
**Response**: **200 OK**
|
||||||
- Minimum: 1 (1 second)
|
|
||||||
- Maximum: 3600 (1 hour)
|
|
||||||
- Default: 60
|
|
||||||
- `auto_scan_enabled` (boolean, required): Whether auto-scanning is enabled system-wide
|
|
||||||
- Default: true
|
|
||||||
|
|
||||||
**Response**:
|
|
||||||
|
|
||||||
- **200 OK**: Settings updated successfully
|
|
||||||
- **400 Bad Request**: Invalid request parameters
|
|
||||||
- **401 Unauthorized**: Invalid or missing authentication
|
|
||||||
- **403 Forbidden**: User does not have admin role
|
|
||||||
- **500 Internal Server Error**: Server error
|
|
||||||
|
|
||||||
**Success Response Body**:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scan_poll_interval_seconds": 30,
|
"key": "scan_poll_interval_seconds",
|
||||||
"auto_scan_enabled": true,
|
"value": "30",
|
||||||
"message": "scan settings updated successfully"
|
"type": "int",
|
||||||
|
"min": "1",
|
||||||
|
"max": "3600",
|
||||||
|
"requires_restart": false,
|
||||||
|
"category": "scanner",
|
||||||
|
"group": "Scanning",
|
||||||
|
"description": "How often to scan all libraries (seconds)",
|
||||||
|
"is_default": false,
|
||||||
|
"reload_required": false,
|
||||||
|
"message": ""
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Error Response Body**:
|
- `reload_required: true` means the change takes effect only after a restart (e.g. rate limits, worker pool, lockout settings).
|
||||||
|
- Validation is type-aware: `int` values are checked against `min`/`max`, `bool` values must parse, `default_timezone` must be a valid IANA timezone via `time.LoadLocation`, and strings must be non-empty.
|
||||||
|
|
||||||
```json
|
**Errors**: `400` (unknown key, invalid value, out of range), `401`, `403`, `503` (settings registry not initialized).
|
||||||
{
|
|
||||||
"error": "error message"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Validation Rules**:
|
|
||||||
|
|
||||||
- `scan_poll_interval_seconds` must be between 1 and 3600 seconds (1 second to 1 hour)
|
|
||||||
- Both fields are required
|
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X PUT https://bookhoard.example.com/api/libraries/scan-settings \
|
curl -X PUT https://bookhoard.example.com/api/system/settings \
|
||||||
-H "Authorization: Bearer <admin_token>" \
|
-H "Authorization: Bearer <admin_token>" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{"key": "scan_poll_interval_seconds", "value": "30"}'
|
||||||
"scan_poll_interval_seconds": 30,
|
|
||||||
"auto_scan_enabled": true
|
|
||||||
}'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Behavior
|
## Setting Catalog
|
||||||
|
|
||||||
### Poll Interval
|
Current tunable settings by category:
|
||||||
|
|
||||||
The `scan_poll_interval_seconds` setting determines how often the system will poll library folders for file changes as a fallback to real-time file watching.
|
**Scanner** (`scanner`)
|
||||||
|
|
||||||
**Constraints**:
|
| Key | Default | Range | Restart | Description |
|
||||||
|
| ------------------------------ | ------- | -------- | ------- | ----------------------------------------- |
|
||||||
|
| `scan_poll_interval_seconds` | `60` | 1-3600 | No | How often to scan all libraries (seconds) |
|
||||||
|
| `auto_scan_enabled` | `true` | - | No | Whether auto-scanning is enabled |
|
||||||
|
|
||||||
- Minimum: 1 second
|
**General** (`general`)
|
||||||
- Maximum: 3600 seconds (1 hour)
|
|
||||||
- Default: 60 seconds
|
|
||||||
|
|
||||||
### Auto-Scan Toggle
|
| Key | Default | Restart | Description |
|
||||||
|
| ----------------- | ------- | ------- | ------------------------- |
|
||||||
|
| `default_timezone`| `UTC` | No | System default timezone |
|
||||||
|
|
||||||
The `auto_scan_enabled` setting acts as a master switch for automatic scanning:
|
**Security** (`security`)
|
||||||
|
|
||||||
- When `true`: File watching and polling fallback are active for all libraries
|
| Key | Default | Range | Restart | Description |
|
||||||
- When `false`: No automatic file monitoring occurs (manual scans still available)
|
| ---------------------------- | --------- | ------------ | ------- | ---------------------------------------------- |
|
||||||
|
| `session_duration_seconds` | `604800` | 300-31536000 | No | How long a login session stays valid |
|
||||||
|
| `password_min_length` | `8` | 1-128 | No | Minimum password length |
|
||||||
|
| `password_require_upper` | `true` | - | No | Require at least one uppercase letter |
|
||||||
|
| `password_require_lower` | `true` | - | No | Require at least one lowercase letter |
|
||||||
|
| `password_require_number` | `true` | - | No | Require at least one number |
|
||||||
|
| `password_require_special` | `true` | - | No | Require at least one special character |
|
||||||
|
| `auth_rate_limit_per_min` | `10` | 1-10000 | **Yes** | Global auth API rate limit (req/min) |
|
||||||
|
| `login_max_attempts` | `5` | 1-100 | **Yes** | Failed login attempts before lockout |
|
||||||
|
| `login_lockout_minutes` | `15` | 1-10080 | **Yes** | Lockout duration after failed logins |
|
||||||
|
|
||||||
### File Watching System
|
**API** (`api`)
|
||||||
|
|
||||||
The scan settings control the file watching system which consists of:
|
| Key | Default | Range | Restart | Description |
|
||||||
|
| ------------------------------- | ------- | --------- | ------- | ------------------------------------ |
|
||||||
|
| `opds_default_page_size` | `50` | 1-500 | No | Default OPDS page size |
|
||||||
|
| `opds_max_page_size` | `200` | 1-1000 | No | Maximum OPDS page size |
|
||||||
|
| `device_rate_sync_per_min` | `60` | 1-10000 | No | Device sync requests per minute |
|
||||||
|
| `device_rate_progress_per_min` | `120` | 1-10000 | No | Device progress requests per minute |
|
||||||
|
| `device_rate_metadata_per_min` | `30` | 1-10000 | No | Device metadata requests per minute |
|
||||||
|
|
||||||
1. **Real-time file watching**: Uses fsnotify to detect file changes immediately
|
**Sync** (`sync`)
|
||||||
2. **Polling fallback**: If file watching fails or is unavailable, polls folders at the configured interval
|
|
||||||
|
|
||||||
The system applies these settings to all configured libraries automatically on startup.
|
| Key | Default | Range | Restart | Description |
|
||||||
|
| ------------------------------- | ------- | -------- | ------- | -------------------------------------------------- |
|
||||||
|
| `annotation_tombstone_ttl_days` | `30` | 1-3650 | No | How long deleted annotations are kept before purge |
|
||||||
|
| `sync_queue_interval_seconds` | `5` | 1-3600 | **Yes** | How often the sync queue flushes |
|
||||||
|
| `sync_queue_batch_size` | `50` | 1-10000 | **Yes** | Max items processed per sync queue flush |
|
||||||
|
|
||||||
|
**Performance** (`performance`)
|
||||||
|
|
||||||
|
| Key | Default | Range | Restart | Description |
|
||||||
|
| ------------------------ | ------- | --------- | ------- | ------------------------------------------- |
|
||||||
|
| `conversion_cache_ttl_hours` | `24` | 1-720 | No | How long converted (KEPUB) files are cached |
|
||||||
|
| `worker_pool_size` | `3` | 1-100 | **Yes** | Number of background worker goroutines |
|
||||||
|
| `worker_queue_cap` | `100` | 1-10000 | **Yes** | Background worker job queue capacity |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Error Codes
|
## Legacy Scan Settings Routes
|
||||||
|
|
||||||
| Status Code | Error Description |
|
The older JSON routes still work for backward compatibility and now refresh the settings registry cache on write, but they are **superseded** by `GET/PUT /api/system/settings`:
|
||||||
| ----------- | ---------------------------------------------------------- |
|
|
||||||
| 400 | Invalid request parameters (e.g., frequency outside range) |
|
- `GET /api/libraries/scan-settings` — returns only `scan_poll_interval_seconds` and `auto_scan_enabled`
|
||||||
| 401 | Missing or invalid JWT token |
|
- `PUT /api/libraries/scan-settings` — accepts `{ "scan_poll_interval_seconds": int, "auto_scan_enabled": bool }`
|
||||||
| 403 | User lacks admin role |
|
|
||||||
| 500 | Internal server error (e.g., database connection issue) |
|
Both fields are backed by the same registry entries documented above.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Related Endpoints
|
## Related Endpoints
|
||||||
|
|
||||||
- `POST /api/libraries/{id}/scan` - Manually trigger a scan for a specific library (admin only)
|
- `GET/PUT /api/system/config` — raw key/value system configuration (see [System Config API](config.md))
|
||||||
- `GET /api/libraries` - List all libraries
|
- `POST /api/scanner/scan` — trigger a manual scan (see [Scanner API](../scanner/))
|
||||||
- `GET /api/libraries/{id}` - Get details for a specific library
|
- `GET /api/admin/hash-conflicts` — duplicates found during hashing (see [Hash Conflicts API](../admin/hash-conflicts.md))
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Migration Notes
|
|
||||||
|
|
||||||
This API has been updated to use a new polling-based scanning system. The following changes were made:
|
|
||||||
|
|
||||||
- **Changed**: `scan_frequency_minutes` renamed to `scan_poll_interval_seconds`
|
|
||||||
- **Changed**: Unit changed from minutes to seconds (15-1440 minutes → 1-3600 seconds)
|
|
||||||
- **Removed**: Old scheduler-based scanning system
|
|
||||||
- **Added**: Real-time file watching with polling fallback
|
|
||||||
- **Preserved**: API endpoint paths remain the same
|
|
||||||
|
|
||||||
The new system ensures that:
|
|
||||||
|
|
||||||
1. File changes are detected in real-time when possible (via fsnotify)
|
|
||||||
2. Polling fallback catches missed events at the configured interval
|
|
||||||
3. Settings apply to all libraries system-wide
|
|
||||||
4. Only administrators can modify scan settings
|
|
||||||
5. The `auto_scan_enabled` setting controls both file watching and polling
|
|
||||||
|
|||||||
Reference in New Issue
Block a user