Add a Style setting beside mode, accent, radius and background. Nostalgia restyles the app through
tokens only (neutral surface palettes, system type, flat shell, top glow) and pins background,
opacity and brightness. Add a top glow reach slider for both styles. Tidy the theme layer first:
charts read live tokens, bare `rounded` follows the radius scale, one shared sign-in toolbar.
Also carries the settings page header redesign.
Require an enabled OIDC-linked superuser before disabling password flows. Track session authentication methods and fail closed across the API, web client, WebSockets, and administrative mutations.
Closes#1002
Let users request books, route approvals, search configured sources, and import fulfilled releases through the Book Dock. Include scoped permissions, automation, download-client integrations, plugin support, requester visibility, and one consolidated schema migration.
Closes#248
Ref #1115
Expose promotion and demotion to existing superusers while keeping shared and self targets blocked. Serialize role lifecycle changes, preserve one active superuser, and invalidate stale credentials.
Closes#1208
Rebuilds the users roster, metadata field rules, file naming and metadata
score panels, and replaces the libraries list with an expandable ledger.
Libraries now batch their counts and last scan into one request instead of a
per-library fan-out, and surface scan history from scan_jobs on demand.
Wire the existing allow_registration setting to an admin toggle in the
Users tab and a public /register page, so the documented self-registration
flow is reachable from the UI instead of the API alone. Expose the flag on
the public setup-status endpoint the router guard already calls, so the
sign-in page can offer sign-up without an extra request.
Harden the newly public path: return a conflict instead of a 500 when
concurrent signups race the unique index, sanitize the logged username,
and reject control, zero-width, and text-direction characters in the
username and display name so a new account cannot impersonate another in
the user list or audit log.
Closes#952
The lockout was checked before the password was verified, so a correct password on a locked
account returned the same generic invalid-credentials error as a wrong one. Users had no way to
tell the two apart, and the natural response was to keep retrying a password that was already
right.
Completing a password reset did not clear the lock either, so the one recovery path the UI
advertises appeared to fail for up to fifteen minutes after a successful reset.
Verify the password first and report the lockout, with the remaining wait, only when the supplied
password was correct. Someone guessing wrong passwords still gets the generic failure, so account
existence is not leaked. Clear the lock whenever a password is reset or changed, and give admins
an explicit unlock action for the case where waiting is not acceptable.
Rework the app shell around a customizable sidebar: reorderable sections, sidebar zones, entity
popovers, and per-user preference persistence, backed by a dedicated browse counts endpoint so
entity totals stay cheap on large libraries.
Redesign the file naming settings with pattern fields, a token helper sheet, and a debounced live
preview. Rebuild the admin users table with server-side pagination, search, and filter DTOs, status
pills, confirmation dialogs, and magic link actions. Group notification preferences by category and
refine the account and privacy settings layouts.
Update theme tokens, icon references, and template event handler bindings across client features for
consistency, extend all locale catalogs, and add unit coverage for the new composables, components,
and server modules.
Replace pipe-delimited Vue I18n plural messages with ICU MessageFormat syntax across all locale catalogs and Vue components. Configure custom message formatting and validation to enforce ICU syntax and argument parity.
Closes#792
* feat(i18n): add vue-i18n foundation with language switcher and Dutch locale
Introduce multi-language support for the client using vue-i18n and
@intlify/unplugin-vue-i18n. Locale is detected from a stored preference
or the browser language and persisted client-first, with optional server
sync riding the existing theme-sync mechanism (new locale category on the
generic user_preferences store, no migration needed).
Adds a language selector in Appearance > Behavior settings and seeds
en/nl message catalogs. Extraction of existing hardcoded strings follows
in subsequent commits.
* feat(i18n): add full en/nl message catalogs and test/build wiring
Populate the English and Dutch message catalogs (~4300 keys) covering the
whole UI, register a vitest setup that installs vue-i18n globally so
component tests resolve real messages, and allow inline HTML in messages
(strictMessage/escapeHtml off) for notes rendered via v-html / <i18n-t>.
* feat(i18n): localize settings and book UI strings
Replace hardcoded strings with t() calls across the settings and book
feature areas (including book detail, table, metadata edit, reading log,
highlights). Label collections captured at setup are wrapped in computed()
so they react to locale changes.
* feat(i18n): localize remaining feature UI strings
Replace hardcoded strings with t() across reader, email, library, tools,
migration, dashboard, auth, hardcover, author, series, book-dock,
book-metadata-fetch, annotations, admin, statistics, collection,
smart-scope, audit, whats-new, achievements, notifications, custom-icons,
scanner and metadata-score. Reactive label maps use computed().
* feat(i18n): localize shared components and view wrappers
Replace hardcoded strings with t() across shared components (app header,
sidebar, view header, pickers, selection bar) and top-level views.
* feat(i18n): localize settings tab bars and browser page titles
Make settings tab labels reactive via t() in the consuming components and
slim the *-tabs.ts helpers to ids/order/permission only. Route the browser
page titles in the router through the app i18n instance so document.title
follows the active locale. Adds settings.<area>.tabs.* and titles.* keys.
* feat(i18n): localize KOReader hash-linking and reader sidebar pin
Localize the strings from the KOReader manual hash-linking feature and the
reader sidebar pin/close controls that were merged from main during the
rebase, adding the corresponding en/nl keys.
* feat(i18n): localize upstream features merged during rebase onto main
Add en/nl catalog keys for the new upstream functionality pulled in by the
rebase (Kobo activity log, KOReader dismiss/remove-device and hash-link
modal, default library access, upload-size settings) and update a few
existing keys whose wording changed upstream (dynamic upload-size hints,
write-and-rename phrasing).
* feat(i18n): switch language picker to a dropdown
Replace the segmented language buttons with a native select, which scales
better as more locales are added.
* feat(i18n): add German and Slovenian translations
Register de and sl in the supported locales and ship full de.json and
sl.json catalogs (4616 keys each, structural parity with en.json).
* fix(client): harden locale switching and translation coverage
Keep locale catalogs structurally aligned, localize rebased UI changes, and use locale-aware formatting. Move language selection into the header, persist authenticated preferences, and prevent stale locale loads from winning.
---------
Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
Add configuration settings and backend support to define default library access permissions for newly created users. Newly registered users automatically receive these default library access permissions upon creation. Also align current users page controls and magic link options in the admin tab settings UI, adding styled callout cards for empty states.
Closes#486
* feat(users): tag/genre content filters for per-user access control
Add granular per-user content filtering by tags and genres, allowing admins to set include/exclude filter rules that are enforced across all book-serving surfaces.
- Implement DB schema, repository, and SQL helpers for content filters
- Wire enforcement across core domains (Books, Collections, OPDS, Kobo sync)
- Add REST endpoints for managing filter rules
- Redesign UserFormDrawer to support configuring content restrictions
- Add read-only Restrictions tab in account settings and user list badges
- Add comprehensive unit tests and fix existing fixtures
Closes#68
* test(client): update account tab expectations for restrictions
Reduce the settings navigation bar from 17 flat tabs to 10 by grouping
related settings into subtab containers, following the existing ?tab=
query-param pattern used by Reader and Metadata.
New groups:
- Integrations (/settings/integrations): Kobo, KOReader, Hardcover
- Admin (/settings/admin): Users, OIDC/SSO (permission-filtered)
- System (/settings/system): File Naming, Book Dock, Maintenance, Audit Log (permission-filtered)
- Account (/settings/account): Profile, Notifications (merged from standalone tabs)
All old routes redirect to their new grouped equivalents for backward
compatibility. Admin and System containers filter available tabs based on
user permissions. Demo-restricted accounts hide the Notifications tab.
New files:
- IntegrationsAllSettings.vue, AdminAllSettings.vue, SystemAllSettings.vue, AccountAllSettings.vue
- lib/integrations-tabs.ts, lib/admin-tabs.ts, lib/system-tabs.ts, lib/account-tabs.ts
- Unit tests for all new containers and tab-lib files (SettingsHeader included)
Closes#55
- improve responsive layouts and controls across dashboard, home, lens, collection, authors, and book detail surfaces
- modernize settings and metadata provider UIs, including the floating dashboard settings action and cleaner section composition
- add synced or per-view cover sizing and spacing behavior, plus expanded mobile filter and sort control patterns
- extend backend filtering with library rules and increase hardcover ID limits across schema, DTO validation, and migration metadata
- add tooltips to all header icons (search, upload, appearance, settings, theme toggle, sidebar trigger)
- fix appearance popover by moving Tooltip outside Popover
- add POST /api/books/export endpoint to zip and download books
- add POST /api/books/bulk-refresh-metadata and bulk-re-extract-cover endpoints
- add BulkBookIdsDto and ExportBooksDto
- add archiver dependency for zip streaming
- update theme CSS variables and component styles across client
- full email provider management (SMTP, test connection, share, default)
- recipient and recipient group management
- email templates with variable interpolation and system default
- user email preferences (provider, recipient, template defaults)
- send book via email from book list and cover card
- send log with pagination, resend on failure, delete entries
- admin email relay settings (SMTP relay, domain allow/blocklist)
- partial unique index to prevent duplicate system templates
- fix load-more pagination to append rather than replace entries
- add URI versioning: global prefix changed to api/v1, all frontend call sites updated
- add AbortSignal.timeout to all outbound fetch calls (10s API, 15s scrapers)
- add X-Request-Id response header and requestId field in error payloads
- add response compression via @fastify/compress (gzip + brotli)
- add security headers via @fastify/helmet with CSP for the Vite SPA
- tune pg pool: max 20, idle/connection/statement timeouts on app and migration pools
- add GET /api/v1/health endpoint via @nestjs/terminus with DB connectivity check