No description
Find a file
Elijah e08c55d4c9
Some checks failed
CI / Backend (Python) (push) Successful in 24s
CI / Container (Docker) (push) Has been cancelled
CI / Frontend (TypeScript) (push) Has been cancelled
Enforce LF line endings for shell scripts
2026-08-15 11:21:45 -07:00
.forgejo/workflows Consolidate Docker deployment into a single PaperJet container 2026-08-15 11:07:59 -07:00
backend Consolidate Docker deployment into a single PaperJet container 2026-08-15 11:07:59 -07:00
frontend Consolidate Docker deployment into a single PaperJet container 2026-08-15 11:07:59 -07:00
shared Rescue Paperjet v1 implementation 2026-08-14 21:05:22 -07:00
.dockerignore Consolidate Docker deployment into a single PaperJet container 2026-08-15 11:07:59 -07:00
.env.example Consolidate Docker deployment into a single PaperJet container 2026-08-15 11:07:59 -07:00
.gitattributes Enforce LF line endings for shell scripts 2026-08-15 11:21:45 -07:00
.gitignore Initial commit with Phase 0 Scaffolding 2026-06-10 18:28:17 -07:00
docker-compose.yml Consolidate Docker deployment into a single PaperJet container 2026-08-15 11:07:59 -07:00
docker-entrypoint.sh Consolidate Docker deployment into a single PaperJet container 2026-08-15 11:07:59 -07:00
Dockerfile Consolidate Docker deployment into a single PaperJet container 2026-08-15 11:07:59 -07:00
openapi.json Rescue Paperjet v1 implementation 2026-08-14 21:05:22 -07:00
openapi_pretty.json Rescue Paperjet v1 implementation 2026-08-14 21:05:22 -07:00
Project Architecture.md Consolidate Docker deployment into a single PaperJet container 2026-08-15 11:07:59 -07:00
README.md Consolidate Docker deployment into a single PaperJet container 2026-08-15 11:07:59 -07:00

PaperJet

PaperJet is a self-hosted, single-user PDF annotation editor. It keeps the uploaded PDF immutable, stores annotations separately, autosaves the working layer, and flattens supported annotations only when exporting.

Run with Docker

  1. Copy .env.example to .env.
  2. Replace SECRET_KEY with a long random value. Compose refuses to start without it.
  3. Build and start the single-container application:
docker compose up --build -d

The container serves the React application through nginx and proxies /api requests to the loopback-only FastAPI process. Open http://localhost:4982 (or the value of HTTP_PORT). The first visit asks you to create the single master password.

The db, pdf_storage, and thumbnails volumes contain application data. Back them up before maintenance or upgrades. Put the frontend behind HTTPS when exposing PaperJet beyond localhost and set COOKIE_SECURE=true.

Run a Forgejo-published image

Set PAPERJET_IMAGE in .env to the desired registry tag, for example the latest or commit-SHA tag published by Forgejo. Then pull and start without building locally:

docker compose pull
docker compose up -d --no-build

The published image exposes only port 80. Your outer reverse proxy should target the Compose port configured by HTTP_PORT.

Development

Backend:

cd backend
pip install -e ".[dev]"
uvicorn app.main:app --reload

Frontend, in a second terminal:

cd frontend
npm ci
npm run dev

The Vite server proxies /api to http://localhost:8000.

Validation

# container
docker compose --env-file .env.example config --quiet
docker compose up --build -d
curl http://localhost:4982/api/v1/health
docker compose ps

# frontend
cd frontend
npm test -- --run
npm run typecheck
npm run lint
npm run build

# backend
cd ../backend
pytest -q
mypy app/
ruff check .

Stop the local stack with docker compose down. Do not use -v unless you intend to remove the local application volumes.

The editor uses PDF.js for display and PyMuPDF for export. Stored annotation coordinates are PDF points with a top-left origin relative to the unrotated CropBox; this is the contract shared by the editor and export renderer.