mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
0b9027c275
* 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.
BookOrbit - Client
Vue 3 SPA built with Vite and Tailwind CSS v4.
Running
From the repo root: pnpm dev (starts both server and client).
Client only: pnpm dev (from this directory). Runs at http://localhost:5173.
The Vite dev server proxies /api and /socket.io requests to the backend at localhost:3000.
IDE setup
- VS Code: Install the Vue (Official) extension. Disable Vetur if installed.
- WebStorm / IntelliJ: Vue support is built in. Enable TypeScript service for
.vuefiles. - Browser: Install Vue.js devtools and enable Custom Object Formatters in DevTools settings.
Project layout
src/
├── features/ Feature modules (one folder per domain)
│ ├── auth/ Login, registration, password reset
│ ├── book/ Book detail, covers, metadata
│ ├── library/ Library management
│ ├── collection/ Book collections
│ ├── smart-scope/ Saved search views
│ ├── scanner/ Scan progress UI
│ ├── reader/ Book reader (epub, pdf, cbz)
│ ├── settings/ User settings
│ └── admin/ Admin panel (users, roles, settings)
├── components/ Shared components (header, sidebar, icons)
│ └── ui/ Reusable UI primitives (button, dialog, etc.)
├── composables/ Global composables
├── views/ Route-level page components
├── router/ Vue Router config and guards
├── lib/ Utilities (api client, helpers)
├── stores/ Pinia stores (theme only - prefer composables)
└── assets/ CSS, fonts, static assets
Testing
pnpm test:unit # run unit tests
pnpm test:cov # run unit tests with coverage
Key conventions
- All components use
<script setup lang="ts">(Composition API only). - Feature state lives in composables (
features/<name>/composables/use*.ts), not global stores. - HTTP calls use the native
fetchAPI viasrc/lib/api.ts. - Styling with Tailwind CSS v4 utility classes. Theme tokens are CSS variables in
src/assets/main.css. - Icons from
lucide-vue-nextonly. - Shared types imported from
@bookorbit/types.