openreader/docs-site/docs/deploy/local-development.md
Richard R 4b26531172 chore(worker): migrate compute worker from Redis/BullMQ to NATS JetStream
Replace Redis and BullMQ with NATS JetStream and KV for job queuing and state management
in the compute worker service. Update environment variables, Docker Compose, and documentation
to reflect the new message queue backend. Adjust dependencies and code to use NATS-based
work queue and key-value storage for durable job processing.

This change improves scalability and reliability of distributed compute workloads by leveraging
NATS JetStream's work queue and persistence features. Documentation and configuration examples
are updated to guide deployments using the new backend.
2026-05-20 07:38:03 -06:00

323 lines
8.3 KiB
Markdown

---
title: Local Development
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Prerequisites
<details>
<summary><strong>Node.js + pnpm (required)</strong></summary>
<Tabs groupId="local-dev-node-pnpm-os">
<TabItem value="macos" label="macOS" default>
```bash
brew install nvm pnpm
mkdir -p ~/.nvm
echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.zshrc
echo '[ -s "$(brew --prefix nvm)/nvm.sh" ] && . "$(brew --prefix nvm)/nvm.sh"' >> ~/.zshrc
source ~/.zshrc
nvm install --lts
nvm use --lts
node -v
pnpm -v
```
</TabItem>
<TabItem value="linux" label="Linux">
```bash
# Debian/Ubuntu example
sudo apt update
sudo apt install -y curl
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
nvm install --lts
nvm use --lts
corepack enable
corepack prepare pnpm@latest --activate
node -v
pnpm -v
```
</TabItem>
</Tabs>
</details>
<details>
<summary><strong>SeaweedFS <code>weed</code> binary (required unless using external S3)</strong></summary>
<Tabs groupId="local-dev-seaweed-os">
<TabItem value="macos" label="macOS" default>
```bash
brew install seaweedfs
weed version
```
:::warning SeaweedFS Compatibility Note (April 16, 2026)
If you see intermittent S3 `InternalError` upload failures with embedded storage, use SeaweedFS `4.18`.
OpenReader currently pins `4.18` in CI and Docker builds while `4.19` compatibility is investigated.
:::
</TabItem>
<TabItem value="linux" label="Linux">
```bash
# Linux amd64 example (pin 4.18)
mkdir -p "$HOME/.local/bin"
curl -fsSL -o /tmp/seaweedfs.tar.gz \
https://github.com/seaweedfs/seaweedfs/releases/download/4.18/linux_amd64.tar.gz
tar -xzf /tmp/seaweedfs.tar.gz -C /tmp weed
install -m 0755 /tmp/weed "$HOME/.local/bin/weed"
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
export PATH="$HOME/.local/bin:$PATH"
weed version
```
:::warning SeaweedFS Compatibility Note (April 16, 2026)
If you see intermittent S3 `InternalError` upload failures with embedded storage, use SeaweedFS `4.18`.
OpenReader currently pins `4.18` in CI and Docker builds while `4.19` compatibility is investigated.
:::
</TabItem>
</Tabs>
</details>
<details>
<summary><strong>LibreOffice (optional, for DOCX conversion)</strong></summary>
<Tabs groupId="local-dev-libreoffice-os">
<TabItem value="macos" label="macOS" default>
```bash
brew install libreoffice
```
</TabItem>
<TabItem value="linux" label="Linux">
```bash
# Debian/Ubuntu example
sudo apt update
sudo apt install -y libreoffice
```
</TabItem>
</Tabs>
</details>
<details>
<summary><strong>Word-by-word highlighting (optional)</strong></summary>
No extra native Whisper CLI build step is required.
Set `COMPUTE_MODE=local` to enable built-in ONNX word alignment in-process.
If you need mirrors or pinned artifact locations, set `WHISPER_MODEL_BASE_URL` in `.env`.
</details>
<details>
<summary><strong>External compute worker dev stack (optional)</strong></summary>
Use this when you want durable compute with NATS JetStream + KV while keeping Next.js on native host `pnpm dev`.
Full worker deployment details are in [Compute Worker (NATS JetStream)](./compute-worker).
Start only NATS + compute-worker via compose watch:
```bash
docker compose --env-file compute/worker/.env -f compute/worker/docker-compose.yml up --watch
# or: pnpm compute:dev:watch
```
`compute/worker/.env.example` contains a starter config. Copy it to `compute/worker/.env` and adjust values for your environment.
Run the main app separately on the host:
```bash
pnpm dev
```
For app server worker mode, set:
```env
COMPUTE_MODE=worker
COMPUTE_WORKER_URL=http://localhost:8081
COMPUTE_WORKER_TOKEN=<same-token-used-by-worker>
```
Worker mode requires worker-reachable shared object storage (S3-compatible endpoint).
Non-exposed embedded `weed mini` is not a supported topology for external worker mode.
</details>
## Steps
### Required flow
1. Clone the repository.
```bash
git clone https://github.com/richardr1126/openreader.git
cd openreader
```
2. Install dependencies.
```bash
pnpm i
```
3. Configure the environment.
```bash
cp .env.example .env
```
Then edit `.env`.
Use one of these `.env` mode templates:
<Tabs groupId="local-env-modes">
<TabItem value="no-auth" label="No Auth (simple)" default>
```env
API_BASE=http://host.docker.internal:8880/v1
API_KEY=none
COMPUTE_MODE=local
# Leave BASE_URL and AUTH_SECRET unset to keep auth disabled.
# (Admin panel is unavailable without auth.)
# API_BASE/API_KEY seed a shared default provider if you want shared mode.
```
</TabItem>
<TabItem value="auth-enabled" label="Auth Enabled">
```env
API_BASE=http://host.docker.internal:8880/v1
API_KEY=none
COMPUTE_MODE=local
BASE_URL=http://localhost:3003
AUTH_SECRET=<generate-with-openssl-rand-hex-32>
# Optional when you need multiple local origins:
# AUTH_TRUSTED_ORIGINS=http://localhost:3003,http://127.0.0.1:3003
```
</TabItem>
<TabItem value="auth-with-admin" label="Auth + Admin Panel">
```env
# API_BASE / API_KEY are seeded into the admin "default-openai" shared provider
# on first boot, then no longer read. Manage them in Settings → Admin afterwards.
API_BASE=http://host.docker.internal:8880/v1
API_KEY=none
COMPUTE_MODE=local
BASE_URL=http://localhost:3003
AUTH_SECRET=<generate-with-openssl-rand-hex-32>
# Comma-separated emails to auto-promote to admin on signin.
ADMIN_EMAILS=you@example.com
```
</TabItem>
<TabItem value="external-s3" label="External S3">
```env
API_BASE=http://host.docker.internal:8880/v1
API_KEY=none
COMPUTE_MODE=local
USE_EMBEDDED_WEED_MINI=false
S3_BUCKET=your-bucket
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
# Optional for non-AWS providers:
# S3_ENDPOINT=https://your-s3-compatible-endpoint
# S3_FORCE_PATH_STYLE=true
```
</TabItem>
<TabItem value="worker-mode" label="External Worker + NATS">
```env
API_BASE=http://host.docker.internal:8880/v1
API_KEY=none
COMPUTE_MODE=worker
COMPUTE_WORKER_URL=http://localhost:8081
COMPUTE_WORKER_TOKEN=<same-token-used-by-worker>
USE_EMBEDDED_WEED_MINI=false
S3_BUCKET=your-bucket
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
# Optional for non-AWS providers:
# S3_ENDPOINT=https://your-s3-compatible-endpoint
# S3_FORCE_PATH_STYLE=true
```
</TabItem>
</Tabs>
:::note Env vars vs. admin panel
On first boot, `API_KEY` / `API_BASE` and any `RUNTIME_SEED_*` flags you've set get auto-seeded into the admin-managed runtime config (DB-backed, keys encrypted at rest). After that, the admin UI is authoritative and editing those env vars no longer changes app behavior. See [Admin Panel](../configure/admin-panel).
:::
:::note User BYOK restriction default
If you want each user to enter personal provider credentials, set `restrictUserApiKeys=false` (from **Settings → Admin** when auth/admin is enabled, or via legacy first-boot seed `RUNTIME_SEED_RESTRICT_USER_API_KEYS=false` for no-admin bootstrap flows).
:::
:::info
For all environment variables, see [Environment Variables](../reference/environment-variables).
:::
See [Auth](../configure/auth) for app/auth behavior.
See [Admin Panel](../configure/admin-panel) for the shared-provider and feature-flag management UI.
Storage configuration details are in [Object / Blob Storage](../configure/object-blob-storage).
Refer to [Database](../configure/database) for database modes.
Learn about migration behavior and commands in [Migrations](../configure/migrations).
4. Start the app.
<Tabs groupId="local-run-mode">
<TabItem value="dev" label="Dev (recommended)" default>
```bash
pnpm dev
```
</TabItem>
<TabItem value="prod" label="Build + Start">
```bash
pnpm build
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).
### Optional workflows
Run manual DB migrations only for troubleshooting or explicit migration workflows:
- Migrations run automatically on startup through the shared entrypoint for both `pnpm dev` and `pnpm start`.
```bash
pnpm migrate
```
:::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`.
:::