Replaced the 8 US-centric timezone options with 24 entries covering
every populated UTC offset worldwide (UTC-10 through UTC+12). Each
option is labeled by regional name with UTC offset in parentheses,
e.g. 'Central European (UTC+1/+2)'. DST-shifting zones show both
standard and daylight offsets.
Covers: Hawaii, Alaska, Pacific, Mountain, Mountain-no DST, Central,
Eastern, Brasilia, British, Central European, Eastern European,
Moscow, Iran, Gulf, Pakistan, India, Bangladesh, Indochina, China,
Japan/Korea, Australian Central, Australian Eastern, New Zealand.
Backend already validates all IANA zones via time.LoadLocation(), so
users with uncommon zones can still set them via the API.
Updated in three locations:
- templates/profile_form.templ (user profile dropdown)
- templates/admin_settings.templ (admin settings dropdown)
- internal/handlers/sidecar.go (HTMX save response HTML)
The admin settings timezone dropdown was incomplete: it had no
pre-selection of the current value, was missing consistent styling,
and the form submission did not persist timezone changes.
Changes:
- frontend.go: load default_timezone from system_settings into the
systemConfig map passed to the template
- admin_settings.templ: match card styling used by the Base URL
section; pre-select current timezone with selected?= attribute
- sidecar.go: handle default_timezone in UpdateSystemConfiguration
by writing to system_settings table instead of system_config;
update HTMX response to include timezone section with current value
- Add selectedAttr() helper for HTMX HTML string response
Replace direct error equality checks (err == pgx.ErrNoRows, err != http.ErrServerClosed)
with the idiomatic errors.Is() function throughout handlers, services, middleware, and app
startup. This correctly handles wrapped error chains.
Also replace a raw type assertion (*HTTPError) with errors.AsType[*HTTPError]() in the
error handler middleware for consistency.
Additionally, rename shadowed variables for clarity:
- sidecar.go: config -> sidecarConfig, systemConfig (shadowed package-level vars)
- media_scanner.go: uuid -> uuidString (shadowed the uuid package import)
Refactor configuration to use one source of truth for base URL
- Add GetBaseURL() to config package: queries system_config table first,
falls back to BASE_URL env var
- Update SidecarHandler to accept config and use single base_url
- Compute opds/api paths from base_url instead of storing separately:
- OPDS: base_url + /opds
- API: base_url + /api
- Device Sync: base_url + /api/sync
- Simplify OPDSHandler.getBaseURLs() to compute opds path
- Remove need for separate opds_base_url and api_base_url columns
Previously the system stored three separate URL config values that were
usually the same domain with different paths. Now store only base_url
and compute the paths, eliminating configuration redundancy.
Changes:
- Update comments: "Bookmann UUID" → "Bookhoard UUID"
- Rename sidecar struct field: Bookmann → Bookhoard
- Update type names: SidecarBookmannConfig → SidecarBookhoardConfig
- Fix test database name in queue_test.go
- Fix uppercase env var examples in KOBO_SETUP.md
Internal Go variable names (BookmannUuid, bookmannUUID) left unchanged
as they're implementation details that don't affect functionality.
Part of project rename to Bookhoard.
- Add OPDS handler for device catalog and book downloads
- Add collections handler for collection CRUD
- Add book matching service for cross-device book linking
- Add sidecar handler for Kobo metadata sync
- Add sync handler for device synchronization