docs: overhaul README and update repo to bookorbit org (#9)

This commit is contained in:
Neon
2026-05-12 00:54:43 -06:00
committed by GitHub
parent c30522d0e3
commit ff3f99e613
3 changed files with 57 additions and 343 deletions
+1 -1
View File
@@ -65,7 +65,7 @@ This step prevents wasted effort on changes that conflict with the project direc
```bash ```bash
git clone https://github.com/<your-username>/bookorbit.git git clone https://github.com/<your-username>/bookorbit.git
cd bookorbit cd bookorbit
git remote add upstream https://github.com/neonsolstice/bookorbit.git git remote add upstream https://github.com/bookorbit/bookorbit.git
``` ```
> **Trusted contributors** with direct push access can skip the fork and work on branches in the main repository. The rest of this guide assumes the fork workflow. > **Trusted contributors** with direct push access can skip the fork and work on branches in the main repository. The rest of this guide assumes the fork workflow.
+53 -339
View File
@@ -1,381 +1,95 @@
<div align="center">
<!-- Replace this with your logo once available -->
<img src="docs/logo.png" alt="BookOrbit" width="120" height="120" />
# BookOrbit # BookOrbit
[![CI](https://github.com/neonsolstice/bookorbit/actions/workflows/ci.yml/badge.svg)](https://github.com/neonsolstice/bookorbit/actions/workflows/ci.yml) A self-hosted library management and reading platform for epub, pdf, audiobooks, and comics.
[![Release](https://github.com/neonsolstice/bookorbit/actions/workflows/release.yml/badge.svg)](https://github.com/neonsolstice/bookorbit/actions/workflows/release.yml)
A self-hostable book and library management app with Kobo device support. Organize your epub, pdf, and cbz collections, track reading progress, and sync with your Kobo. [![CI](https://github.com/bookorbit/bookorbit/actions/workflows/ci.yml/badge.svg)](https://github.com/bookorbit/bookorbit/actions/workflows/ci.yml)
[![Release](https://github.com/bookorbit/bookorbit/actions/workflows/release.yml/badge.svg)](https://github.com/bookorbit/bookorbit/actions/workflows/release.yml)
[![Latest release](https://img.shields.io/github/v/release/bookorbit/bookorbit?label=latest)](https://github.com/bookorbit/bookorbit/releases)
[![Commits/month](https://img.shields.io/github/commit-activity/m/bookorbit/bookorbit?label=commits%2Fmonth)](https://github.com/bookorbit/bookorbit/commits/main)
[![Stars](https://img.shields.io/github/stars/bookorbit/bookorbit?style=flat)](https://github.com/bookorbit/bookorbit/stargazers)
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](LICENSE)
[![Container image](https://img.shields.io/badge/ghcr.io-bookorbit%2Fbookorbit-informational?logo=docker&logoColor=white)](https://github.com/bookorbit/bookorbit/pkgs/container/bookorbit)
**[Documentation](https://bookorbit.app) · [Live Demo](https://demo.bookorbit.app) · [Report a Bug](https://github.com/bookorbit/bookorbit/issues/new?template=bug_report.yml) · [Request a Feature](https://github.com/bookorbit/bookorbit/issues/new?template=feature_request.yml)**
</div>
--- ---
## Quick Start ![BookOrbit dashboard showing reading stats, widgets, and book shelves](https://bookorbit.app/images/home/dashboard-overview.webp)
### Prerequisites
| Tool | Version | Install |
| ------- | ------- | ------------------------------------------------------------ |
| Node.js | >= 24 | [nodejs.org](https://nodejs.org) |
| pnpm | >= 9 | `corepack enable && corepack prepare pnpm@latest --activate` |
| Docker | latest | [docker.com](https://www.docker.com/products/docker-desktop) |
### Setup
```bash
git clone <repo-url> bookorbit
cd bookorbit
pnpm setup
```
Docker is only used for PostgreSQL. The server and client run directly on your machine.
### Start developing
```bash
pnpm dev
```
This starts the NestJS server and Vue client concurrently:
- **Client:** http://localhost:5173
- **API:** http://localhost:3000/api
If you prefer separate terminals (cleaner logs):
```bash
# Terminal 1
cd server && pnpm start:dev
# Terminal 2
cd client && pnpm dev
```
Both must be running. The client proxies all `/api` and `/socket.io` requests to the server, so API calls will fail if only the client is running.
### First steps after setup
1. **Complete initial setup** - you'll be redirected to `/setup` to create the first administrator account (username, password, name, and email).
2. **Create a library** - open Settings (gear icon) > Libraries > Create Library. Add a folder path pointing to some books on your machine, e.g. any directory containing `.epub`, `.pdf`, or `.cbz` files.
3. **Scan** - the library scans automatically after creation. You should see books appear on the home page once the scan completes.
> **Where does data go?** `APP_DATA_PATH` in `server/.env` defaults to `../local/data` (resolves to `<project-root>/local/data`). This is the app's data directory where extracted cover images and thumbnails are stored (`local/data/covers/`). It is **not** where your book files live - those paths are configured per-library in the UI. The `local/` folder is gitignored.
--- ---
## Project Structure ## About
``` BookOrbit is a self-hosted book and library manager. Deploy it once on your own server and get a full reading platform: built-in readers, rich metadata, reading statistics, device sync, and multi-user support - all running on your hardware.
bookorbit/
├── client/ Vue 3 frontend (Vite + Tailwind CSS v4)
├── server/ NestJS 11 backend (Fastify + Drizzle ORM)
├── packages/
│ └── types/ Shared TypeScript types (@bookorbit/types)
├── docker/
│ └── postgres/ Postgres init scripts (extensions)
├── local/ Local dev data (covers, docs) - gitignored
├── docker-compose.dev.yml Dev: runs Postgres only (app runs natively)
├── docker-compose.yml Prod: app + Postgres
├── .env.example Template env file for production compose
└── Dockerfile Production multi-stage build
```
### Monorepo layout No subscription. No third-party account. No data leaving your server.
This is a **pnpm workspace**. The three packages are:
- **`server/`** - NestJS API. Modules live in `src/modules/`, one folder per feature. Database schema is in `src/db/schema/`.
- **`client/`** - Vue 3 SPA. Feature code lives in `src/features/`, shared components in `src/components/ui/`.
- **`packages/types/`** - Shared types imported as `@bookorbit/types` by both server and client. Add any type that crosses the API boundary here.
--- ---
## Common Commands ## Live Demo
All commands run from the **repo root** unless noted otherwise. Try BookOrbit without installing anything. The demo is pre-loaded with a sample library and resets automatically.
### Everyday workflow **[Open demo](https://demo.bookorbit.app/magic?token=2d92cb900e184cf0eb8b11f72cffc6011673d1016e1b300d750eb3d76abc1572)** - no account needed, click the link to log in automatically.
| Command | Description |
| -------------------- | --------------------------------------------------- |
| `pnpm setup` | One-time bootstrap |
| `pnpm dev` | Daily development |
| `pnpm verify` | Default local checks before push |
| `pnpm verify:fast` | Faster local checks while coding (lint + typecheck) |
| `pnpm verify:strict` | Aspirational strict gate (format + full typecheck) |
### Development
| Command | Description |
| ----------------------------- | ------------------------------------ |
| `pnpm dev` | Start server + client (concurrently) |
| `cd server && pnpm start:dev` | Server only (watch mode) |
| `cd client && pnpm dev` | Client only (Vite dev server) |
### Testing
| Command | Description |
| ------------------------------------- | ---------------------------- |
| `pnpm test` | Server + client unit tests |
| `pnpm test:server` | Server unit tests |
| `pnpm test:client` | Client unit tests |
| `pnpm run e2e:run -- guard-mechanics` | Server smoke e2e |
| `pnpm coverage` | Coverage for server + client |
| `pnpm --filter server test:e2e` | Server e2e only |
### Database
| Command | Description |
| ----------------------------------------- | ---------------------------------------- |
| `pnpm db:up` | Start local Postgres |
| `pnpm db:migrate` | Apply pending migrations |
| `pnpm db:seed` | Seed baseline app data |
| `pnpm db:reset` | Reset schema, migrate, and seed |
| `pnpm --filter server db:generate <name>` | Generate a migration from schema changes |
| `pnpm --filter server db:studio` | Open Drizzle Studio (DB browser) |
### Production operations
| Command | Description |
| ---------------- | ------------------------------------- |
| `pnpm prod:up` | Start/update production compose stack |
| `pnpm prod:down` | Stop production compose stack |
### Linting & formatting
| Command | Description |
| --------------------- | ---------------------------------- |
| `pnpm format:check` | Check formatting |
| `pnpm format` | Auto-format source files |
| `pnpm lint:check` | Non-mutating lint checks |
| `pnpm lint:fix` | Auto-fix lint issues |
| `pnpm typecheck` | Typecheck server + client |
| `pnpm typecheck:full` | Typecheck server + client (strict) |
--- ---
## Development Workflow ## Features
Once `pnpm dev` is running, here's how the feedback loop works for each type of change: - **4 built-in readers** - eBook (EPUB, KEPUB, MOBI, AZW3, FB2), PDF, Comics (CBZ, CBR, CB7), Audiobook (M4B, MP3, FLAC, and more)
- **Multiple libraries** with independent scan rules, format priorities, and metadata configuration
### Frontend (`client/`) - **Collections and Smart Scopes** - curated lists and saved filters that live in your sidebar
- **Metadata from 9 providers** - Google Books, Goodreads, Hardcover, Amazon, Audible, ComicVine, and more; with field-level rules and confidence scoring
Save a file → Vite HMR hot-swaps the module → browser updates instantly. No restart needed. - **Reading statistics** - daily time, heatmap, streaks, pace, goal tracking, and library health
- **Kobo sync** - sideload books and sync reading position over the local network
### Backend (`server/`) - **OPDS, email delivery, and Book Dock** for getting books in from anywhere
- **Multi-user** with per-user permissions, isolated reading data, and OIDC/SSO support
Save a file → NestJS watch mode (SWC) recompiles and restarts the server automatically. Takes about a second.
### Shared types (`packages/types/`)
The types package points directly at `.ts` source files. Edit a type → both client and server pick it up on their next rebuild cycle. No build step needed.
### Database schema
Schema changes are the one thing that isn't automatic. See [Database Workflow](#database-workflow) for the generate + migrate steps.
### Environment variables
The `start:dev` script reads `server/.env` once at startup. If you change a value in `.env`, you must restart `pnpm dev` for it to take effect.
### After `git pull`
If other people have pushed changes, you may need to sync dependencies and migrations:
```bash
pnpm install # pick up lockfile changes
pnpm db:migrate # apply any new migrations
```
### Adding a dependency
Always install into the correct workspace, not the root:
```bash
cd server && pnpm add <pkg> # backend dependency
cd client && pnpm add <pkg> # frontend dependency
```
### Adding a new feature
The fastest way to learn the patterns is to follow an existing module:
- **Backend:** Look at `server/src/modules/bookmark/` for a minimal example (controller, service, repository, DTO, module). Copy it, rename, and adapt.
- **Frontend:** Look at `client/src/features/collection/` for a full feature (composables for state/API, components for UI).
- **Shared types:** If the feature adds API request/response shapes, add them in `packages/types/src/` and import via `@bookorbit/types`.
--- ---
## Environment Variables ## Setup
Server environment is configured in `server/.env` for local development. Production compose uses the repo-root `.env` created from `.env.example`. See the **[Installation guide](https://bookorbit.app/installation.html)** for Docker setup, NAS installs, environment variables, and upgrade instructions.
| Variable | Default | Description |
| ------------------------------- | --------------------------------------------------------- | ----------------------------------------------------------------- |
| `DATABASE_URL` | `postgres://bookorbit:bookorbit@localhost:5432/bookorbit` | PostgreSQL connection string |
| `PORT` | `3000` | Server port |
| `NODE_ENV` | `development` | Environment mode |
| `JWT_SECRET` | `change-me-in-production` | JWT signing secret |
| `SETUP_BOOTSTRAP_TOKEN` | (empty) | Required in production for initial `/api/v1/auth/setup` |
| `APP_DATA_PATH` | `../local/data` | App data directory for cover images (not where books live) |
| `APP_URL` | `http://localhost:5173` | Client URL (used in emails) |
| `CSP_ALLOW_CLOUDFLARE_INSIGHTS` | `false` | Allow Cloudflare Web Analytics beacon script/connect hosts in CSP |
| `NODE_MAX_OLD_SPACE_SIZE` | `2048` | Docker Node.js heap limit in MB |
## Production Deploy
Production uses the root compose file and env file:
- Compose: `docker-compose.yml`
- Env file: `.env` (from `.env.example`)
- Image source: CI-published images (`latest`, sha tags, or digests)
Quick start:
```bash
cp .env.example .env
# edit .env and set secrets, APP_URL, BOOKS_HOST_PATH, and optionally APP_IMAGE
pnpm prod:up
```
For production compose, `BOOKS_HOST_PATH` is the only host folder most users need to choose. It is mounted as `/books` in the container, and library paths created in the UI should point under `/books`.
Generated app data and PostgreSQL live in explicit folders beside the compose file:
```text
./data/app generated covers, author images, staging files, and Book Dock uploads
./data/postgres PostgreSQL data
```
The container starts as root only long enough to create/chown app-managed data paths, then runs the Node process as `PUID:PGID`.
On NAS installs, set `PUID` and `PGID` to the user/group that should own app-generated files:
```bash
id your-media-user
```
Do not add a compose `user:` override unless your platform requires it; that bypasses the startup permission repair.
The app container defaults Node's JavaScript heap limit to 2048 MB. Set `NODE_MAX_OLD_SPACE_SIZE` in `.env` if the host needs a lower or higher limit.
--- ---
## Database Workflow ## Documentation
The database schema is defined in `server/src/db/schema/` using Drizzle ORM. Each domain has its own schema file (e.g. `books.ts`, `libraries.ts`, `auth.ts`). Full documentation is at **[bookorbit.app](https://bookorbit.app)**.
**Making schema changes:** > [What is BookOrbit?](https://bookorbit.app/what-is-bookorbit.html) &nbsp;·&nbsp; [Installation](https://bookorbit.app/installation.html) &nbsp;·&nbsp; [Creating a Library](https://bookorbit.app/creating-a-library.html) &nbsp;·&nbsp; [Metadata](https://bookorbit.app/metadata.html) &nbsp;·&nbsp; [Kobo Sync](https://bookorbit.app/kobo.html) &nbsp;·&nbsp; [Users & Permissions](https://bookorbit.app/users.html)
1. Edit the relevant file in `server/src/db/schema/`
2. Generate a migration: `pnpm --filter server db:generate describe_your_change`
3. Apply it: `pnpm db:migrate`
Never hand-write migration SQL. Always generate from schema diffs.
### Resetting the database from scratch
```bash
pnpm db:reset
```
--- ---
## Architecture Overview ## Developing
``` See **[DEVELOPMENT.md](DEVELOPMENT.md)** for local setup, architecture, project structure, database workflow, and commands. See **[TESTING.md](TESTING.md)** for test suites, coverage, and E2E details.
┌──────────────┐ ┌──────────────────────┐ ┌────────────┐
│ Vue 3 SPA │──────>│ NestJS API (/api) │──────>│ PostgreSQL │
│ port 5173 │<──────│ port 3000 │<──────│ port 5432 │
└──────────────┘ └──────────────────────┘ └────────────┘
│ │
│ WebSocket │ Drizzle ORM
│ (socket.io) │ (schema in src/db/schema/)
└────────────────────────┘
```
- **Backend:** NestJS 11 on Fastify. Global prefix `/api`. Auth via JWT (access + refresh tokens in httpOnly cookies). RBAC with permissions system.
- **Frontend:** Vue 3 Composition API (`<script setup>`). Tailwind CSS v4 for styling. Feature-local state in composables, not global stores.
- **Database:** PostgreSQL 16 via Drizzle ORM. Migrations generated by Drizzle Kit.
- **Shared types:** `@bookorbit/types` package ensures API contracts stay in sync.
--- ---
## Troubleshooting ## Contributing
### Port 5432 already in use Contributions are welcome. For the full contribution workflow (branch naming, test expectations, PR checklist, commit format), see **[CONTRIBUTING.md](CONTRIBUTING.md)**.
Another PostgreSQL instance is running. Either stop it or change the port mapping in `docker-compose.yml`: To report a security vulnerability, use [GitHub's private vulnerability reporting](https://github.com/bookorbit/bookorbit/security/advisories/new) - do not open a public issue.
```yaml
ports:
- "5433:5432" # use 5433 on host
```
Then update `DATABASE_URL` in `server/.env` to use port `5433`.
### Port 3000 or 5173 already in use
Kill the process occupying the port:
```bash
lsof -ti:3000 | xargs kill -9 # server port
lsof -ti:5173 | xargs kill -9 # client port
```
### `pnpm db:migrate` does nothing after a schema change
You need to generate a migration first:
```bash
cd server && pnpm db:generate describe_your_change
cd server && pnpm db:migrate
```
### `pnpm db:generate` fails with a connection error
Drizzle Kit auto-loads `server/.env` for the `DATABASE_URL`. If the file is missing or the URL is wrong, generation fails. Verify `server/.env` exists and that PostgreSQL is running (`docker compose ps`).
The fallback URL in `drizzle.config.ts` uses `postgres:5432` (the Docker service hostname), which only works inside Docker, not from the host machine.
### Docker container won't start
```bash
docker compose down
docker compose up -d --wait
```
If the volume is corrupted, wipe it (destroys all data):
```bash
docker compose down -v
docker compose up -d --wait
cd server && pnpm db:migrate
```
### `EACCES: permission denied, mkdir '/data/covers'`
The default compose uses `./data/app` for generated app data. The container repairs `/data` ownership during startup, then runs as `PUID:PGID`.
If this still happens, make sure the folder mounted at `/data` is writable by `PUID:PGID`. Avoid adding `user:` to the app service, because startup cannot repair ownership when it is forced to start as a non-root user.
### `Cannot find module '@bookorbit/types'`
The shared types package needs to be built or the workspace link is broken:
```bash
pnpm install
```
### CORS errors in the browser
Make sure you're accessing the client at `http://localhost:5173` (not port 3000). The Vite dev server proxies API requests to the backend automatically.
--- ---
## Further Reading ## Support
| Doc | What it covers | - **Questions and discussion:** [GitHub Discussions](https://github.com/bookorbit/bookorbit/discussions)
| ---------------------------------------------------- | ------------------------------------------------------------ | - **Bug reports:** [GitHub Issues](https://github.com/bookorbit/bookorbit/issues/new?template=bug_report.yml)
| [`docs/production.md`](docs/production.md) | Production compose deployment, backups, restore testing | - **Feature requests:** [GitHub Issues](https://github.com/bookorbit/bookorbit/issues/new?template=feature_request.yml)
| [`docs/release-process.md`](docs/release-process.md) | Release workflow, PR title format, Docker publish, rollback |
| [`server/README.md`](server/README.md) | Backend module map, DB commands, NestJS conventions | ---
| [`client/README.md`](client/README.md) | Frontend project layout, IDE setup, Vue/Tailwind conventions |
| [`packages/types/`](packages/types/) | Shared type definitions between server and client | ## License
BookOrbit is licensed under the **[GNU Affero General Public License v3.0](LICENSE)**.
+3 -3
View File
@@ -88,8 +88,8 @@ If all commits since the last release are non-releasable types (`chore`, `docs`,
The `release.yml` workflow publishes Docker images after a successful release: The `release.yml` workflow publishes Docker images after a successful release:
- `ghcr.io/neonsolstice/bookorbit:<X.Y.Z>` - version-specific tag - `ghcr.io/bookorbit/bookorbit:<X.Y.Z>` - version-specific tag
- `ghcr.io/neonsolstice/bookorbit:latest` - latest stable release - `ghcr.io/bookorbit/bookorbit:latest` - latest stable release
Images are scanned with Trivy before push. If critical or high vulnerabilities are found, the push is blocked. Images are scanned with Trivy before push. If critical or high vulnerabilities are found, the push is blocked.
@@ -107,7 +107,7 @@ To deploy a previous version:
```bash ```bash
# In your production docker-compose.yml or .env, set: # In your production docker-compose.yml or .env, set:
APP_IMAGE=ghcr.io/neonsolstice/bookorbit:X.Y.Z APP_IMAGE=ghcr.io/bookorbit/bookorbit:X.Y.Z
``` ```
Replace `X.Y.Z` with the version you want to roll back to, then redeploy: Replace `X.Y.Z` with the version you want to roll back to, then redeploy: