mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 08:21:39 -06:00
d87312a8ca
Every settings write from the reader PUT the whole object: the defaults write sent all twenty-one EPUB fields and the per-book write sent the entire accumulated delta. PUT replaces the stored row, so a write from this client threw away whatever another one had set since the page loaded. That is a real conflict now rather than a theoretical one. The iOS reader owns the look fields and keeps the layout fields on the device, so it writes a small subset and leaves the rest alone. A full snapshot from a web tab reverted its look edits silently, and there was nothing either side could do about it: last writer won the whole row. Move the three writes to the PATCH routes, which merge field by field on the server, so two clients editing different fields no longer race. An empty patch is dropped rather than sent, because the server rejects an empty body. Reset still deletes, on both routes: removing a customization is a whole-row operation and means the same thing to every client.
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.