refactor(docs): reorganize and enhance documentation structure

- Rename configuration.md to auth.md for clarity
- Rename storage-and-blob-behavior.md to object-blob-storage.md
- Split server library import into dedicated documentation page
- Rename intro.md to introduction.md
- Merge support.md into support-and-contributing.md
- Add interactive tabs to configuration and setup guides
- Improve cross-references and navigation between documentation pages
- Update sidebar structure and Docusaurus config for new file paths
This commit is contained in:
Richard R 2026-02-11 04:16:02 -07:00
parent 4e2d18962d
commit 63483e055e
14 changed files with 315 additions and 120 deletions

View file

@ -15,5 +15,5 @@ This page covers application-level configuration for provider access and authent
- For the complete variable reference: [Environment Variables](../reference/environment-variables) - For the complete variable reference: [Environment Variables](../reference/environment-variables)
- For TTS character limits and quota behavior: [TTS Rate Limiting](./tts-rate-limiting) - For TTS character limits and quota behavior: [TTS Rate Limiting](./tts-rate-limiting)
- For provider-specific guidance: [TTS Providers](./tts-providers) - For provider-specific guidance: [TTS Providers](./tts-providers)
- For storage/S3/SeaweedFS behavior: [Object / Blob Storage](./storage-and-blob-behavior) - For storage/S3/SeaweedFS behavior: [Object / Blob Storage](./object-blob-storage)
- For database mode and migration commands: [Database and Migrations](./database-and-migrations) - For database mode and migration commands: [Database and Migrations](./database-and-migrations)

View file

