mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
b1ba3a03e7
Clearing a book's progress deleted the shared row and left the KOReader device row behind, so the next pull served the deleted position straight back. Clearing that row too is not enough either: an empty response reads as "this server knows nothing about your book", which is the one reply that leaves a device certain its own sidecar is the only position there is, and it pushes that back on the next sync. Record the reset as a durable fact and answer the pull with a real start position attributed to BookOrbit. Route the position by format, because KOReader's own kosync plugin feeds it straight to GotoPage or GotoXPointer with no percentage fallback and an empty value leaves the reader where it was. Stamp each delivery as current, because both clients compare that against their last page turn and default backward syncs to disabled, so the original reset time would be dropped on any pull deferred past a page turn without ever prompting. Serving a reset proves nothing, since either client can classify it as a backward sync and drop it silently, so the marker survives delivery and a device is held until its own push reports the start. Retire it once a device that took the reset reads on: the pull carries no device identity, so a marker kept alive past its purpose is answered to every device and would send that one back to the start on every sync. The bound this leaves is deliberate. A second device that never took the reset is protected only until the first reads on, and closing that needs device_id on the pull, which is a plugin change. Judge convergence on the reported position rather than the percentage, so page 1 of a hundred page comic is not mistaken for a position no short book could ever reach. Wind Kobo bookmarks back through the same paths, since a Kobo device otherwise resumes from its own bookmark and reports it back the same way. Closes #1032
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/vueonly. - Shared types imported from
@bookorbit/types.