Commit Graph

503 Commits

Author SHA1 Message Date
neon 02262e3b3f fix(books): update metadata and locks atomically
When a newly filled metadata field is locked before saving, the subsequent
save causes a 409 conflict because the field was locked but not yet saved.
This introduces a new endpoint and DTO to update both metadata and locks
simultaneously, resolving the conflict.

Closes #172
2026-05-31 15:48:01 +00:00
neon 7a1b0120b8 feat(series): add selectable cover modes for collapsed series cards
Allow readers to choose which representative series cover appears in collapsed grid view so browsing can prioritize first, latest, or first unread volumes.

Closes #160
2026-05-31 15:10:00 +00:00
neon 0b3a96cbe3 fix(cover): make placeholder palettes react to theme accent
Unify accent metadata in one client module to prevent hue and tone drift across theme picker, chart palettes, and cover placeholders.

Guard placeholder theme-store access when Pinia is unavailable so non-store mounts remain stable while preserving reactive updates when a store is active.
2026-05-31 06:35:42 +00:00
neon cc7cbb13a1 fix(library): increase reading threshold constraint max to 100
The database check constraint for the library reading threshold was previously enforcing a maximum value of 1, causing an internal server error when configuring a threshold greater than 1% via the UI. The constraint max has been increased to 100 to support percentage-based values and align with the mark_as_finished constraint.