@ -2,12 +2,15 @@
title: Database and Migrations title: Database and Migrations
--- ---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
This page covers database mode selection and migration behavior for OpenReader WebUI. This page covers database mode selection and migration behavior for OpenReader WebUI.
## Database mode ## Database mode
- Default mode: embedded SQLite at `docstore/sqlite3.db` - SQLite (default): embedded DB at `docstore/sqlite3.db`; good for local/self-host single-instance setups.
- External mode: Postgres when `POSTGRES_URL` is set - Postgres: enabled when `POSTGRES_URL` is set; recommended for production/distributed deployments.
## Startup migration behavior ## Startup migration behavior
@ -22,6 +25,10 @@ Startup migration phases:
- DB schema migrations (`pnpm migrate`) - DB schema migrations (`pnpm migrate`)
- Storage/data migration (`pnpm migrate-fs`) for legacy filesystem content into S3 + DB rows - Storage/data migration (`pnpm migrate-fs`) for legacy filesystem content into S3 + DB rows
:::info
In most setups, you do not need to run migration commands manually because startup handles this automatically.
:::
To skip automatic startup migrations: To skip automatic startup migrations:
- Set `RUN_DRIZZLE_MIGRATIONS=false` - Set `RUN_DRIZZLE_MIGRATIONS=false`
@ -33,6 +40,9 @@ Database variables are documented in [Environment Variables](../reference/enviro
In most cases, you do not need manual migration commands because startup runs migrations automatically. In most cases, you do not need manual migration commands because startup runs migrations automatically.
<Tabs groupId="migration-commands">
<TabItem value="project-scripts" label="Project Scripts" default>
```bash ```bash
# Run pending migrations (uses Postgres config when POSTGRES_URL is set, otherwise SQLite) # Run pending migrations (uses Postgres config when POSTGRES_URL is set, otherwise SQLite)
pnpm migrate pnpm migrate
@ -47,7 +57,8 @@ pnpm migrate-fs:dry-run
pnpm generate pnpm generate
``` ```
## Manual Drizzle commands (advanced) </TabItem>
<TabItem value="drizzle-direct" label="Drizzle Direct (Advanced)">
```bash ```bash
# Migrate SQLite # Migrate SQLite
@ -62,3 +73,10 @@ pnpm exec drizzle-kit generate --config drizzle.config.sqlite.ts
# Generate Postgres migrations # Generate Postgres migrations
pnpm exec drizzle-kit generate --config drizzle.config.pg.ts pnpm exec drizzle-kit generate --config drizzle.config.pg.ts
``` ```
</TabItem>
</Tabs>
:::warning
If you disable startup migrations, ensure your deployment process runs migrations before serving traffic.
:::

View file

@ -2,12 +2,12 @@
title: Object / Blob Storage title: Object / Blob Storage
--- ---
This page documents storage backends, blob upload routing, and Docker mount behavior. This page documents storage backends, blob upload routing, and core Docker mount behavior.
## Storage backends ## Storage backends
- Default: embedded SQLite metadata + embedded SeaweedFS (`weed mini`) blobs - Embedded (default): SQLite metadata + embedded SeaweedFS (`weed mini`) blobs.
- External option: Postgres + external S3-compatible object storage - External: Postgres + external S3-compatible object storage.
Storage variables are documented in [Environment Variables](../reference/environment-variables) under the storage sections. Storage variables are documented in [Environment Variables](../reference/environment-variables) under the storage sections.
@ -16,24 +16,23 @@ Storage variables are documented in [Environment Variables](../reference/environ
- `3003`: OpenReader app and API routes - `3003`: OpenReader app and API routes
- `8333`: Embedded SeaweedFS S3 endpoint for direct browser blob access - `8333`: Embedded SeaweedFS S3 endpoint for direct browser blob access
:::info
`8333` is only needed for direct browser presigned access to embedded SeaweedFS.
:::
## Upload behavior ## Upload behavior
- Primary path: browser uploads to presigned URL from `/api/documents/blob/upload/presign` - Primary path: browser uploads to presigned URL from `/api/documents/blob/upload/presign`.
- Fallback path: `/api/documents/blob/upload/fallback` if direct upload fails or endpoint is unreachable - Fallback path: `/api/documents/blob/upload/fallback` when direct upload fails/unreachable.
- Content serving path: `/api/documents/blob` - Read/download path: blob/content serving route `/api/documents/blob` (not the upload fallback route).
## Recommended Docker mounts ## Recommended Docker mounts
| Mount | Type | Recommended | Purpose | Example | | Mount | Type | Recommended | Purpose | Example |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| `/app/docstore` | Docker named volume | Yes (for persistence) | Persists SeaweedFS blob data, SQLite metadata DB, migrations, and local runtime temp state | `-v openreader_docstore:/app/docstore` | | `/app/docstore` | Docker named volume | Yes (for persistence) | Persists SeaweedFS blob data, SQLite metadata DB, migrations, and local runtime temp state | `-v openreader_docstore:/app/docstore` |
| `/app/docstore/library` | Bind mount | Optional + `:ro` | Read-only source for server library import (files are copied/imported into client storage) | `-v /path/to/your/library:/app/docstore/library:ro` |
To import from mounted library: **Settings -> Documents -> Server Library Import**. For server library mounts/import behavior, see [Server Library Import](./server-library-import).
:::note
Every file in the mounted library is imported into client browser storage. Keep the library reasonably sized.
:::
## Private blob endpoint mode ## Private blob endpoint mode
@ -43,6 +42,10 @@ If `8333` is not published externally:
- Reads/snippets continue through app API routes - Reads/snippets continue through app API routes
- Direct presigned browser upload/download to embedded endpoint is unavailable - Direct presigned browser upload/download to embedded endpoint is unavailable
:::warning
Without `8333`, expect higher app-server traffic because uploads/downloads go through API routes instead of direct object endpoint access.
:::
## Audiobook storage note ## Audiobook storage note
- In current versions, audiobook assets live in object storage (`audiobooks_v1` keyspace), not as durable files under `/app/docstore`. - In current versions, audiobook assets live in object storage (`audiobooks_v1` keyspace), not as durable files under `/app/docstore`.

View file

@ -0,0 +1,66 @@
---
title: Server Library Import
---
This page documents how server library import works and how to configure it.
## What it does
Server library import lets you browse files from one or more server directories and import selected files into OpenReader.
- Import is user-driven via a selection modal
- Only selected files are imported
- Imported files become normal OpenReader documents
## Configure library roots
Library roots are resolved from environment variables:
- `IMPORT_LIBRARY_DIRS` (takes precedence): multiple roots separated by comma, colon, or semicolon
- `IMPORT_LIBRARY_DIR`: single root
- Fallback when neither is set: `docstore/library`
See [Environment Variables](../reference/environment-variables#import_library_dir) for details.
## Docker mount example
Mount a host folder to the default library path:
```bash
docker run --name openreader-webui \
--restart unless-stopped \
-p 3003:3003 \
-v openreader_docstore:/app/docstore \
-v /path/to/your/library:/app/docstore/library:ro \
ghcr.io/richardr1126/openreader-webui:latest
```
Using `:ro` is recommended so the app treats the library as a read-only source.
## Import flow
1. Open **Settings -> Documents -> Server Library Import**.
2. Select files in the modal.
3. Click **Import**.
Selected files are fetched from the server library endpoint and imported into OpenReader storage.
:::warning Shared Library Roots
Library roots are configured at the server level (not per-user). Any user who can access Server Library Import can browse/import from the same configured roots.
Imported documents are still saved to the importing user's document scope.
:::
## Supported file types
- `.pdf`
- `.epub`
- `.html`, `.htm`
- `.txt`
- `.md`, `.mdown`, `.markdown`
## Notes
- Library listing is capped per request (up to 10,000 files).
- When auth is enabled, library import endpoints require a valid session.
- The mounted library is a source; removing it does not delete already imported documents.

View file

@ -2,47 +2,75 @@
title: TTS Providers title: TTS Providers
--- ---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
OpenReader WebUI supports OpenAI-compatible TTS providers through a common API shape. OpenReader WebUI supports OpenAI-compatible TTS providers through a common API shape.
## Supported provider patterns :::tip
If you are running a self-hosted TTS server (Kokoro/Orpheus/etc.), use **Custom OpenAI-Like** in Settings.
:::
- OpenAI API ## Quick Setup by Provider
- DeepInfra
- Kokoro-FastAPI
- Orpheus-FastAPI
- Custom OpenAI-compatible endpoints
## Provider dropdown behavior <Tabs groupId="tts-provider-setup">
<TabItem value="openai" label="OpenAI" default>
In Settings, the provider dropdown includes: 1. In Settings, choose provider: `OpenAI`.
2. Keep the default `API_BASE` (auto-filled).
3. Set `API_KEY` to your OpenAI key.
4. Choose model/voice.
</TabItem>
<TabItem value="deepinfra" label="DeepInfra">
1. In Settings, choose provider: `Deepinfra`.
2. Keep the default `API_BASE` (auto-filled).
3. Set `API_KEY` to your DeepInfra key.
4. Choose model/voice.
</TabItem>
<TabItem value="custom" label="Custom OpenAI-Like">
1. In Settings, choose provider: `Custom OpenAI-Like`.
2. Set `API_BASE` to your endpoint (example: `http://host.docker.internal:8880/v1`).
3. Set `API_KEY` if your provider requires one.
4. Choose model/voice.
</TabItem>
</Tabs>
## Provider Dropdown Behavior
In Settings, provider options include:
- `OpenAI` - `OpenAI`
- `Deepinfra` - `Deepinfra`
- `Custom OpenAI-Like` (for Kokoro, Orpheus, and other compatible endpoints) - `Custom OpenAI-Like` (Kokoro, Orpheus, and other OpenAI-compatible endpoints)
`API_BASE` guidance: `API_BASE` guidance:
- For `OpenAI` and `Deepinfra`, OpenReader auto-fills the default endpoint. - `OpenAI` and `Deepinfra` auto-fill default endpoints.
- For `Custom OpenAI-Like`, set `API_BASE` to your server endpoint. - `Custom OpenAI-Like` requires setting `API_BASE` manually.
- In practice, you usually only set `API_BASE` when using a provider/endpoint that is not directly covered by the built-in dropdown defaults.
## Custom provider compatibility :::info OpenAI-Compatible API Shape
Custom providers should expose:
For custom providers, OpenReader expects these endpoints:
- `GET /v1/audio/voices` - `GET /v1/audio/voices`
- `POST /v1/audio/speech` - `POST /v1/audio/speech`
:::
If your provider exposes this interface, it can be used as an OpenAI-compatible TTS backend. :::warning Server-Reachable API Base
TTS requests are sent from the Next.js server, not directly from the browser. `API_BASE` must be reachable from the server runtime.
:::
## Setup flow ## Related Guides
1. Select your provider in the OpenReader Settings modal. - [Environment Variables](../reference/environment-variables)
2. If using `Custom OpenAI-Like` (or overriding a default), set `API_BASE`. - [TTS Rate Limiting](./tts-rate-limiting)
3. Set `API_KEY` if required by your provider. - [Auth](./auth)
4. Choose model and voice. - [Kokoro-FastAPI](../integrations/kokoro-fastapi)
- [Orpheus-FastAPI](../integrations/orpheus-fastapi)
For environment variables, see [Environment Variables](../reference/environment-variables). - [Deepinfra](../integrations/deepinfra)
For TTS quota behavior, see [TTS Rate Limiting](./tts-rate-limiting). - [OpenAI](../integrations/openai)
For auth behavior, see [Auth](./configuration). - [Custom OpenAI](../integrations/custom-openai)
For provider-specific integration guides, see [Kokoro-FastAPI](../integrations/kokoro-fastapi), [Orpheus-FastAPI](../integrations/orpheus-fastapi), [Deepinfra](../integrations/deepinfra), [OpenAI](../integrations/openai), and [Custom OpenAI](../integrations/custom-openai).

View file

@ -47,5 +47,5 @@ IP backstop daily limits:
## Related docs ## Related docs
- Full variable list: [Environment Variables](../reference/environment-variables) - Full variable list: [Environment Variables](../reference/environment-variables)
- Auth configuration: [Auth](./configuration) - Auth configuration: [Auth](./auth)
- Provider setup: [TTS Providers](./tts-providers) - Provider setup: [TTS Providers](./tts-providers)

View file

@ -1,40 +0,0 @@
---
id: intro
title: Introduction
slug: /
---
OpenReader WebUI is an open source text-to-speech document reader built with Next.js. It provides a read-along experience with narration for **EPUB, PDF, TXT, MD, and DOCX documents**.
It supports multiple TTS providers including OpenAI, DeepInfra, and custom OpenAI-compatible endpoints such as [Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI) and [Orpheus-FastAPI](https://github.com/Lex-au/Orpheus-FastAPI).
## Highlights
- Multi-provider TTS support
- [Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI) (including multi-voice combinations)
- [Orpheus-FastAPI](https://github.com/Lex-au/Orpheus-FastAPI)
- Custom OpenAI-compatible endpoints (`/v1/audio/voices` and `/v1/audio/speech`)
- Cloud providers such as [DeepInfra](https://deepinfra.com/models/text-to-speech) and [OpenAI API](https://platform.openai.com/docs/pricing#transcription-and-speech)
- Server-side sync and storage
- External library import from a server-mounted folder
- Sync documents between browser and server for multi-device use
- Server-side audiobook export in `m4b`/`mp3`, with resumable chapter-based export
- Read-along highlighting for PDF and EPUB
- Optional word-by-word highlighting using server-side timestamps from [whisper.cpp](https://github.com/ggml-org/whisper.cpp)
- Sentence-aware narration that merges across pages/chapters for smoother playback
- Optimized Next.js TTS proxy with caching for faster repeat playback
- Customizable themes, TTS settings, and document handling
## Start Here
- [Docker Quick Start](./start-here/docker-quick-start)
- [Local Development](./start-here/local-development)
- [Environment Variables](./reference/environment-variables)
- [Auth](./configure/configuration)
- [Database and Migrations](./configure/database-and-migrations)
- [Object / Blob Storage](./configure/storage-and-blob-behavior)
- [TTS Providers](./configure/tts-providers)
## Source Repository
- GitHub: [richardr1126/OpenReader-WebUI](https://github.com/richardr1126/OpenReader-WebUI)

View file

@ -0,0 +1,48 @@
---
id: intro
title: Introduction
slug: /
---
OpenReader WebUI is an open source text-to-speech document reader built with Next.js. It provides a read-along experience with narration for **EPUB, PDF, TXT, MD, and DOCX documents**.
It supports multiple TTS providers including OpenAI, DeepInfra, and custom OpenAI-compatible endpoints such as [Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI) and [Orpheus-FastAPI](https://github.com/Lex-au/Orpheus-FastAPI).
## ✨ Highlights
- 🎯 **Multi-Provider TTS Support**
- [**Kokoro-FastAPI**](https://github.com/remsky/Kokoro-FastAPI): supports multi-voice combinations (for example `af_heart+af_bella`)
- [**Orpheus-FastAPI**](https://github.com/Lex-au/Orpheus-FastAPI)
- **Custom OpenAI-compatible**: any TTS API with `/v1/audio/voices` and `/v1/audio/speech` endpoints
- **Cloud TTS providers**:
- [**DeepInfra**](https://deepinfra.com/models/text-to-speech): Kokoro-82M and other hosted models
- [**OpenAI API**](https://platform.openai.com/docs/pricing#transcription-and-speech): `tts-1`, `tts-1-hd`, and `gpt-4o-mini-tts`
- 🛜 **Server-side Document Storage**
- Documents are persisted in server blob/object storage for consistent access
- 📚 **External Library Import**
- Import documents from server-mounted folders
- 🎧 **Server-side Audiobook Export** in `m4b`/`mp3` with resumable chapter generation
- 📖 **Read Along Experience**
- Real-time highlighting for PDF/EPUB, with optional word-level [whisper.cpp](https://github.com/ggml-org/whisper.cpp) timestamps
- 🔐 **Auth Optional by Design**
- Run no-auth for local use, or enable auth with user isolation and claim flow
- 🗂️ **Flexible Storage and Database Modes** with embedded defaults or external S3/Postgres
- 🚀 **Production-ready Server Behavior** with TTS caching/retries/rate limits and startup migrations
- 🎨 **Customizable Experience**
- Theme, TTS, and document handling controls
## 🚀 Start Here
- [Docker Quick Start](./start-here/docker-quick-start)
- [Vercel Deployment](./start-here/vercel-deployment)
- [Local Development](./start-here/local-development)
- [Environment Variables](./reference/environment-variables)
- [Auth](./configure/auth)
- [Database and Migrations](./configure/database-and-migrations)
- [Object / Blob Storage](./configure/object-blob-storage)
- [Server Library Import](./configure/server-library-import)
- [TTS Providers](./configure/tts-providers)
## Source Repository
- GitHub: [richardr1126/OpenReader-WebUI](https://github.com/richardr1126/OpenReader-WebUI)

View file

@ -2,6 +2,9 @@
title: Docker Quick Start title: Docker Quick Start
--- ---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Prerequisites ## Prerequisites
- A recent Docker version installed - A recent Docker version installed
@ -13,7 +16,10 @@ If you have suitable hardware, you can run Kokoro locally with Docker. See [Koko
## 1. Start the Docker container ## 1. Start the Docker container
Minimal setup (auth disabled, embedded storage ephemeral, no library import): <Tabs groupId="docker-start-mode">
<TabItem value="minimal" label="Minimal" default>
Auth disabled, embedded storage ephemeral, no library import:
```bash ```bash
docker run --name openreader-webui \ docker run --name openreader-webui \
@ -23,7 +29,10 @@ docker run --name openreader-webui \
ghcr.io/richardr1126/openreader-webui:latest ghcr.io/richardr1126/openreader-webui:latest
``` ```
Fully featured setup (persistent storage, embedded SeaweedFS `weed mini`, optional auth): </TabItem>
<TabItem value="full" label="Full Setup">
Persistent storage, embedded SeaweedFS `weed mini`, optional auth, optional library mount:
```bash ```bash
docker run --name openreader-webui \ docker run --name openreader-webui \
@ -39,21 +48,38 @@ docker run --name openreader-webui \
ghcr.io/richardr1126/openreader-webui:latest ghcr.io/richardr1126/openreader-webui:latest
``` ```
You can remove `/app/docstore/library` if you do not need server library import. </TabItem>
You can remove either `BASE_URL` or `AUTH_SECRET` to keep auth disabled. </Tabs>
Quick notes: :::tip
Remove `/app/docstore/library` if you do not need server library import.
:::
- `API_BASE` should point to your TTS server base URL. :::tip
- Expose `8333` for direct browser access to embedded SeaweedFS presigned URLs. Remove either `BASE_URL` or `AUTH_SECRET` to keep auth disabled.
- If `8333` is not exposed, uploads still work through `/api/documents/blob/upload/fallback`. :::
- To enable auth, set both `BASE_URL` and `AUTH_SECRET`.
- DB migrations run automatically during container startup via the shared entrypoint.
For all environment variables, see [Environment Variables](../reference/environment-variables). :::tip TTS API Base
For app/auth behavior, see [Auth](../configure/configuration). Set `API_BASE` to your reachable TTS server base URL.
For database startup and migration behavior, see [Database and Migrations](../configure/database-and-migrations). :::
For blob behavior and mounts, see [Object / Blob Storage](../configure/storage-and-blob-behavior).
:::warning Port `8333` Exposure
Expose `8333` for direct browser presigned upload/download with embedded SeaweedFS.
If `8333` is not reachable from the browser, direct presigned access is unavailable. Uploads can still fall back to `/api/documents/blob/upload/fallback`, and document reads/downloads continue through `/api/documents/blob`.
:::
:::info Auth and Migrations
- Auth is enabled only when both `BASE_URL` and `AUTH_SECRET` are set.
- DB/storage migrations run automatically at container startup via the shared entrypoint.
:::
:::info Related Docs
- [Environment Variables](../reference/environment-variables)
- [Auth](../configure/auth)
- [Database and Migrations](../configure/database-and-migrations)
- [Object / Blob Storage](../configure/object-blob-storage)
:::
## 2. Configure settings in the app UI ## 2. Configure settings in the app UI
@ -70,4 +96,8 @@ docker image rm ghcr.io/richardr1126/openreader-webui:latest || true && \
docker pull ghcr.io/richardr1126/openreader-webui:latest docker pull ghcr.io/richardr1126/openreader-webui:latest
``` ```
:::tip
If you use a mounted volume for `/app/docstore`, your persisted data remains after image updates.
:::
Visit [http://localhost:3003](http://localhost:3003) after startup. Visit [http://localhost:3003](http://localhost:3003) after startup.

View file

@ -2,6 +2,9 @@
title: Local Development title: Local Development
--- ---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Prerequisites ## Prerequisites
- Node.js (recommended with [nvm](https://github.com/nvm-sh/nvm)) - Node.js (recommended with [nvm](https://github.com/nvm-sh/nvm))
@ -14,10 +17,21 @@ npm install -g pnpm
- A reachable TTS API server - A reachable TTS API server
- [SeaweedFS](https://github.com/seaweedfs/seaweedfs) `weed` binary (required) - [SeaweedFS](https://github.com/seaweedfs/seaweedfs) `weed` binary (required)
<Tabs groupId="seaweedfs-install">
<TabItem value="macos" label="macOS" default>
```bash ```bash
brew install seaweedfs brew install seaweedfs
``` ```
</TabItem>
<TabItem value="linux" label="Linux">
Install the `weed` binary from the [SeaweedFS releases](https://github.com/seaweedfs/seaweedfs/releases) and ensure it is available on `PATH`.
</TabItem>
</Tabs>
Optional, depending on features: Optional, depending on features:
- [libreoffice](https://www.libreoffice.org) (required for DOCX conversion) - [libreoffice](https://www.libreoffice.org) (required for DOCX conversion)
@ -39,7 +53,7 @@ cmake --build build -j --config Release
echo WHISPER_CPP_BIN="$(pwd)/build/bin/whisper-cli" echo WHISPER_CPP_BIN="$(pwd)/build/bin/whisper-cli"
``` ```
:::note :::tip
Set `WHISPER_CPP_BIN` in your `.env` to enable word-by-word highlighting. Set `WHISPER_CPP_BIN` in your `.env` to enable word-by-word highlighting.
::: :::
@ -66,10 +80,8 @@ cp .env.example .env
Then edit `.env`. Then edit `.env`.
Auth is enabled when both are set: - No auth mode: leave `BASE_URL` or `AUTH_SECRET` unset.
- Auth enabled mode: set both `BASE_URL` (typically `http://localhost:3003`) and `AUTH_SECRET` (generate with `openssl rand -base64 32`).
- `BASE_URL` (for local dev, typically `http://localhost:3003`)
- `AUTH_SECRET` (generate with `openssl rand -base64 32`)
Optional: Optional:
@ -77,9 +89,12 @@ Optional:
- Stable S3 credentials via `S3_ACCESS_KEY_ID` and `S3_SECRET_ACCESS_KEY` - Stable S3 credentials via `S3_ACCESS_KEY_ID` and `S3_SECRET_ACCESS_KEY`
- External S3 storage by setting `USE_EMBEDDED_WEED_MINI=false` and related S3 vars - External S3 storage by setting `USE_EMBEDDED_WEED_MINI=false` and related S3 vars
:::info
For all environment variables, see [Environment Variables](../reference/environment-variables). For all environment variables, see [Environment Variables](../reference/environment-variables).
For app/auth behavior, see [Auth](../configure/configuration). :::
For storage configuration, see [Object / Blob Storage](../configure/storage-and-blob-behavior).
For app/auth behavior, see [Auth](../configure/auth).
For storage configuration, see [Object / Blob Storage](../configure/object-blob-storage).
For database mode and migrations, see [Database and Migrations](../configure/database-and-migrations). For database mode and migrations, see [Database and Migrations](../configure/database-and-migrations).
4. Run DB migrations. 4. Run DB migrations.
@ -91,21 +106,32 @@ For database mode and migrations, see [Database and Migrations](../configure/dat
pnpm migrate pnpm migrate
``` ```
:::note :::info
If `POSTGRES_URL` is set, migrations target Postgres; otherwise local SQLite is used. To disable automatic startup migrations, set `RUN_DRIZZLE_MIGRATIONS=false` and/or `RUN_FS_MIGRATIONS=false`. You can run storage migration manually with `pnpm migrate-fs`. If `POSTGRES_URL` is set, migrations target Postgres; otherwise local SQLite is used. To disable automatic startup migrations, set `RUN_DRIZZLE_MIGRATIONS=false` and/or `RUN_FS_MIGRATIONS=false`. You can run storage migration manually with `pnpm migrate-fs`.
::: :::
5. Start the app. 5. Start the app.
<Tabs groupId="local-run-mode">
<TabItem value="dev" label="Dev" default>
```bash ```bash
pnpm dev pnpm dev
``` ```
Or build + start production mode: </TabItem>
<TabItem value="prod" label="Build + Start">
```bash ```bash
pnpm build pnpm build
pnpm start pnpm start
``` ```
</TabItem>
</Tabs>
:::warning API Base Reachability
`API_BASE` must be reachable from the Next.js server process, not just your browser.
:::
Visit [http://localhost:3003](http://localhost:3003). Visit [http://localhost:3003](http://localhost:3003).

View file

@ -2,17 +2,24 @@
title: Vercel Deployment title: Vercel Deployment
--- ---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
This guide covers deploying OpenReader WebUI to Vercel with external Postgres and S3-compatible object storage. This guide covers deploying OpenReader WebUI to Vercel with external Postgres and S3-compatible object storage.
## What works on Vercel ## What works on Vercel
- Documents (PDF/EPUB/TXT/MD) work with `POSTGRES_URL` + external S3 storage. - Documents (PDF/EPUB/TXT/MD) work with `POSTGRES_URL` + external S3 storage.
- Audiobook routes work on Node.js serverless functions using `ffmpeg-static`/`ffprobe-static`. - Audiobook routes work on Node.js serverless functions using `ffmpeg-static`/`ffprobe-static`.
- `docx` conversion requires `soffice` (LibreOffice), which is not available in a standard Vercel runtime.
## 1. Required environment variables :::warning DOCX Conversion Limitation
`docx` conversion requires `soffice` (LibreOffice), which is not available in a standard Vercel runtime.
:::
Set these in your Vercel project: ## 1. Environment Variables
<Tabs groupId="vercel-env-setup">
<TabItem value="required" label="Required" default>
```bash ```bash
POSTGRES_URL=postgres://... POSTGRES_URL=postgres://...
@ -26,7 +33,8 @@ S3_FORCE_PATH_STYLE=true
S3_PREFIX=openreader S3_PREFIX=openreader
``` ```
Optional but common: </TabItem>
<TabItem value="common" label="Common Optional">
```bash ```bash
BASE_URL=https://your-app.vercel.app BASE_URL=https://your-app.vercel.app
@ -36,15 +44,26 @@ NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT=true
NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT=true NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT=true
``` ```
</TabItem>
</Tabs>
:::tip
For all variables and defaults, see [Environment Variables](../reference/environment-variables). For all variables and defaults, see [Environment Variables](../reference/environment-variables).
:::
## 2. FFmpeg/ffprobe packaging in Vercel functions ## 2. FFmpeg/ffprobe packaging in Vercel functions
`ffmpeg-static` and `ffprobe-static` binaries must be included in function traces. This repo already does that in `next.config.ts` via `outputFileTracingIncludes` for: `ffmpeg-static` and `ffprobe-static` binaries must be included in function traces. This repo already does that in `next.config.ts` via `outputFileTracingIncludes` for:
- `/api/audiobook(.*)` - `/api/audiobook`
- `/api/audiobook/chapter`
- `/api/audiobook/status`
- `/api/whisper` - `/api/whisper`
:::info
`serverExternalPackages` should include `ffmpeg-static` and `ffprobe-static` so package paths resolve at runtime instead of being bundled into route output.
:::
If you change route paths or split handlers, update `outputFileTracingIncludes` accordingly. If you change route paths or split handlers, update `outputFileTracingIncludes` accordingly.
## 3. Function memory sizing ## 3. Function memory sizing
@ -66,7 +85,7 @@ Adjust memory per route if your files are larger or your plan differs.
## 4. Runtime expectations and caveats ## 4. Runtime expectations and caveats
- Audiobook APIs require S3 configuration; otherwise they return `503`. - Audiobook APIs require S3 configuration; otherwise they return `503`.
- `better-sqlite3` remains in `serverExternalPackages` for mixed/self-host setups, but production Vercel should use `POSTGRES_URL`. - For production Vercel deploys, use `POSTGRES_URL` instead of SQLite.
- Filesystem-to-object-store migrations run via server scripts/entrypoint (`scripts/migrate-fs-v2.mjs`), not API routes. - Filesystem-to-object-store migrations run via server scripts/entrypoint (`scripts/migrate-fs-v2.mjs`), not API routes.
- Vercel deployments do not run `scripts/openreader-entrypoint.mjs`, so run `pnpm migrate-fs` in a controlled environment when migrating legacy filesystem data. - Vercel deployments do not run `scripts/openreader-entrypoint.mjs`, so run `pnpm migrate-fs` in a controlled environment when migrating legacy filesystem data.

View file

@ -98,7 +98,7 @@ const config: Config = {
{ {
title: 'Community', title: 'Community',
items: [ items: [
{ label: 'Support', to: '/project/support' }, { label: 'Support', to: '/project/support-and-contributing' },
{ label: 'GitHub Discussions', href: 'https://github.com/richardr1126/OpenReader-WebUI/discussions' }, { label: 'GitHub Discussions', href: 'https://github.com/richardr1126/OpenReader-WebUI/discussions' },
{ label: 'Issues', href: 'https://github.com/richardr1126/OpenReader-WebUI/issues' }, { label: 'Issues', href: 'https://github.com/richardr1126/OpenReader-WebUI/issues' },
], ],

View file

@ -21,14 +21,11 @@ const sidebars: SidebarsConfig = {
label: 'Configure', label: 'Configure',
items: [ items: [
'configure/tts-providers', 'configure/tts-providers',
{ 'configure/auth',
type: 'doc',
id: 'configure/configuration',
label: 'Auth (Reccomended)',
},
'configure/tts-rate-limiting', 'configure/tts-rate-limiting',
'configure/database-and-migrations', 'configure/database-and-migrations',
'configure/storage-and-blob-behavior', 'configure/object-blob-storage',
'configure/server-library-import',
], ],
}, },
{ {
@ -45,7 +42,7 @@ const sidebars: SidebarsConfig = {
{ {
type: 'category', type: 'category',
label: 'Project', label: 'Project',
items: ['project/support', 'project/acknowledgements', 'project/license'], items: ['project/support-and-contributing', 'project/acknowledgements', 'project/license'],
}, },
], ],
}; };