Files
bookorbit/client
neon 199ba687c3 feat(achievements): answer in the language the client asks for
Achievement names, descriptions and category labels, the secret placeholder and the monthly
challenge are text the server writes and every client shows as is, so they stayed English in a
translated web page and will in the localized iOS app. The routes that return them now read
Accept-Language and answer in that language, with Vary: Accept-Language.

The translations live in the web's catalogs under serverText, so Crowdin, its checks and its
translators handle them through the existing pipeline; the server reads that subtree, and the image
copies the catalogs beside dist. English is never looked up: a request without the header, and
every client that predates it, gets the bytes it got before. A test keeps serverText in en.json
equal to the seed and the constants it mirrors. The web now sends its chosen language on every API
request, and the Accept-Language matcher moved into @bookorbit/types so the client and the server
negotiate the same way.

The iOS app is a consumer the web client does not show: it will send its own interface language.
App Store builds that predate that still send the device language, so on a non-English device they
will start getting translated achievement names inside English screens. That was accepted; the
response shape does not change.

Ref bookorbit/bookorbit-ios-support#79
2026-10-30 02:21:07 +00:00
..

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:6263.

The Vite dev server proxies /api and /socket.io requests to the backend at localhost:6262.

IDE setup

  • VS Code: Install the Vue (Official) extension. Disable Vetur if installed.
  • WebStorm / IntelliJ: Vue support is built in. Enable TypeScript service for .vue files.
  • 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 fetch API via src/lib/api.ts.
  • Styling with Tailwind CSS v4 utility classes. Theme tokens are CSS variables in src/assets/main.css.
  • Icons from @lucide/vue only.
  • Shared types imported from @bookorbit/types.