The Book Dock directory inside the container was previously hardcoded to `/data/book-dock`. This adds support for the `BOOK_DOCK_PATH` environment variable, allowing users to customize the internal container directory where the Book Dock monitors for files. If the environment variable is not set, it defaults to the `book-dock` folder inside the configured app data path. This replaces the `BOOK_DROP_HOST_PATH` volume mapping in the compose file with a standard volume and environment variable approach.
Closes#178
* feat(docker): expose Book Dock folder as a configurable drop zone
Add support for an external book drop folder that users can bind-mount
into the container via the BOOK_DROP_HOST_PATH env var. Files copied or
moved into this folder are automatically picked up and ingested by the
existing Book Dock file watcher.
- docker-compose.yml: add BOOK_DROP_HOST_PATH volume override so the
book-dock path is separately bind-mountable
- .env.example: document BOOK_DROP_HOST_PATH with an example NAS path
- AppInfoResponse: add bookDockPath so the UI can show the
container-internal path admins need to bind-mount
- AppInfoService: compute and return bookDockPath from storage config
- BookDockSettings: display drop folder path with BOOK_DROP_HOST_PATH hint
- useAppInfo: expose bookDockPath ref from the app-info API response
- README: document the optional drop folder in the quickstart section
When BOOK_DROP_HOST_PATH is unset, the volume defaults to
./data/app/book-dock, preserving full backward compatibility.
No watcher code changes required - the watcher already watches
the correct container-internal path.
Closes#58
* fix(book-dock): resolve symlink paths so rescan stays idempotent
BookDockWatcherService and BookDockIngestService were building
bookDockPath with path.join(), which preserves symlinks. `@parcel/watcher`
resolves symlinks internally when reporting events (using realpath), so the
absolutePath values stored by watcher events and the paths computed by
walkAndIngest during rescan never matched. This caused findByAbsolutePath
to always return undefined on rescan, creating duplicate DB records for
every file already tracked via a watcher event.
Fix: both services now call `realpath(bookDockPath)` in
onApplicationBootstrap (after mkdir), updating the stored path to the
canonical real path that the watcher also uses. Rescan is now idempotent
regardless of symlinks in the data directory.
Verified by E2E test: 3 consecutive rescans produce zero new records.
- add local provider icon assets and a shared providerIconPath helper for metadata providers
- switch provider links in book details and quick view to use bundled SVG icons
- proxy external metadata cover URLs through /api/v1/books/cover/proxy for display while keeping same-origin/data/blob URLs untouched
- apply proxied display cover URLs in metadata diff/result UI and Book Dock surfaces
- keep raw provider cover URLs in metadata patches and add composable tests for proxy behavior
- add optional CSP_ALLOW_CLOUDFLARE_INSIGHTS env support and document it in server/root env examples and README
- wire conditional Cloudflare Insights script/connect sources into CSP directives
- remove pino HTTP customProps context injection to avoid duplicated context labels
- reduce file-write log noise by using debug level for write start and auto-skipped completions
- tune entity-manager duplicate scans by setting pg_trgm similarity_threshold per query/transaction to align with minSimilarity and prevent scan blowups
Handle existing upload folder paths without creating duplicate books, tolerate partial RAR 1.5 archive reads, and clean up related production defaults and dashboard type safety.
- resolve all 69 client type-checking errors for stricter TS compliance
- remove obsolete type-check baseline scripts and files
- overhaul project root with updated README.md and new DEVELOPMENT.md
- migrate to unified baseline migration strategy and cleanup docker configs
- remove redundant production and dev-specific shell scripts