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
8.5 KiB
System Settings API
Overview
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/system
Authentication: Admin JWT token required
Content-Type: application/json
Endpoints
List All Settings
Retrieve every known tunable setting with its current value and metadata.
Endpoint: GET /api/system/settings
Authentication: Admin role required
Response: 200 OK
[
{
"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
}
]
Entry fields:
| Field | Type | Description |
|---|---|---|
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:
curl -X GET https://bookhoard.example.com/api/system/settings \
-H "Authorization: Bearer <admin_token>"
Update a Setting
Validate, persist, and reload a single setting.
Endpoint: PUT /api/system/settings
Authentication: Admin role required
Request Body:
{
"key": "scan_poll_interval_seconds",
"value": "30"
}
| Field | Type | Required | Description |
|---|---|---|---|
key |
string | Yes | Setting key (from the list) |
value |
string | Yes | New value, as a string |
Response: 200 OK
{
"key": "scan_poll_interval_seconds",
"value": "30",
"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": ""
}
reload_required: truemeans the change takes effect only after a restart (e.g. rate limits, worker pool, lockout settings).- Validation is type-aware:
intvalues are checked againstmin/max,boolvalues must parse,default_timezonemust be a valid IANA timezone viatime.LoadLocation, and strings must be non-empty.
Errors: 400 (unknown key, invalid value, out of range), 401, 403, 503 (settings registry not initialized).
Example:
curl -X PUT https://bookhoard.example.com/api/system/settings \
-H "Authorization: Bearer <admin_token>" \
-H "Content-Type: application/json" \
-d '{"key": "scan_poll_interval_seconds", "value": "30"}'
Setting Catalog
Current tunable settings by category:
Scanner (scanner)
| 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 |
General (general)
| Key | Default | Restart | Description |
|---|---|---|---|
default_timezone |
UTC |
No | System default timezone |
Security (security)
| Key | Default | Range | Restart | Description |
|---|---|---|---|---|
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 |
API (api)
| 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 |
Sync (sync)
| 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 |
Legacy Scan Settings Routes
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:
GET /api/libraries/scan-settings— returns onlyscan_poll_interval_secondsandauto_scan_enabledPUT /api/libraries/scan-settings— accepts{ "scan_poll_interval_seconds": int, "auto_scan_enabled": bool }
Both fields are backed by the same registry entries documented above.
Related Endpoints
GET/PUT /api/system/config— raw key/value system configuration (see System Config API)POST /api/scanner/scan— trigger a manual scan (see Scanner API)GET /api/admin/hash-conflicts— duplicates found during hashing (see Hash Conflicts API)