App for previewing Door43 Resources in Web and PDF form.
8.6K

A React application for previewing and printing Bible translations, study resources, and Open Bible Stories from the Door43 Content Service (DCS). Generate web previews for online viewing or print-ready PDFs with customizable layouts.
Live App: https://preview.door43.org
Report Bug · Request Feature
Door43 Preview is a web application that fetches Bible translations, translation notes, translation words, study questions, and Open Bible Stories from the Door43 Content Service (DCS) and renders them in two modes:
Built with React 18 + Vite 7, the app uses Proskomma for Scripture processing and PagedJS for print rendering.

Visit the hosted app: https://preview.door43.org
For local development, see the Development section below.
npm install -g pnpm or corepack enable)Copy the example environment file and configure variables:
cp .env.example .env
Edit .env with your values:
# Server-side variables (used by Express at runtime)
PORT=3000 # Server port
CACHE_DIR=./cached-files # Directory for cached content
# DCS API token - allows access to public DCS repos that require authentication
# Create a dummy DCS user with no repos and generate a token with "public_repo" (read-only) scope
# Leave empty if all resources you need are publicly accessible without authentication
DCS_READ_ONLY_TOKEN=
# Verification key - shared secret between client and server
# Client sends this key with cache upload requests; server validates before accepting uploads
# Use any random string (e.g., openssl rand -hex 32)
# This prevents unauthorized users from uploading arbitrary cached content
PREVIEW_VERIFICATION_KEY=
Note: All configuration is provided to the React client at runtime via the /api/config endpoint. No build-time environment variables are needed.
Start the Vite development server with hot module replacement:
pnpm install
pnpm dev
Access: http://localhost:5173
The dev server proxies API requests to http://localhost:3000 (if you run the backend separately for testing caching features).
To test caching and server-side features, run both frontend and backend:
# Terminal 1: Start Express server
pnpm dev:server
# Terminal 2: Start Vite dev server
pnpm dev
pnpm build
This creates optimized production assets in dist/:
pnpm preview
Access: http://localhost:4173
This serves the built dist/ folder for testing.
Start the Express server to serve the built app:
pnpm start
Access: http://localhost:3000
The Express server:
dist//api/save-html-to-cache, /api/get-cached-html)index.html)The app is containerized using Docker with Chainguard's security-hardened Node base image.
Docker Compose manages the entire stack with proper environment variable handling and volume mounting.
Ensure your .env file contains the required variables:
# Get a DCS token by:
# 1. Create a dummy DCS user at https://qa.door43.org
# 2. Go to Settings > Applications > Generate New Token
# 3. Select "public_repo" scope (read-only access to public repositories)
# 4. Copy the token here
DCS_READ_ONLY_TOKEN=your_dcs_token_here
# Generate a random verification key (any random string):
# openssl rand -hex 32
PREVIEW_VERIFICATION_KEY=your_random_verification_key_here
# Build and start in detached mode
docker-compose up -d --build
# View logs
docker-compose logs -f
# Stop and remove containers
docker-compose down
Access: http://localhost:3000
The docker-compose.yml file:
./cached-files as a volume for persistent caching/health endpoint)For manual Docker builds without Compose:
docker build -t door43-preview-app .
No build arguments needed! All configuration is provided at runtime.
docker run -d \
-p 3000:3000 \
-e NODE_ENV=production \
-e PORT=3000 \
-e CACHE_DIR=/app/cached-files \
-e DCS_READ_ONLY_TOKEN="${DCS_READ_ONLY_TOKEN}" \
-e PREVIEW_VERIFICATION_KEY="${PREVIEW_VERIFICATION_KEY}" \
-v "$(pwd)/cached-files:/app/cached-files" \
--name door43-preview \
door43-preview-app
Runtime Environment Variables:
NODE_ENV=production: Enables production modePORT=3000: Server portCACHE_DIR=/app/cached-files: Cache directory pathDCS_READ_ONLY_TOKEN: Optional DCS API token for accessing authenticated repos (create a dummy DCS user with public_repo read-only scope)PREVIEW_VERIFICATION_KEY: Shared secret for validating cache upload requests (prevents unauthorized uploads)# View logs
docker logs -f door43-preview
# Stop container
docker stop door43-preview
# Remove container
docker rm door43-preview
# View container details
docker inspect door43-preview
cgr.dev/chainguard/node:latest (currently Node.js 25.x, security-hardened, minimal attack surface):latest tag (no version-specific tags like :22). Currently points to Node 25, which is compatible with this app. Local development uses Node 22 LTS (see .nvmrc).GET /health returns {"status":"ok","timestamp":"..."}door43-preview-app/
├── src/ # React application source
│ ├── components/ # React components
│ ├── hooks/ # Custom React hooks
│ ├── helpers/ # Utility functions
│ ├── renderer/ # Content rendering logic
│ ├── App.jsx # Root component
│ └── main.jsx # Entry point
├── server/ # Express backend
│ ├── index.js # Server entry point
│ └── routes/ # API route handlers
│ ├── save-html-to-cache.js
│ ├── get-cached-html.js
│ └── serve-cached-page.js
├── public/ # Static assets
├── dist/ # Production build output (generated)
├── cached-files/ # Cache storage (gitignored)
├── docs/ # Additional documentation
│ ├── USAGE.md # User guide
│ └── DEPLOYMENT.md # Deployment details
├── Dockerfile # Docker image definition
├── docker-compose.yml # Docker Compose configuration
├── vite.config.js # Vite build configuration
├── package.json # Dependencies and scripts
├── .env.example # Environment variable template
├── AGENTS.md # Contributor guidelines
└── ARCHITECHTURE.md # Architecture documentation
vite.config.js: Build configuration, path aliases, CommonJS optionsserver/index.js: Express server, API routes, SPA fallbackDockerfile: Multi-stage build with Chainguard Node basedocker-compose.yml: Orchestration with build args and volumes.env.example: Template showing required/optional environment variables# Development
pnpm dev # Start Vite dev server (port 5173)
pnpm dev:server # Start Express server only (port 3000)
# Building
pnpm build # Build React app for production
pnpm preview # Preview production build (port 4173)
# Production
pnpm start # Run Express server with built assets (port 3000)
# Quality
pnpm lint # Run ESLint (fails on errors, allows warnings)
# Docker
pnpm docker:build # Build Docker image with build args
pnpm docker:compose # Start with Docker Compose
The Express server provides these endpoints:
GET /health
Response: {"status":"ok","timestamp":"2025-12-04T..."}
GET /api/config
Response: {
"dcsReadOnlyToken": "...", // DCS API token for accessing authenticated repos
"previewVerificationKey": "..." // Shared secret for cache upload verification
}
Purpose: Provides runtime environment variables to the React client.
Client uses dcsReadOnlyToken for DCS API requests.
Client sends previewVerificationKey with cache uploads for validation.
POST /api/save-html-to-cache?path=u/owner/repo/ref/book.json.gz&verification=KEY
Body: Gzipped JSON data (binary)
Response: {"message":"Cache Success","path":"..."}
Note: The 'verification' parameter must match PREVIEW_VERIFICATION_KEY.
This prevents unauthorized cache uploads from untrusted clients.
GET /api/get-cached-html?path=u/owner/repo/ref/book.json.gz
Response: {"cached":true,"data":{...}} or {"cached":false}
GET /api/cached-page/:owner/:repo/:ref?
Response: Cached book data or 404
Contributions are welcome! See AGENTS.md for contributor guidelines including:
For component development process, see the RCL development guidelines.
git checkout -b feature/amazing-feature)pnpm install)pnpm lint)pnpm build && pnpm preview)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)Having trouble? Get help in the official Open Components Ecosystem Discord.
Distributed under the MIT License. See LICENSE for more information.
Content type
Image
Digest
sha256:93b4e3504…
Size
155.9 MB
Last updated
3 months ago
docker pull unfoldingword/door43-preview-appPulls:
28
Last week