docs(admin): settings page — every knob, what it does, and its range

The ninth page and the core of the owner's admin-docs brief: all 29
registry settings plus Base URL, documented setting-by-setting to the
admin tier — key, type, default, valid range, live-vs-restart, and
prose for what it does and what it means when that's confusing
(extractor-version as the gradual backfill lever vs. force rescan;
password rules apply at next set, never retroactively; tombstone TTL
as offline-device protection; rate limits as throttling behavior;
worker pool sizing honesty for small servers). Grouped exactly like
the page renders them, with the three save paths explained up front.
Ranges/defaults/flags from SettingDefaults; exclusion of the three
dedicated-UI keys from the tunables verified in the page handler.
Backfills the Settings links into dashboard.md and users.md now that
the target exists. Glossary gains Save Settings, Save Scan Settings,
both Tunable bucket headings, and Default Timezone.
This commit is contained in:
John O'Keefe committed 2026-11-02 14:16:04 -05:00
1 parent 39b0ab03fe
commit 607e5a1708
4 files changed
+258 -4

No files matched your search

+3 -3
View File
@@ -29,11 +29,11 @@ user can see.
The **File Watcher** card shows how many libraries are currently under
live watch for file changes. The watcher exists when **Auto-Scan** is
enabled on the Settings page (Settings → Scanning); the number updates on
page load.
enabled on the Settings page; the number updates on page load.
- Watching **0** libraries usually means auto-scan is off — turn it on in
Settings → Scanning, and the watcher arms on the next server start.
[Settings](settings.md) → Scanning, and the watcher arms on the next
server start.
- Watched libraries get shallow scans as files change, plus a periodic
poll on the scan interval — see [Scanning](scanning.md) for exactly what
those do.
+234
View File
@@ -0,0 +1,234 @@
<!-- Ground truth: templates/admin_settings.templ (page structure, save
buttons, live/restart buckets), internal/database/settings_registry.go
(SettingDefaults: keys, types, defaults, min/max, restart flags,
groups — the source of truth), internal/handlers/system_settings.go
(ApplySetting validates type+bounds then reloads; UpdateScanSettings
validates 1-3600), internal/router/frontend.go (settings page handler,
dedicatedUI exclusion list). Re-verify against these when settings
change — a new key lands in SettingDefaults AND schema.sql AND here. -->
# System Settings
The Settings page is every server-wide knob in one place. Each setting
below lists its **key** (the name shown on the page and stored in the
database), its **default**, its **valid range**, and whether it applies
live or needs a restart.
## How saving works
The page has three separate save paths, each with its own button:
- **Save Settings** (top card) — commits the Base URL and Default
Timezone together.
- **Save Scan Settings** — commits the two scanning controls.
- A per-row **Save** for each tunable setting — you change one value and
save exactly that one.
Live tunables apply immediately. The restart bucket saves your value
right away but only takes effect the next time the server restarts — the
page marks that bucket in amber so it can't be missed. Invalid values are
refused with an error; nothing silently clamps.
---
## Base URL
**base_url** — string, no default. The public URL of your Bookhoard
instance (e.g. `https://books.example.com`). This is the address Bookhoard
hands out to devices and OPDS clients — device sync, OPDS, and API
endpoint references are built from it — so it must be the URL your other
machines can actually reach, not `localhost`. The **URL Paths** card
underneath shows the three addresses derived from it (`/opds`, `/api`,
`/api/sync`) as a sanity check.
## System Defaults
**default_timezone** — string, default `UTC`. The timezone used for any
user who hasn't picked their own (each user's profile can override it).
This governs how the server renders dates and times for that user —
history, stats day boundaries, timestamps. The dropdown offers a fixed
list of zones.
## Scanning
Two of these live in their own card with **Save Scan Settings**; the last
two appear among the Live tunables under a "Scanning" heading. All four
are documented together here.
**auto_scan_enabled** — bool, default on. **Auto-Scan** in the UI. The
system-wide switch for automatic scanning: when on, a filesystem watcher
fires scans as files change, a periodic poll runs on the interval below,
and a shallow scan runs at startup. When off, libraries only change when
you scan them by hand. See [Scanning](scanning.md) for shallow vs. force.
**scan_poll_interval_seconds** — int, default `60`, range 1–3600.
**Scan Interval (seconds)** in the UI. How often the automatic poll
re-checks every library for changes. Lower is more responsive, higher is
less background work; every tick is a shallow scan, so unchanged files
cost almost nothing.
**auto_playlist_collections** — bool, default on. Live tunable. When a
book's sidecar metadata marks its series as a *reading order*, Bookhoard
automatically creates a collection that gathers the series in reading
order. Turn it off to stop creating these during future scans (existing
collections stay).
**scan_extractor_version** — int, default `1`, range 1–1000000. Live
tunable. The parser version stamped on each book's scan manifest. This is
the gradual backfill lever: raise it after a scanner improvement, and
books scanned under the older parser get re-extracted a bounded batch per
scan until all are caught up — no manual force rescan required. Leave it
alone unless you know a parser change shipped; don't set it far ahead of
the real version.
## Session
**session_duration_seconds** — int, default `604800` (7 days), range 300
(5 minutes)–31536000 (1 year). How long a login session stays valid.
Shorter is safer for shared machines; longer means fewer re-logins on
personal devices.
## Password Quality
Five settings that together define every new password — set at
registration, created by an admin, or changed by a user. Existing
passwords are never retroactively invalidated; the rules apply when a
password is next set.
**password_min_length** — int, default `8`, range 1–128. Minimum
character count.
**password_require_upper** — bool, default on. At least one uppercase
letter (A-Z).
**password_require_lower** — bool, default on. At least one lowercase
letter (a-z).
**password_require_number** — bool, default on. At least one digit (0-9).
**password_require_special** — bool, default on. At least one special
character.
The Users page's create form and the change-password form build their
live requirement checklists from these exact values.
## Public Registration
**registration_enabled** — bool, default on. Whether visitors can create
their own accounts from the sign-up page. Off, the instance is
invite-by-admin: accounts are created only from the
[Users](users.md) page (admins can always create accounts).
## OPDS Catalog
Page-size controls for the OPDS catalog (what apps like KOReader use to
browse your library over the network).
**opds_default_page_size** — int, default `50`, range 1–500. How many
entries a catalog page contains when the client doesn't ask for a
specific size.
**opds_max_page_size** — int, default `200`, range 1–1000. The ceiling
on what a client may request — a protection against one app asking for
enormous pages.
## Device Rate Limits
Per-device request ceilings, per minute, by kind of request. These
protect the server from a misbehaving or runaway device; a device that
hits its limit is throttled until the minute rolls over. Defaults are
sized for normal reading — raise them for very large libraries whose
initial device sync needs more headroom.
**device_rate_sync_per_min** — int, default `60`, range 1–10000. Sync
requests per minute (annotations, bookmarks, reading-state sync).
**device_rate_progress_per_min** — int, default `120`, range 1–10000.
Progress updates per minute (position saves as you read).
**device_rate_metadata_per_min** — int, default `30`, range 1–10000.
Metadata requests per minute.
## Annotation Retention
**annotation_tombstone_ttl_days** — int, default `30`, range 1–3650.
When an annotation (highlight, note, bookmark) is deleted, it isn't
destroyed instantly — a tombstone records the deletion so every other
device learns about it on their next sync. After this many days the
tombstone is purged for good. Longer is safer if some of your devices
stay offline for weeks; shorter reclaims rows sooner.
## Conversion Cache
**conversion_cache_ttl_hours** — int, default `24`, range 1–720. How
long converted files (Kobo-optimized KEPUB, for example) are kept cached
after conversion. Longer saves repeat conversion work at the cost of
disk; the conversion is regenerated when the cache entry expires.
## Auth Rate Limiting
*Restart required.*
**auth_rate_limit_per_min** — int, default `10`, range 1–10000. Global
cap on authentication requests per minute — the brute-force damper on
the login endpoints, server-wide. Raise it only if legitimate logins are
being throttled (many users behind one NAT, for example).
## Login Lockout
*Restart required.* Two settings that work as a pair: after
**login_max_attempts** consecutive failed attempts, that account waits
**login_lockout_minutes** before accepting more tries.
**login_max_attempts** — int, default `5`, range 1–100.
**login_lockout_minutes** — int, default `15`, range 1–10080 (up to one
week).
## Sync Queue
*Restart required.* Device-originated sync changes flow through a
background queue instead of being written the instant they arrive.
**sync_queue_interval_seconds** — int, default `5`, range 1–3600. How
often the queue flushes.
**sync_queue_batch_size** — int, default `50`, range 1–10000. The
maximum number of queued items processed per flush.
## Worker Pool
*Restart required.* Background jobs — scans, sync-queue flushes, and
other async work — run on a fixed pool of workers.
**worker_pool_size** — int, default `3`, range 1–100. How many jobs run
concurrently. More workers chew through queued work faster at the cost
of CPU and database load; on a small home server, more is not better.
**worker_queue_cap** — int, default `100`, range 1–10000. How many jobs
may wait in line when every worker is busy. Work offered beyond the cap
is refused rather than queued — a large force rescan of many libraries
wants headroom here.
## Podcasts
How often feeds are checked and how downloads behave server-wide.
**podcast_poll_interval_seconds** — int, default `3600` (one hour),
range 300 (5 minutes)–604800 (one week). How often Bookhoard checks
feeds for new episodes. Feeds marked *complete* (podcasts that have
ended) back off instead of being checked hourly forever.
**podcast_download_concurrency** — int, default `4`, range 1–16. Episode
downloads in flight server-wide; fair-share scheduling spreads them
across feeds so one feed can't hog the slots.
**podcast_download_speed_mbps** — float, default `0` (unlimited), range
0–10000. A shared bandwidth cap, in megabits per second, across all
podcast downloads — useful when the server's connection is also serving
readers.
## About
The version of Bookhoard this server is running. Worth checking before
filing a problem — and after an update, to confirm the new build landed.
+1 -1
View File
@@ -16,7 +16,7 @@ flow.
**+ Create User** opens the creation form (it stays hidden until clicked,
so the page doesn't shout account creation at you — and so admins can
still create accounts even when public self-registration is switched off
on the Settings page).
in [Settings](settings.md) → Public Registration).
Fields: **Username** (3–50 characters), **Email**, **Password** plus a
confirm, optional **First name** / **Last name**, and a **Role** of User
+20
View File
@@ -308,6 +308,26 @@ label: Edit User Profile
where: Admin → Users → a user card → Edit
does: The admin edit modal — profile fields, role, and Change Password without requiring the user's current password.
label: Save Settings
where: Admin → Settings → top card
does: Commits the Base URL and Default Timezone together.
label: Save Scan Settings
where: Admin → Settings → Scanning card
does: Commits Auto-Scan and the Scan Interval.
label: Tunable Settings — Live
where: Admin → Settings → section heading
does: Settings that apply immediately on save, grouped by area.
label: Tunable Settings — Restart Required
where: Admin → Settings → section heading
does: Settings whose saves take effect only after the server restarts; the bucket is marked in amber.
label: Default Timezone
where: Admin → Settings → System Defaults card
does: The timezone used for any user who hasn't chosen their own; governs how dates and times render for them.
label: Resume rewind
where: audio player → player settings; profile settings
does: Rewinds playback a configured few seconds when you resume.