Adds a reader section covering the vendored tree, the $foliate alias and the traps around it, and refreshes the stale stack line, oklch claim and rough edges. Records why CSP is not enabled in TODO.md.
106 lines
5.3 KiB
Markdown
106 lines
5.3 KiB
Markdown
# Chitai
|
|
|
|
Self-hosted eBook library manager. Users organise eBook files into **libraries**, which contain
|
|
**books** (one book = one metadata record + one or more files on disk). Books carry authors,
|
|
publishers, tags, series and identifiers, can be grouped into per-user **bookshelves**, and are read
|
|
in-browser through built-in EPUB and PDF readers with reading-progress tracking. The catalogue is
|
|
also exposed as an **OPDS** feed for e-reader apps, and progress syncs with **KOReader** devices via
|
|
a KOSync-compatible endpoint.
|
|
|
|
## Layout
|
|
|
|
| Path | What |
|
|
| -------------------------- | ---------------------------------------------------------------------------------------- |
|
|
| `backend/` | Litestar REST API + PostgreSQL. See `backend/AGENTS.md`. |
|
|
| `frontend/` | SvelteKit SSR web app. See `frontend/AGENTS.md`. |
|
|
| `frontend/src/lib/vendor/` | Vendored `foliate-js` (the EPUB engine), copied by `frontend/scripts/vendor-foliate.sh`. |
|
|
| `frontend/static/pdfjs/` | Vendored pdf.js viewer, used by the PDF reader in an iframe. |
|
|
| `docker-compose.yml` | Production stack: `db` (postgres:17), `backend`, `frontend`. |
|
|
| `docs/screenshots/` | Images used by `README.md`. |
|
|
| `shell.nix` | Root dev shell; composes the two sub-shells. |
|
|
|
|
## Development environment
|
|
|
|
`nix-shell` from the repo root is the intended entry point. It pulls in both
|
|
`backend/shell.nix` and `frontend/shell.nix`, whose `shellHook`s do real work as a side effect:
|
|
|
|
- **backend** — `uv venv` + `uv sync`, then `initdb` / `pg_ctl start` into `backend/.postgres/`
|
|
(socket dir, not TCP), `createdb chitai`, and finally applies migrations with
|
|
`alchemy --config chitai.database.config.config upgrade --no-prompt`.
|
|
`exitHook` stops PostgreSQL on shell exit.
|
|
- **frontend** — `pnpm install`.
|
|
|
|
So entering the shell gives you a running database with an up-to-date schema; you do not need to
|
|
start Postgres yourself. Both hooks `cd` around, which can be surprising in scripts.
|
|
|
|
Without Nix you need: Python 3.13 + `uv`, Node 24 + `pnpm`, and PostgreSQL 17 with the `pg_trgm`
|
|
extension available.
|
|
|
|
## Configuration
|
|
|
|
All backend settings are read by `backend/src/chitai/config.py` (`Settings`, pydantic-settings) with
|
|
the **`CHITAI_` prefix** from the repo-root `.env`. `.env.prod-example` is the template; copy it to
|
|
`.env` for a fresh deployment.
|
|
|
|
`.env` is gitignored and contains a real `CHITAI_TOKEN_SECRET` — do not print, copy or commit it.
|
|
|
|
The frontend reads exactly one variable, `VITE_BACKEND_API_URL`
|
|
(`frontend/src/lib/server/config.ts`, defaulting to `http://localhost:8000`).
|
|
|
|
## How a request flows
|
|
|
|
```
|
|
browser
|
|
└─ SvelteKit SSR node server
|
|
├─ hooks.server.ts reads `authToken` cookie, validates via GET /access/me,
|
|
│ populates locals.user / locals.api, redirects to /login otherwise
|
|
├─ $lib/api/*.remote.ts remote functions (query/command/form) → locals.api (ApiClient)
|
|
└─ routes/api/[...path] catch-all proxy, for browser-direct fetches (reader file streams)
|
|
└─ Litestar backend
|
|
└─ controllers/ → services/ → SQLAlchemy models → PostgreSQL
|
|
```
|
|
|
|
The JWT the frontend holds in the `authToken` cookie is the same bearer token the backend issues
|
|
from `POST /access/login`. The frontend never stores credentials beyond that cookie.
|
|
|
|
## Commands
|
|
|
|
Backend (from `backend/`):
|
|
|
|
```bash
|
|
uv run litestar --app-dir src/chitai/ run --reload # dev server on :8000
|
|
pytest tests/ # needs Docker (pytest-databases)
|
|
ruff format src/
|
|
alchemy --config chitai.database.config.config make-migrations
|
|
alchemy --config chitai.database.config.config upgrade
|
|
```
|
|
|
|
Frontend (from `frontend/`):
|
|
|
|
```bash
|
|
pnpm dev # vite dev server on :5173
|
|
pnpm build # adapter-node output in build/
|
|
pnpm check # svelte-check — run before finishing
|
|
pnpm lint # prettier --check + eslint
|
|
pnpm format # prettier --write
|
|
```
|
|
|
|
API docs are served by the running backend at `http://localhost:8000/schema/` (Swagger) and
|
|
`/schema/openapi.json`.
|
|
|
|
## Cross-cutting rules
|
|
|
|
- **Keep the two schema layers in sync.** Backend request/response shapes live in
|
|
`backend/src/chitai/schemas/` (Pydantic); the frontend mirrors them as Zod schemas in
|
|
`frontend/src/lib/schema/`. Changing one without the other produces runtime validation failures,
|
|
not type errors.
|
|
- **Regenerate the OpenAPI types** after changing API shapes.
|
|
`frontend/src/lib/schema/openapi/schema.d.ts` is generated from the backend's OpenAPI document
|
|
with `openapi-typescript` (a devDependency; there is no `package.json` script for it, so it is run
|
|
manually against a live backend).
|
|
- **Migrations are mandatory.** The app runs with `create_all=False`, so a model change without a
|
|
matching Alembic revision will not reach the database.
|
|
- **Commit messages** follow `type: summary` — `feat:`, `fix:`, `refactor:`, `chore:`.
|
|
- The three `README.md` files are user-facing. Agent-facing knowledge belongs in the `AGENTS.md`
|
|
files.
|