Closes #142
2026-05-31 01:22:11 +00:00
Chris Mansell 26b3c8ba18 feat(settings): add adaptive cover display preferences (#169)
Allow users to choose how cover artwork is fitted so mixed aspect ratios render cleanly in cards, lists, carousels, and widgets.

Persist display preferences through shared types and user-preferences endpoints so these settings stay consistent across sessions and devices.

Closes #152
2026-05-30 18:57:29 -06:00
MohammadYusif c37f668bed fix: percent-encode credentials when building DATABASE_URL (#126) (#167)
When DATABASE_URL is not provided, entrypoint.sh assembled it by
interpolating POSTGRES_USER, POSTGRES_PASSWORD and POSTGRES_DB directly
into a postgres:// URL. Any reserved URL character in those values (for
example a '#', '/' or '?' in the password) produced an invalid URL, and
pg-connection-string's new URL() call then threw ERR_INVALID_URL,
preventing the container from starting.

Percent-encode the user, password and database components via
encodeURIComponent before building the URL so passwords containing
special characters work without manual escaping.

Co-authored-by: MohammadYusif <MohammadYusif@users.noreply.github.com>
2026-05-30 18:57:08 -06:00
neon 3f6f7163d8 fix(auth): allow https in csp img-src for oidc provider icons (#140)
The Content Security Policy was previously blocking external images,
preventing admin-configured OIDC provider icons from loading.
This allows https: images to be loaded while continuing to block
plain http: to maintain mixed-content protection.

Closes #131
2026-05-30 12:28:09 -06:00
neon a1fe471e83 feat(settings): add theme persistence across devices
Introduce a user-preferences module and database schema to sync theme
settings (theme, accent, radius, background, brightness) across devices.
Users can now enable theme sync to persist their customization choices.

Closes #146
2026-05-30 17:27:08 +00:00
Chris Mansell 100334773c feat(metadata): add bulk metadata edit dialog (#164)
Add a dialog to batch-edit metadata for multiple selected books.

Support add/remove/replace/clear modes for list fields, with clear as an explicit
frontend-only mode.

Fix scalar input border rendering, year field validation/coercion, tags replace
optimistic updates, and submit error handling.

Closes #150
2026-05-30 11:21:27 -06:00
neon 6ffce7d7c8 feat(books): add manual write-and-rename action in metadata editor
allow users to trigger file write-back and rename from the edit metadata tab as a single explicit action.

return write and rename outcomes with library setting flags so the UI can show clear result and warning states.

Closes #143
2026-05-30 05:16:33 +00:00
neon 9b50b0ebb7 fix(cover): retain audiobook square covers in discovery carousels
Align recommendation data and rendering with per-book media format semantics.
Expose audiobook state from recommendation queries and render audiobook cards as square while preserving portrait and spine treatment for non-audiobooks.

Closes #149
2026-05-30 03:58:49 +00:00
neon a1994a0b40 fix(cover): apply spine overlay to details tab covers
Keep details-view cover rendering consistent with global cover preferences, and preserve the no-spine behavior for audiobook entries.

Closes #148
2026-05-30 02:10:50 +00:00
neon 0ab342d80b fix(cover): disable spine overlay for audiobook covers
Respect audiobook presentation by forcing spine effects off for audio items.
Keep the selected spine mode unchanged for non-audiobook covers.

Ref #147
2026-05-30 02:03:42 +00:00
neon f096f55ca6 fix(server): sanitize book dock published year before finalize
Align Book Dock metadata validation with the database year constraint to prevent intermittent finalize failures from malformed extracted years.
Return a user-safe validation message when metadata constraints are hit.

Closes #144
2026-05-30 02:01:27 +00:00
neon 59511b0856 feat(client): add shift-click selection to book dock
Allow users to select a range of files in the book dock by holding the shift key while clicking checkboxes, matching standard multi-select behavior.

Closes #136
2026-05-29 04:57:12 +00:00
dependabot[bot] fc6d4fec83 chore(deps): bump the production-dependencies group with 12 updates (#139)
Bumps the production-dependencies group with 12 updates:

| Package | From | To |
| --- | --- | --- |
| [@tanstack/vue-virtual](https://github.com/TanStack/virtual/tree/HEAD/packages/vue-virtual) | `3.13.25` | `3.13.26` |
| [dompurify](https://github.com/cure53/DOMPurify) | `3.4.5` | `3.4.7` |
| [reka-ui](https://github.com/unovue/reka-ui) | `2.9.7` | `2.9.8` |
| [vue](https://github.com/vuejs/core) | `3.5.34` | `3.5.35` |
| [vue-router](https://github.com/vuejs/router) | `5.0.7` | `5.1.0` |
| [@nestjs/common](https://github.com/nestjs/nest/tree/HEAD/packages/common) | `11.1.23` | `11.1.24` |
| [@nestjs/core](https://github.com/nestjs/nest/tree/HEAD/packages/core) | `11.1.23` | `11.1.24` |
| [@nestjs/platform-fastify](https://github.com/nestjs/nest/tree/HEAD/packages/platform-fastify) | `11.1.23` | `11.1.24` |
| [@nestjs/platform-socket.io](https://github.com/nestjs/nest/tree/HEAD/packages/platform-socket.io) | `11.1.23` | `11.1.24` |
| [@nestjs/websockets](https://github.com/nestjs/nest/tree/HEAD/packages/websockets) | `11.1.23` | `11.1.24` |
| [mysql2](https://github.com/sidorares/node-mysql2) | `3.22.3` | `3.22.4` |
| [nodemailer](https://github.com/nodemailer/nodemailer) | `8.0.7` | `8.0.9` |


Updates `@tanstack/vue-virtual` from 3.13.25 to 3.13.26
- [Release notes](https://github.com/TanStack/virtual/releases)
- [Changelog](https://github.com/TanStack/virtual/blob/main/packages/vue-virtual/CHANGELOG.md)
- [Commits](https://github.com/TanStack/virtual/commits/@tanstack/vue-virtual@3.13.26/packages/vue-virtual)

Updates `dompurify` from 3.4.5 to 3.4.7
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.4.5...3.4.7)

Updates `reka-ui` from 2.9.7 to 2.9.8
- [Release notes](https://github.com/unovue/reka-ui/releases)
- [Commits](https://github.com/unovue/reka-ui/compare/v2.9.7...v2.9.8)

Updates `vue` from 3.5.34 to 3.5.35
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/compare/v3.5.34...v3.5.35)

Updates `vue-router` from 5.0.7 to 5.1.0
- [Release notes](https://github.com/vuejs/router/releases)
- [Commits](https://github.com/vuejs/router/compare/v5.0.7...v5.1.0)

Updates `@nestjs/common` from 11.1.23 to 11.1.24
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.24/packages/common)

Updates `@nestjs/core` from 11.1.23 to 11.1.24
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.24/packages/core)

Updates `@nestjs/platform-fastify` from 11.1.23 to 11.1.24
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.24/packages/platform-fastify)

Updates `@nestjs/platform-socket.io` from 11.1.23 to 11.1.24
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.24/packages/platform-socket.io)

Updates `@nestjs/websockets` from 11.1.23 to 11.1.24
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.24/packages/websockets)

Updates `mysql2` from 3.22.3 to 3.22.4
- [Release notes](https://github.com/sidorares/node-mysql2/releases)
- [Changelog](https://github.com/sidorares/node-mysql2/blob/master/Changelog.md)
- [Commits](https://github.com/sidorares/node-mysql2/compare/v3.22.3...v3.22.4)

Updates `nodemailer` from 8.0.7 to 8.0.9
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodemailer/nodemailer/compare/v8.0.7...v8.0.9)

---
updated-dependencies:
- dependency-name: "@tanstack/vue-virtual"
  dependency-version: 3.13.26
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: dompurify
  dependency-version: 3.4.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: reka-ui
  dependency-version: 2.9.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: vue
  dependency-version: 3.5.35
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: vue-router
  dependency-version: 5.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: "@nestjs/common"
  dependency-version: 11.1.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@nestjs/core"
  dependency-version: 11.1.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@nestjs/platform-fastify"
  dependency-version: 11.1.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@nestjs/platform-socket.io"
  dependency-version: 11.1.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@nestjs/websockets"
  dependency-version: 11.1.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: mysql2
  dependency-version: 3.22.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: nodemailer
  dependency-version: 8.0.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-28 21:36:32 -06:00
neon 0ce4dabc30 fix(settings): enable cross-platform path sanitization by default
Enable cross-platform path sanitization by default to prevent file and folder renaming failures
caused by invalid special characters or reserved names on various filesystems. Update the frontend
settings UI description to clarify the behavior of this setting, and update tests to reflect the
new default and verify correct sanitization behavior.

Closes #134
2026-05-29 03:34:56 +00:00
neon 48218b7cb1 fix(settings): restore per-library inherit toggle updates
Remove the \.stop modifier from the inherit toggle update handler so value changes emit correctly and per-library overrides can switch modes again.

Closes #130
2026-05-29 03:34:56 +00:00
neon 54814201b8 feat(metadata): add provider connection testing and token validation
Add UI and backend support for testing metadata provider credentials
before saving. Include parsing and validation for Bearer tokens,
display test results in the settings panel, and execute a test
connection specifically against the Hardcover provider.

Closes #127
2026-05-29 03:34:56 +00:00
dependabot[bot] 75ee8d495c chore(deps): bump the github-actions group with 3 updates (#138)
Bumps the github-actions group with 3 updates: [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action), [docker/login-action](https://github.com/docker/login-action) and [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action).


Updates `docker/setup-buildx-action` from 4.0.0 to 4.1.0
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd...d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5)

Updates `docker/login-action` from 4.1.0 to 4.2.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/4907a6ddec9925e35a0a9e82d7399ccc52663121...650006c6eb7dba73a995cc03b0b2d7f5ca915bee)

Updates `docker/setup-qemu-action` from 4.0.0 to 4.1.0
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/ce360397dd3f832beb865e1373c09c0e9f86d70a...06116385d9baf250c9f4dcb4858b16962ea869c3)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/login-action
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/setup-qemu-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-28 21:24:40 -06:00
Chris Mansell e659111e4e feat(library): add bulk rename tool and e2e coverage (#124)
* feat(library): add bulk rename based on file naming settings

Provides a way to rename all books in a library according to the user's
configured file naming template without requiring manual metadata edits.
Includes a streaming endpoint to report progress back to the frontend.

Closes #121

* test(library): add e2e tests for bulk file rename

Introduce a comprehensive E2E test suite for the bulk rename functionality to verify behavior across different library modes (book per file, book per folder) and handle edge cases like naming collisions or special characters.

Additionally fix a TypeScript compilation error in BulkRenameView.vue by replacing `replaceAll` with a regex-based `replace` for broader target compatibility.

---------

Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
2026-05-28 09:27:03 -06:00
neon 8ee6929f55 revert(docker): remove SSE4.2 startup hard-fail check
Revert 3f32d8e828 to restore startup on CPUs without SSE4.2 support.

Closes #129
2026-05-28 15:06:43 +00:00
neon bfb4d2d4b1 fix(settings): restore magic links admin tab access
Expose magic links as its own admin tab and route it directly in Admin settings.
Keep it superuser-only and cover tab visibility and routing behavior in tests.
2026-05-28 06:09:15 +00:00
neon 020e33db82 feat(reader): add no gaps infinite scroll mode for webtoons
Update the long-strip reading mode in the comic reader to remove gaps between pages and correctly apply fit modes for webtoon reading.

Closes #108
2026-05-28 05:50:54 +00:00
neon 465ed11aa9 fix(smart-scope): make icon picker responsive to viewport bounds
The icon picker panel was overflowing the viewport bottom boundary when there wasn't enough space, cutting off the search bar. Add dynamic max height calculation and visual viewport resize listeners. Also includes a style fix for the sidebar section header kebab buttons.

Closes #125
2026-05-28 05:25:25 +00:00
neon df20b6f8e6 fix(auth): tolerate refresh-token rotation races
Parallel refresh requests from a single client (multi-tab SPA, mobile tab restore)
tripped reuse-detection and logged users out every few hours. Track rotation
provenance via new rotated_at + replaced_by_token_hash columns and accept revoked-
token reuse only inside a configurable grace window with a chain that reaches a
live, non-logout link. Scope the rotate UPDATE with revoked_at IS NULL so a
concurrent logout or admin revoke fails the racing refresh instead of handing the
user a fresh access token.

Closes #120
2026-05-28 04:56:05 +00:00
neon 2161c9d1af feat(annotations): compute location strings and sort keys from CFI
Provide the ability to sort and display annotations by their physical location in the book. Previously, annotations and bookmarks could only be sorted chronologically, making it difficult to track reading progress or locate notes.

By parsing EpubCFI strings into numeric sort keys, the sidebar can now reliably order items by their position. This also introduces human-readable location labels and fallback states for missing or invalid CFIs. Foliate integration is enhanced to resolve chapter titles and reading fractions for better context.

Closes #119
2026-05-27 21:45:12 +00:00
neon 3f32d8e828 fix(docker): fail fast on CPUs that lack SSE4.2 support (#118)
On old hardware (e.g. AMD Turion/Phenom, Intel Core 2), sharp's musl binary
crashes with SIGILL during NestJS module init. Combined with bufferLogs: true
and restart: unless-stopped, this produces a silent infinite restart loop -
only the migration success message is ever visible.

Add check_cpu_sse42 to entrypoint.sh: greps /proc/cpuinfo for sse4_2, exits
with a clear error if absent, no-op when /proc/cpuinfo is unavailable. Also
add a System Requirements section to README documenting the SSE4.2 minimum.

Closes #116
2026-05-27 14:27:12 -06:00
neon 419f634e5c feat(auth): add opt-in private oidc issuer override (#113)
Allow self-hosted deployments to explicitly trust private/local OIDC issuer hosts while keeping production defaults locked down.

Keep SSRF protections unchanged outside OIDC issuer and discovery validation paths.

Closes #107
2026-05-27 14:26:57 -06:00
neon 3a72ece26d fix(settings): gate integration tabs by integration permissions
Prevent unauthorized users from seeing integrations they cannot use and keep settings routing consistent with API authorization behavior. Add hardcover_sync and enforce it server-side so tab visibility and endpoint access stay aligned.
2026-05-26 19:52:32 +00:00
neon 78b99d0b78 fix(settings): accept socket postgres urls in DATABASE_URL validation
Validate DATABASE_URL with pg's connection-string parser so unix-socket DSNs with empty authority hosts pass while malformed/non-postgres values are rejected.

Closes #106
2026-05-26 01:48:24 +00:00
neon 39bb872f7c fix(client): show actual achievement description when all tiers are complete instead of redundant text 2026-05-25 05:40:51 +00:00
neon 1be2abe36a fix(scanner): clamp precision-unsafe inodes to avoid lossy matching (#90)
* fix(scanner): clamp precision-unsafe inodes to avoid lossy matching

Clamp inode values above Number.MAX_SAFE_INTEGER to 0 before scanner, upload,
and file-event matching paths consume them.

Add regression tests for Unraid-style inodes so precision-unsafe values
cannot collapse file detection during scans.

Lower server coverage thresholds from 85 to 80 as requested for this branch.

Closes #84

* fix(scanner): reuse existing book for same-library folder renames

Keep the original book id when a folder path changes so scan does not create a duplicate entry with no files. Use inode first and hash fallback for precision-unsafe inode values while keeping book_per_file behavior unchanged.
2026-05-24 23:24:41 -06:00
neon 1479989f74 feat(settings): add cross-platform path sanitization option
Book titles and author names can contain characters that are invalid on Windows,
SMB/NFS shares, or cloud sync platforms (e.g., `:`, `?`, `*`, `"`). Without
sanitization these characters appear verbatim in generated file and folder names,
which causes failures on Windows filesystems, broken NFS/SMB mounts, and sync issues.

Add a toggleable app setting that, when enabled, sanitizes illegal filesystem
characters in all pattern-resolved paths (upload, rename, book-dock finalize, and
download). Each token value is sanitized before substitution: invalid chars are
replaced with `_`, trailing dots and spaces are stripped, and Windows reserved names
(CON, AUX, NUL, COM1-COM9, LPT1-LPT9) get a suffix to avoid conflicts. The setting
defaults to off to preserve existing behavior.

Closes #103
2026-05-25 05:17:17 +00:00
neon c481304e0d fix(settings): clarify koreader sync accuracy expectations
document cross-reader sync limitations in the KOReader settings panel.
set clear expectations for direction-specific accuracy so users understand why resume location can differ between KOReader and the web reader.
2026-05-25 04:23:53 +00:00
neon 7fe5b9133a fix(cover): prevent series badge clicks from opening reader
treat the series-position badge as a non-open interactive target and
exclude those clicks from card-open handling.

add regression tests for hover hit-testing and badge-click behavior.

type vitest mock functions in the series detail spec to satisfy
the repository pre-push lint checks.

Closes #99
2026-05-24 16:31:44 +00:00
neon 989c16313f fix(series): open add-to-collection sheet from book actions
Handle add-to-collection actions in the series detail view so the collection sheet opens with the selected book id. Add regression tests for grid and table actions plus sheet close state reset.

Closes #102
2026-05-24 16:13:25 +00:00
neon afeff2566d refactor(stats): extract caching logic to StatsCache
Extracts the in-memory caching logic previously duplicated across
UserStatisticsService and StatisticsService into a new shared
StatsCache class. This standardizes cache keys, improves invalidation
by scope (such as userId), and makes the dashboard widget and
statistics caching more robust.
2026-05-23 21:48:01 +00:00
neon de9d3a9d86 fix(book): resolve series collapse query issues
The previous SQL query used a LATERAL join and complex aggregations that caused series collapsing to fail. This refactors the query to use a unified base_rows CTE and explicit window functions for fetching series covers, ensuring that series are correctly grouped and displayed.

Closes #87
2026-05-23 04:51:17 +00:00
neon d43b97dc85 fix(server): check for app updates dynamically with 10-minute cache
The backend previously only checked for new releases from GitHub
during application bootstrap. If the server stayed up for a long time,
the UI would never be notified of new releases.

The AppInfoService now re-checks GitHub when the frontend requests
app info, using a 10-minute cache TTL to balance freshness with
API rate limits.
2026-05-23 02:39:53 +00:00
neon 738a8709c4 ci: fetch github usernames via API for release notes
The previous hardcoded AUTHOR_MAP was incomplete and caused missing authors
in the generated release notes. The config now attempts to fetch actual
GitHub usernames associated with commit SHAs using the GitHub API,
falling back to local git log author names if the API request fails.
2026-05-23 02:37:22 +00:00
neon f651039535 build: remove legacy release config and fix hash-based attribution
Use a single semantic-release config to avoid diverging behavior, and update the release notes context logic to map authors with full commit hashes and stable issue URLs.
2026-05-23 01:49:45 +00:00
neon 3e837c4fb9 fix(opds): stable sort tiebreaker, unique feed IDs, remove dead code (#94)
Add books.id ASC tiebreaker to all 7 OPDS_SORT_MAP sort orders so
pagination is deterministic even when books share identical addedAt
timestamps (e.g. after a bulk library scan). Without a tiebreaker,
PostgreSQL returns equal-valued rows in an undefined order, causing
books to appear on multiple pages or not at all.

Make catalog feed IDs context-specific: filtered views (by library,
collection, smartScope, author, series, or search query) now produce
distinct URNs instead of all sharing urn:bookorbit:catalog. This
aligns with the OPDS spec requirement that <id> uniquely identify
the logical feed.

Remove the dead idQuery.$dynamic() block from paginatedBookQuery
that was built and conditionally mutated but never awaited.

Closes #93
2026-05-22 19:11:54 -06:00
neon 45135fa157 feat(collections): allow removing books from collections in details
support toggling membership in the collection sheet so users can remove books without leaving the details and quick-view flow.

cover add/remove paths plus access edge cases with frontend and backend tests.

Closes #85
2026-05-23 00:15:17 +00:00
neon 1f77d11701 fix(email): fix recipient loading when send dialog opens (#92)
Run recipient fetch on initial open state so dialogs mounted with open=true load data immediately. Add dialog and recipient composable unit tests to lock in the regression behavior and error paths.

Closes #89
2026-05-22 16:48:49 -06:00
neon 513dfa21a7 feat(client): add docs and github star actions to app header
improve header discoverability with quick access to documentation and
community support actions. keep the github prompt in a dismissible
popover to avoid adding noise to the main navigation.
2026-05-22 17:10:22 +00:00
Chris Mansell 956a7a5e9a feat(users): add per-user tag/genre content restrictions (#83)
* 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
2026-05-22 11:01:11 -06:00
neon a3a4edfc0b fix: align tiered achievement copy with current tiers
Use each group's displayed tier description instead of the next tier description so titles and copy stay consistent across all tiered cards. Refresh achievement seed names for books, pages, hours, long-book, and library ladders, and adjust books_finished_3 to a 35-book threshold to match the new progression.
2026-05-22 07:07:40 +00:00
neon 7f488ac673 feat(authors): add manual author image upload and removal
Enable author image upload and removal from the author detail edit panel.
Persist author photos with generated thumbnails and enforce server-side validation plus access-scoped API routes.
Cover the new controller and service behavior with author module tests.
2026-05-22 06:04:07 +00:00
dependabot[bot] b141af2bf3 chore(deps): bump js-cookie from 3.0.5 to 3.0.7 (#82)
Bumps [js-cookie](https://github.com/js-cookie/js-cookie) from 3.0.5 to 3.0.7.
- [Release notes](https://github.com/js-cookie/js-cookie/releases)
- [Commits](https://github.com/js-cookie/js-cookie/compare/v3.0.5...v3.0.7)

---
updated-dependencies:
- dependency-name: js-cookie
  dependency-version: 3.0.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-21 22:56:45 -06:00