Files
bookhoard/docs/developer/api/system/settings.md
T
john-okeefe 44a0f8c7a4 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 in 885f6d8 / 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
2026-08-20 14:40:45 -04:00

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: 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.

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 only scan_poll_interval_seconds and auto_scan_enabled
  • PUT /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.


  • 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)