# Stirling-PDF Administrator & Developer Guide

Stirling-PDF is a self-hosted, enterprise-capable PDF manipulation platform built on a multi-module architecture spanning Java (Spring Boot), TypeScript (React/Mantine), Rust (Tauri), and Python (FastAPI). This guide covers every operational and development concern for administrators, DevOps engineers, and contributors working with Stirling-PDF version **2.9.2**.

---

## 1. Architecture Overview

Stirling-PDF follows a modular monorepo structure with four distinct runtime components that can be deployed together or independently.

### 1.1 Component Map

```
┌─────────────────────────────────────────────────────────────┐
│                     Stirling-PDF v2.9.2                      │
├──────────────┬──────────────┬───────────────┬───────────────┤
│   Backend    │   Frontend   │    Desktop    │   AI Engine   │
│ Spring Boot  │ React/Vite   │  Tauri/Rust   │ Python/FastAPI│
│  4.0.5       │ Mantine UI   │              │  pydantic-ai  │
│  Java 21     │ TypeScript   │              │              │
├──────────────┼──────────────┼───────────────┼───────────────┤
│  app/common  │ frontend/src │ frontend/    │ engine/src/   │
│  app/core    │   /core      │  src-tauri/  │  stirling/    │
│  app/        │   /proprietary│             │   api/        │
│  proprietary │   /saas      │              │   agents/     │
│              │   /desktop   │              │              │
└──────────────┴──────────────┴───────────────┴───────────────┘
```

### 1.2 Backend Modules

The Spring Boot backend is split into three Gradle subprojects:

| Module | Path | Purpose |
|---|---|---|
| **common** | `app/common/` | Shared models, configuration classes, annotations, cross-cutting services (`TaskManager`, `FileStorage`, `EndpointConfiguration`) |
| **core** | `app/core/` | All PDF operation controllers (19 controller files), core configuration (19 config files), PDF manipulation via Apache PDFBox 3.0.7 |
| **proprietary** | `app/proprietary/` | Enterprise features: OAuth2, SAML2, SSO, user/role management, audit logging, workflows. Licensed under Stirling PDF User License |

The application entry point is `stirling.software.SPDF.SPDFApplication`. The embedded servlet container is **not** Tomcat — the build explicitly excludes `spring-boot-starter-tomcat` in favor of Jetty/Undertow.

### 1.3 Frontend Architecture

The React frontend uses Vite as the build tool and is organized into four feature domains:

| Domain | Path | Contents |
|---|---|---|
| **core** | `frontend/src/core/` | 47 service files, 49 utility files, page editor with undo/redo command pattern, PDFium WASM rendering, i18n (40+ locales) |
| **proprietary** | `frontend/src/proprietary/` | Auth flows, Stripe checkout, workflow builder, enterprise configuration UI |
| **saas** | `frontend/src/saas/` | SaaS deployment: onboarding, billing, PostHog analytics |
| **desktop** | `frontend/src/desktop/` | Tauri bridge services, backend health monitoring, connection mode management, operation routing |

> [!NOTE]
> The frontend uses **PDFium compiled to WebAssembly** for client-side PDF rendering and manipulation. This means many operations execute entirely in the browser without round-tripping to the backend.

### 1.4 Desktop Application (Tauri)

The desktop app wraps the React frontend in a native Rust shell (`frontend/src-tauri/`). Tauri commands expose:

- **Auth**: save/get/clear tokens for enterprise auth
- **Backend management**: spawn, monitor, and manage a local backend process
- **Connection modes**: local backend, remote server, or hybrid
- **File handling**: native file dialogs, drag-and-drop, default PDF handler registration
- **Native print**: OS-level print integration
- **Platform detection**: Windows/macOS/Linux-specific behavior

A Windows thumbnail handler DLL (`stirling_thumbnail_handler.dll`) implements the COM `IThumbnailProvider` interface, enabling PDF preview thumbnails directly in Windows Explorer. A provisioner tool supports enterprise deployment by locking the server URL in configuration.

### 1.5 AI Engine

The Python FastAPI service (`engine/src/stirling/api/app.py`) provides AI-powered PDF operations using `pydantic-ai`:

| Agent | Role |
|---|---|
| `OrchestratorAgent` | Routes user natural-language requests to the correct tool/agent |
| `PdfEditAgent` | AI-guided PDF editing based on user instructions |
| `PdfQuestionAgent` | Answers questions about PDF content |
| `UserSpecAgent` | Drafts and revises user specifications from requirements |
| `ExecutionPlanningAgent` | Plans multi-step PDF operation sequences |
| `MathAuditorAgent` | Audits financial/math PDFs, verifies ledger entries |

API routes: `/draft`, `/revise`, `/next-action`, `/examine`, `/deliberate`, `/orchestrate`, `/pdf_edit`, `/pdf_questions`, `/health`.

### 1.6 Dependency Stack

| Layer | Technology | Version |
|---|---|---|
| JVM | Java | 21 (source/target), 25 (compilation toolchain) |
| Framework | Spring Boot | 4.0.5 |
| PDF manipulation | Apache PDFBox | 3.0.7 |
| Cryptography | BouncyCastle | 1.83 |
| Image I/O | TwelveMonkeys imageio | 3.13.1 |
| Code generation | Lombok | 1.18.44 |
| SAML | Spring Security SAML | 7.0.4 |
| SAML (impl) | OpenSAML | 5.2.1 |
| Markdown | Commonmark | 0.28.0 |
| Frontend framework | React + Mantine UI | — |
| Frontend build | Vite | — |
| Frontend routing | React Router | — |
| Frontend i18n | i18next | — |
| Desktop | Tauri | — |
| AI runtime | FastAPI + pydantic-ai | — |

---

## 2. Requirements & Prerequisites

### 2.1 Hardware Requirements

| Deployment | CPU | RAM | Disk |
|---|---|---|---|
| Ultra-lite (Java-only ops) | 1 core | 512 MB | 500 MB |
| Standard (with external tools) | 2 cores | 2 GB | 2 GB |
| Fat (all dependencies) | 2+ cores | 4 GB | 5 GB |
| With AI engine | 2+ cores | 4+ GB | 6 GB |

### 2.2 Software Requirements

**For Docker deployment (recommended):**
- Docker Engine 20.10+
- Docker Compose v2

**For bare-metal / development:**
- Java 21 JDK (compilation requires Java 25 toolchain)
- Node.js (for frontend build)
- Gradle (wrapper included)
- Optional external tools: LibreOffice, qpdf, Ghostscript, Tesseract OCR, OpenCV, Python 3.x, unoconvert

> [!IMPORTANT]
> The fat Docker image bundles all external tools. The standard image requires you to install LibreOffice, Tesseract, and other CLI tools separately if you need endpoints that depend on them. The ultra-lite image intentionally excludes all external dependencies.

---

## 3. Configuration Mastery

### 3.1 settings.yml

The primary configuration file is mounted at `/configs/settings.yml` inside the container. It controls all runtime behavior. Configuration keys map to Spring properties via relaxed binding.

### 3.2 Environment Variables — Complete Reference

All configuration can be set via environment variables, which override `settings.yml` values.

#### System Configuration

| Variable | Default | Description |
|---|---|---|
| `SYSTEM_DEFAULTLOCALE` | `en-US` | Default UI language. Supports 40+ locales |
| `SYSTEM_MAXFILESIZE` | `100` | Maximum upload file size in megabytes |
| `SYSTEM_ROOTURIPATH` | _(empty)_ | Base URI path for reverse proxy deployments (e.g., `/stirling-pdf`) |
| `SYSTEM_GOOGLEVISIBILITY` | `false` | When `true`, allows search engine indexing via robots.txt |
| `SYSTEM_ENABLEMOBILESCANNER` | _(unset)_ | Enables mobile document scanner via WebRTC camera access |

#### Security Configuration

| Variable | Default | Description |
|---|---|---|
| `DOCKER_ENABLE_SECURITY` | `false` | Master switch for security features (OAuth2, SAML2, user management) |
| `SECURITY_ENABLELOGIN` | `false` | Enables the login page and session-based authentication |
| `SECURITY_CUSTOMGLOBALAPIKEY` | _(unset)_ | Sets a global API key accepted via `X-API-KEY` header for all requests |

#### UI Configuration

| Variable | Default | Description |
|---|---|---|
| `UI_APPNAME` | `Stirling-PDF` | Application name displayed in the UI |
| `UI_HOMEDESCRIPTION` | _(unset)_ | Custom homepage description text |
| `UI_APPNAMENAVBAR` | _(unset)_ | Custom name in the navigation bar (overrides `UI_APPNAME` in navbar only) |

#### Container & Process Configuration

| Variable | Default | Description |
|---|---|---|
| `MODE` | `BOTH` | Container operating mode: `BOTH` (full stack), `FRONTEND` (UI only), `BACKEND` (API only) |
| `BACKEND_INTERNAL_PORT` | `8081` | Internal backend port when `MODE=BOTH` |
| `VITE_API_BASE_URL` | _(unset)_ | Backend URL when running frontend-only (`MODE=FRONTEND`) |
| `PUID` | `1000` | Process user ID inside container |
| `PGID` | `1000` | Process group ID inside container |
| `UMASK` | `022` | File creation mask |
| `JAVA_CUSTOM_OPTS` | _(unset)_ | Additional JVM flags passed to the Java process |
| `STIRLING_JVM_PROFILE` | `balanced` | JVM tuning profile: `balanced` (G1GC) or `performance` (Shenandoah GC) |
| `FAT_DOCKER` | `false` | Set `true` when using the fat Docker image to enable all tool-dependent endpoints |

#### Feature Toggles

| Variable | Default | Description |
|---|---|---|
| `DISABLE_ADDITIONAL_FEATURES` | `false` | When `true`, disables all endpoints requiring external CLI tools |
| `ENDPOINTS_GROUPS_TO_REMOVE` | _(unset)_ | Comma-separated list of endpoint groups to disable (e.g., `CLI,Python,OpenCV`) |
| `METRICS_ENABLED` | `true` | Enables Prometheus-compatible metrics endpoint |
| `SHOW_SURVEY` | _(unset)_ | Shows feedback survey prompt in the UI |

#### OCR & Language Configuration

| Variable | Default | Description |
|---|---|---|
| `TESSERACT_LANGS` | _(unset)_ | Comma-separated Tesseract OCR language codes to install (e.g., `eng,fra,deu`) |
| `LANGS` | _(unset)_ | Supported UI languages |

#### Storage Configuration

| Variable | Default | Description |
|---|---|---|
| `STORAGE_LOCAL_BASEPATH` | _(unset)_ | Base filesystem path for local file storage (enterprise feature) |

#### LibreOffice / UNO Server Configuration

| Variable | Default | Description |
|---|---|---|
| `PROCESS_EXECUTOR_AUTO_UNO_SERVER` | `true` | Automatically starts a local UNO server for LibreOffice operations |
| `PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_N_HOST` | _(unset)_ | Hostname of remote UNO server endpoint (N = 0, 1, 2, ...) |
| `PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_N_PORT` | `2003` | Port for remote UNO server endpoint |
| `PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_N_HOST_LOCATION` | _(unset)_ | Set to `remote` for remote UNO servers |
| `PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_N_PROTOCOL` | `http` | Protocol for UNO server communication |
| `PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT` | _(unset)_ | Maximum concurrent LibreOffice conversion sessions |

#### AI Engine Configuration

| Variable | Default | Description |
|---|---|---|
| `STIRLING_SMART_MODEL` | _(unset)_ | AI model for complex reasoning tasks (e.g., `gpt-4`) |
| `STIRLING_FAST_MODEL` | _(unset)_ | AI model for quick tasks (e.g., `gpt-3.5-turbo`) |
| `STIRLING_SMART_MODEL_MAX_TOKENS` | _(unset)_ | Max output tokens for smart model |
| `STIRLING_FAST_MODEL_MAX_TOKENS` | _(unset)_ | Max output tokens for fast model |
| `STIRLING_LOG_LEVEL` | _(unset)_ | Engine log level |
| `STIRLING_LOG_FILE` | _(unset)_ | Engine log file path |
| `STIRLING_POSTHOG_ENABLED` | _(unset)_ | Enable PostHog telemetry in AI engine |
| `STIRLING_POSTHOG_API_KEY` | _(unset)_ | PostHog project API key |
| `STIRLING_POSTHOG_HOST` | _(unset)_ | PostHog instance URL |

> [!TIP]
> For resource-constrained environments, set `STIRLING_JVM_PROFILE=balanced` and `PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT=1` to prevent LibreOffice from consuming excessive memory during concurrent conversions.

### 3.3 Volume Mounts

| Container Path | Purpose | Required |
|---|---|---|
| `/configs` | `settings.yml` and configuration files | Recommended |
| `/logs` | Application log output | Recommended |
| `/usr/share/tessdata` | Tesseract OCR language data files | Only for OCR |
| `/customFiles` | UI customization assets (logos, CSS overrides) | Optional |
| `/pipeline` | Pipeline/automation configuration files | Optional |
| `/tmp/stirling-pdf` | Shared temp directory for remote UNO server operations | Only for remote UNO |

---

## 4. Deployment

### 4.1 Docker Images

Stirling-PDF provides four Dockerfile variants targeting different use cases:

| Variant | Dockerfile | Size | External Tools | Use Case |
|---|---|---|---|---|
| **Standard** | `Dockerfile` | ~800 MB | Some (configurable) | General purpose |
| **Fat** | `Dockerfile.fat` | ~2.5 GB | All bundled | Full feature set, no external deps to manage |
| **Ultra-lite** | `Dockerfile.ultra-lite` | ~300 MB | None | Java-only PDF operations, minimal footprint |
| **Unified** | `Dockerfile.unified` | Varies | Configurable | Split frontend/backend or combined via `MODE` env var |

### 4.2 Standard Deployment (Docker Compose)

```yaml
version: "3.8"
services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest
    ports:
      - "8080:8080"
    volumes:
      - ./configs:/configs
      - ./logs:/logs
      - ./customFiles:/customFiles
    environment:
      - DOCKER_ENABLE_SECURITY=false
      - SYSTEM_MAXFILESIZE=100
      - SYSTEM_DEFAULTLOCALE=en-US
    restart: unless-stopped
```

### 4.3 Fat Docker Deployment

```yaml
version: "3.8"
services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest-fat
    ports:
      - "8080:8080"
    volumes:
      - ./configs:/configs
      - ./logs:/logs
      - ./tessdata:/usr/share/tessdata
      - ./pipeline:/pipeline
    environment:
      - FAT_DOCKER=true
      - TESSERACT_LANGS=eng,fra,deu,spa
      - SYSTEM_MAXFILESIZE=500
    restart: unless-stopped
```

> [!NOTE]
> The fat image bundles LibreOffice, Tesseract, qpdf, Ghostscript, OpenCV, and Python. Set `FAT_DOCKER=true` so the endpoint configuration system knows all tool dependencies are satisfied.

### 4.4 Ultra-lite Deployment

```yaml
version: "3.8"
services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest-ultra-lite
    ports:
      - "8080:8080"
    volumes:
      - ./configs:/configs
    environment:
      - DISABLE_ADDITIONAL_FEATURES=true
    restart: unless-stopped
```

The ultra-lite image supports only Java-native PDF operations: merge, split, rotate, rearrange, remove pages, add watermark, encrypt/decrypt, metadata editing, flatten, and similar operations that use PDFBox directly without external CLI tools.

### 4.5 Unified Container — Split Frontend/Backend

The unified Dockerfile supports three operating modes via the `MODE` environment variable:

**Mode: BOTH (default)** — runs frontend and backend in a single container:

```yaml
services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:unified
    environment:
      - MODE=BOTH
      - BACKEND_INTERNAL_PORT=8081
    ports:
      - "8080:8080"
```

**Mode: FRONTEND** — serves only the React UI, proxying API calls to a separate backend:

```yaml
services:
  frontend:
    image: stirlingtools/stirling-pdf:unified
    environment:
      - MODE=FRONTEND
      - VITE_API_BASE_URL=http://backend:8080
    ports:
      - "3000:3000"
```

**Mode: BACKEND** — runs only the Spring Boot API:

```yaml
services:
  backend:
    image: stirlingtools/stirling-pdf:unified
    environment:
      - MODE=BACKEND
    ports:
      - "8080:8080"
    volumes:
      - ./configs:/configs
      - ./logs:/logs
```

**Full split deployment example:**

```yaml
version: "3.8"
services:
  backend:
    image: stirlingtools/stirling-pdf:unified
    environment:
      - MODE=BACKEND
      - DOCKER_ENABLE_SECURITY=true
      - SECURITY_ENABLELOGIN=true
    ports:
      - "8080:8080"
    volumes:
      - ./configs:/configs
      - ./logs:/logs
      - ./tessdata:/usr/share/tessdata

  frontend:
    image: stirlingtools/stirling-pdf:unified
    environment:
      - MODE=FRONTEND
      - VITE_API_BASE_URL=http://backend:8080
    ports:
      - "3000:3000"
    depends_on:
      - backend
```

> [!IMPORTANT]
> When using `MODE=FRONTEND`, the `VITE_API_BASE_URL` must be set at **build time** or via the unified container's entrypoint script. This URL is baked into the frontend JavaScript bundle. Changing it requires a container restart.

### 4.6 Remote UNO Server (Scalable LibreOffice)

For high-throughput document conversion, deploy LibreOffice as remote UNO servers to distribute the load:

```yaml
version: "3.8"
services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest
    environment:
      - PROCESS_EXECUTOR_AUTO_UNO_SERVER=false
      - PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_HOST=uno-server-1
      - PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_PORT=2003
      - PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_HOST_LOCATION=remote
      - PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_PROTOCOL=http
      - PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_HOST=uno-server-2
      - PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_PORT=2003
      - PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_HOST_LOCATION=remote
      - PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_PROTOCOL=http
    volumes:
      - shared-tmp:/tmp/stirling-pdf
    ports:
      - "8080:8080"

  uno-server-1:
    image: libreoffice-uno-server:latest
    volumes:
      - shared-tmp:/tmp/stirling-pdf

  uno-server-2:
    image: libreoffice-uno-server:latest
    volumes:
      - shared-tmp:/tmp/stirling-pdf

volumes:
  shared-tmp:
```

> [!WARNING]
> Remote UNO servers require a **shared `/tmp/stirling-pdf` volume** between the Stirling-PDF container and all UNO server containers. Without this shared filesystem, file-to-pdf and other LibreOffice-dependent conversions will fail silently because the UNO server cannot access the temporary files created by Stirling-PDF.

Key configuration:
- Set `PROCESS_EXECUTOR_AUTO_UNO_SERVER=false` to disable the local UNO server
- Configure each remote endpoint with incrementing index (`_0_`, `_1_`, etc.)
- Set `HOST_LOCATION=remote` for each remote endpoint
- Use `PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT` to cap concurrent sessions per server

### 4.7 Reverse Proxy Configuration

When deploying behind a reverse proxy (Nginx, Traefik, Caddy), set `SYSTEM_ROOTURIPATH` to match the proxy's path prefix.

**Nginx example (subpath):**

```nginx
location /stirling-pdf/ {
    proxy_pass http://stirling-pdf:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    client_max_body_size 100M;  # Match SYSTEM_MAXFILESIZE
}
```

With environment: `SYSTEM_ROOTURIPATH=/stirling-pdf`

**Traefik example (subdomain):**

```yaml
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.stirling.rule=Host(`pdf.example.com`)"
  - "traefik.http.routers.stirling.tls.certresolver=letsencrypt"
  - "traefik.http.services.stirling.loadbalancer.server.port=8080"
```

### 4.8 Health Check

The container health check endpoint:

```bash
curl -f http://localhost:8080${SYSTEM_ROOTURIPATH:-''}/api/v1/info/status | grep -q 'UP'
```

Docker Compose health check configuration:

```yaml
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8080/api/v1/info/status"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 60s
```

---

## 5. Endpoint Configuration System

The `EndpointConfiguration` class (in `app/common`) is the central mechanism for controlling which PDF operations are available at runtime. It evaluates three factors: explicit configuration, external tool availability, and group membership.

### 5.1 Functional Groups

Endpoints are organized into functional groups. Disabling a group disables all its member endpoints:

| Group | Endpoints | Count |
|---|---|---|
| **PageOps** | remove-pages, merge-pdfs, split-pages, rearrange-pages, rotate-pdf, multi-page-layout, booklet-imposition, scale-pages, crop, pdf-to-single-page, auto-split-pdf, split-by-size-or-count, overlay-pdf, split-pdf-by-sections, split-pdf-by-chapters, add-page-numbers, extract-pages | 17 |
| **Convert** | pdf-to-img, img-to-pdf, pdf-to-pdfa, file-to-pdf, pdf-to-word, pdf-to-presentation, pdf-to-text, pdf-to-html, pdf-to-xml, html-to-pdf, url-to-pdf, markdown-to-pdf, pdf-to-csv, pdf-to-markdown, eml-to-pdf, pdf-to-epub, pdf-to-vector, vector-to-pdf, pdf-to-video, cbz-to-pdf, pdf-to-cbz, pdf-to-json, json-to-pdf, pdf-to-rtf | 24 |
| **Security** | add-password, remove-password, change-permissions, add-watermark, cert-sign, remove-cert-sign, sanitize-pdf, timestamp-pdf, auto-redact, validate-signature, add-stamp, unlock-pdf-forms, redact, verify-pdf, sign | 15 |
| **Other** | ocr-pdf, extract-images, update-metadata, flatten, remove-blanks, remove-annotations, get-info-on-pdf, add-attachments, replace-invert-pdf, edit-table-of-contents, text-editor-pdf, add-image, compare, view-pdf, multi-tool, fields, modify-fields, delete-fields, fill | 19 |
| **Advance** | compress-pdf, extract-image-scans, repair, auto-rename, scanner-effect, overlay-pdf, adjust-contrast | 7 |
| **Automation** | handleData, automate, pipeline | 3 |
| **DeveloperTools** | show-javascript | 1 |
| **DeveloperDocs** | dev-api-docs, dev-folder-scanning-docs, dev-sso-guide-docs, dev-airgapped-docs | 4 |

### 5.2 Tool Groups (External Dependencies)

Each tool group maps endpoints to the external binary they require:

| Tool Group | Required Binary | Dependent Endpoints |
|---|---|---|
| **CLI** | qpdf, Ghostscript, etc. | compress-pdf, extract-image-scans, repair, pdf-to-pdfa, file-to-pdf, pdf-to-word, pdf-to-presentation, pdf-to-html, pdf-to-xml, ocr-pdf, html-to-pdf, url-to-pdf, pdf-to-rtf |
| **Python** | Python 3.x | extract-image-scans, html-to-pdf, url-to-pdf, file-to-pdf |
| **OpenCV** | OpenCV libraries | extract-image-scans |
| **LibreOffice** | LibreOffice (soffice) | file-to-pdf, pdf-to-word, pdf-to-presentation, pdf-to-rtf, pdf-to-html, pdf-to-xml, pdf-to-pdfa |
| **Unoconvert** | unoconvert | file-to-pdf (alternative to LibreOffice) |
| **Java** | Built-in (JVM) | 50+ endpoints — no external dependency |

### 5.3 Disable Reasons

When an endpoint is unavailable, the system reports one of three reasons:

| Reason | Meaning |
|---|---|
| `CONFIG` | Explicitly disabled via `settings.yml` or `ENDPOINTS_GROUPS_TO_REMOVE` |
| `DEPENDENCY` | Required external tool is not installed or not found on PATH |
| `UNKNOWN` | Disabled for an unidentified reason |

### 5.4 Endpoint Alternatives

Some endpoints support multiple backends. For example, `file-to-pdf` can use either LibreOffice or Unoconvert. If one tool is missing, the system falls back to the alternative if available.

### 5.5 Disabling Endpoints

**Disable entire functional groups:**

```yaml
# In settings.yml
endpoints:
  groupsToRemove:
    - CLI
    - Python
```

Or via environment variable:

```bash
ENDPOINTS_GROUPS_TO_REMOVE=CLI,Python
```

**Disable all external-tool features at once:**

```bash
DISABLE_ADDITIONAL_FEATURES=true
```

**Disable individual endpoints in settings.yml:**

```yaml
endpoints:
  disabled:
    - ocr-pdf
    - compress-pdf
```

---

## 6. Security

### 6.1 Authentication Modes

Stirling-PDF supports multiple authentication mechanisms, all gated behind the `DOCKER_ENABLE_SECURITY=true` master switch:

| Mode | Module | Configuration |
|---|---|---|
| **Local login** | proprietary | `SECURITY_ENABLELOGIN=true` — session-based username/password auth |
| **OAuth2** | proprietary | Spring Security OAuth2 client configuration |
| **SAML2 SSO** | proprietary | Spring Security SAML 7.0.4 + OpenSAML 5.2.1 |
| **API key** | core/proprietary | `X-API-KEY` header — per-user or global (`SECURITY_CUSTOMGLOBALAPIKEY`) |
| **MFA** | proprietary | TOTP-based multi-factor authentication |

> [!CAUTION]
> Setting `SECURITY_CUSTOMGLOBALAPIKEY` creates a single shared API key for **all** API access. This is convenient for automation but bypasses per-user audit trails. In production, prefer per-user API keys issued through the user management system.

### 6.2 CSRF Protection

Spring Security CSRF protection is enabled by default when security is active. API endpoints that accept the `X-API-KEY` header bypass CSRF checks (they are stateless by nature).

### 6.3 User & Role Management

The proprietary module provides:
- User creation, modification, deletion
- Role-based access control
- Session management (timeout, concurrent session limits)
- Audit logging of user actions

### 6.4 Security Hardening Checklist

```
[ ] Set DOCKER_ENABLE_SECURITY=true
[ ] Enable login: SECURITY_ENABLELOGIN=true
[ ] Configure OAuth2 or SAML2 for SSO
[ ] Set per-user API keys (avoid global key in production)
[ ] Enable MFA for admin accounts
[ ] Set SYSTEM_MAXFILESIZE to prevent abuse
[ ] Deploy behind reverse proxy with TLS
[ ] Set SYSTEM_GOOGLEVISIBILITY=false to prevent indexing
[ ] Mount /configs read-only if settings won't change at runtime
[ ] Review audit logs regularly
```

---

## 7. Operations

### 7.1 JVM Tuning

Two JVM profiles are available via `STIRLING_JVM_PROFILE`:

| Profile | GC Algorithm | Best For |
|---|---|---|
| `balanced` (default) | G1GC | General workloads, predictable pause times |
| `performance` | Shenandoah GC | Low-latency requirements, large heaps |

Additional tuning via `JAVA_CUSTOM_OPTS`:

```bash
# Example: increase heap for large PDF processing
JAVA_CUSTOM_OPTS="-Xmx4g -Xms2g -XX:+HeapDumpOnOutOfMemoryError"
```

### 7.2 Logging

Application logs are written to the `/logs` volume mount. Configure log levels via Spring Boot properties in `settings.yml` or environment variables.

For the AI engine, use `STIRLING_LOG_LEVEL` and optionally `STIRLING_LOG_FILE`.

### 7.3 Metrics

When `METRICS_ENABLED=true` (default), Stirling-PDF exposes Prometheus-compatible metrics. Integrate with Grafana for dashboarding:

```yaml
# prometheus.yml scrape config
- job_name: 'stirling-pdf'
  metrics_path: '/actuator/prometheus'
  static_configs:
    - targets: ['stirling-pdf:8080']
```

### 7.4 Backup & Restore

Critical data to back up:

| Path | Contents | Frequency |
|---|---|---|
| `/configs/settings.yml` | All runtime configuration | On change |
| `/configs/` | User database (if security enabled) | Daily |
| `/customFiles/` | UI branding assets | On change |
| `/pipeline/` | Automation pipeline definitions | On change |
| `/usr/share/tessdata/` | OCR language data | On change |

### 7.5 Scaling Considerations

**Horizontal scaling** is supported via the unified container's split mode:

```
                    ┌─── Frontend (MODE=FRONTEND) ──┐
Load Balancer ──────┤                                ├──► Backend Pool
                    └─── Frontend (MODE=FRONTEND) ──┘     (MODE=BACKEND)
                                                          ├── instance-1
                                                          ├── instance-2
                                                          └── instance-3
```

> [!TIP]
> LibreOffice is the primary bottleneck in high-throughput deployments. Use remote UNO servers (Section 4.6) to scale document conversion independently from the core PDF operations. Set `PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT` to prevent a single instance from being overwhelmed.

### 7.6 OCR Language Management

Tesseract OCR languages are installed via `TESSERACT_LANGS`:

```bash
# Install multiple languages
TESSERACT_LANGS=eng,fra,deu,spa,ita,por,jpn,chi_sim,chi_tra,kor,ara

# Mount custom/additional traineddata files
volumes:
  - ./tessdata:/usr/share/tessdata
```

Language data files (`.traineddata`) can be downloaded from the [tessdata repository](https://github.com/tesseract-ocr/tessdata) and placed in the mounted volume.

---

## 8. Developer Reference

### 8.1 Build System

The project uses Gradle with the Spring Boot plugin:

```bash
# Build everything
./gradlew build

# Build backend only
./gradlew :app:core:build

# Run locally
./gradlew bootRun

# Run with specific profile
./gradlew bootRun --args='--spring.profiles.active=dev'
```

**Build configuration:**
- Java source/target: Java 21
- Compilation toolchain: Java 25
- Code formatter: Spotless (google-java-format 1.28.0)
- Code coverage: JaCoCo
- Static analysis: SonarQube integration
- License compliance: dependency-license-report plugin

**Version sync:** The `syncAppVersion` Gradle task synchronizes the version number across `tauri.conf.json` and simulation configuration files.

### 8.2 Frontend Build

```bash
cd frontend

# Install dependencies
npm install

# Development server
npm run dev

# Production build
npm run build

# Run tests
npm run test        # Vitest unit tests
npm run test:e2e    # Playwright E2E tests
```

### 8.3 AI Engine Development

```bash
cd engine

# Install dependencies
pip install -r requirements.txt

# Run locally
uvicorn stirling.api.app:app --reload --port 8000

# Run tests
pytest tests/
```

### 8.4 Code Formatting

Spotless enforces google-java-format 1.28.0:

```bash
# Check formatting
./gradlew spotlessCheck

# Auto-fix formatting
./gradlew spotlessApply
```

> [!NOTE]
> The Spotless check runs as part of the build pipeline. Pull requests with formatting violations will fail CI. Run `spotlessApply` before committing.

---

## 9. Module Reference

### 9.1 Backend — app/common

Shared library consumed by both `core` and `proprietary`:

| Class / Service | Purpose |
|---|---|
| `EndpointConfiguration` | Runtime endpoint availability management (groups, tools, alternatives) |
| `TaskManager` | Manages async task execution and progress tracking |
| `FileStorage` | Abstraction over file storage backends |
| Annotation classes | Custom annotations for endpoint metadata, validation |
| Model classes | Shared DTOs and domain models |

### 9.2 Backend — app/core

The core module contains all PDF operation implementations:

**Controllers** (`app/core/src/main/java/stirling/software/SPDF/controller/api/`):
19 controller files totaling ~201K characters of endpoint logic. Controllers are organized by functional domain (page operations, conversions, security, etc.) and delegate to service classes that use PDFBox for manipulation.

**Configuration** (`app/core/.../config/`):
19 configuration files handling Spring context setup, bean definitions, security filter chains, CORS, multipart file upload limits, and static resource serving.

**Entry Point**: `stirling.software.SPDF.SPDFApplication` — the `@SpringBootApplication` main class.

### 9.3 Backend — app/proprietary

Enterprise features under separate license:

| Domain | Contents |
|---|---|
| **Security** | OAuth2 client configuration, SAML2 service provider, SSO flow management |
| **User management** | User CRUD, role assignment, session management, MFA enrollment |
| **Storage** | Enterprise file storage backends |
| **Workflows** | Multi-step PDF processing workflows |
| **Audit** | Action logging, compliance reporting |

### 9.4 Frontend Services

| Service | Module | Purpose |
|---|---|---|
| `AutomationStorage` | core | Persist and retrieve automation/pipeline configurations |
| `DocumentManipulationService` | core | High-level document manipulation orchestration |
| `EnhancedPDFProcessingService` | core | Advanced PDF processing with progress tracking |
| `FileAnalyzer` | core | Analyze uploaded files (type detection, validation) |
| `FileProcessingService` | core | File upload, processing pipeline, result download |
| `FileStorageService` | core | Client-side file storage (IndexedDB) |
| `GoogleDrivePickerService` | core | Google Drive integration for file import |
| `IndexedDBManager` | core | IndexedDB wrapper for persistent browser storage |
| `PDFExportService` | core | Export PDFs in various formats |
| `PDFProcessingService` | core | Core PDF operations via PDFium WASM |
| `PdfiumDocument` / `PdfiumPage` / `PdfiumFont` / `PdfiumImage` | core | PDFium WASM bindings for client-side rendering |
| `PreferencesService` | core | User preference management |
| `ProcessingCache` | core | Cache intermediate processing results |
| `SignatureStorageService` | core | Store and manage digital signature data |
| `ThumbnailGenerationService` | core | Generate PDF page thumbnails |
| `UpdateService` | core | Check for application updates |
| `ZipFileService` | core | ZIP file creation and extraction |
| `UndoManager` | core | Undo/redo stack for page editor |

**Page Editor Commands** (command pattern):

| Command | Operation |
|---|---|
| `RotatePageCommand` | Rotate individual pages |
| `DeletePagesCommand` | Remove pages from document |
| `ReorderPagesCommand` | Drag-and-drop page reordering |
| `SplitCommand` | Split document at specified points |

### 9.5 Desktop Services

| Service | Purpose |
|---|---|
| `AuthService` | Manage authentication tokens via Tauri secure storage |
| `ConnectionModeService` | Switch between local, remote, and hybrid backend connections |
| `OperationRouter` | Route operations to local backend or remote server based on connection mode |
| `TauriBackendService` | Lifecycle management for the embedded backend process |
| `SaasBillingService` | SaaS billing integration for desktop users |
| `BackendHealthMonitor` | Periodic health checks on the backend, auto-restart on failure |

### 9.6 AI Engine Agents

| Agent | Input | Output | Use Case |
|---|---|---|---|
| `OrchestratorAgent` | Natural language request | Tool selection + parameters | "Convert this to Word and compress it" |
| `PdfEditAgent` | Edit instructions + PDF | Modified PDF | "Add a header to every page" |
| `PdfQuestionAgent` | Question + PDF | Natural language answer | "What is the total on page 3?" |
| `UserSpecAgent` | Requirements description | Specification document | Draft/revise functional specs |
| `ExecutionPlanningAgent` | Multi-step request | Ordered operation plan | Plan complex multi-tool workflows |
| `MathAuditorAgent` | Financial PDF | Audit report | Verify ledger entries, check calculations |

Supporting classes:
- `AppRuntime`: Application lifecycle and configuration
- `PostHogSpanProcessor`: Telemetry span processing for AI agent traces

---

## 10. Supported Operations

The platform supports **38 distinct operation types** (defined in `engine/tool_models.py`):

| Operation | Description |
|---|---|
| `addAttachments` | Embed files into a PDF |
| `addPassword` | Password-protect a PDF |
| `adjustContrast` | Adjust page contrast/brightness |
| `autoRename` | AI-based file renaming from content |
| `automate` | Run automation pipelines |
| `bookletImposition` | Arrange pages for booklet printing |
| `certSign` | Apply certificate-based digital signature |
| `changeMetadata` | Edit PDF metadata (title, author, etc.) |
| `changePermissions` | Set PDF permission flags |
| `compress` | Reduce PDF file size |
| `convert` | Convert between file formats |
| `crop` | Crop page margins |
| `editTableOfContents` | Modify PDF bookmarks/TOC |
| `extractImages` | Extract embedded images |
| `extractPages` | Extract specific page ranges |
| `flatten` | Flatten form fields and annotations |
| `merge` | Combine multiple PDFs |
| `ocr` | Optical character recognition |
| `overlayPdfs` | Overlay one PDF on another |
| `pageLayout` | Multi-page layout (N-up) |
| `pdfToSinglePage` | Combine all pages into one continuous page |
| `redact` | Permanently remove sensitive content |
| `removeAnnotations` | Strip all annotations |
| `removeBlanks` | Detect and remove blank pages |
| `removeCertSign` | Remove digital signatures |
| `removeImage` | Remove images from PDF |
| `removePages` | Delete specific pages |
| `removePassword` | Decrypt a password-protected PDF |
| `reorganizePages` | Reorder pages |
| `repair` | Repair corrupted PDFs |
| `replaceColor` | Replace colors in PDF content |
| `rotate` | Rotate pages |
| `sanitize` | Remove hidden data, scripts, metadata |
| `scalePages` | Resize pages |
| `scannerImageSplit` | Split scanned image pages |
| `sign` | Add visual signature |
| `split` | Split into multiple PDFs |
| `unlockPDFForms` | Make locked form fields editable |
| `watermark` | Add text/image watermark |

---

## 11. Testing

### 11.1 Test Infrastructure

| Test Type | Location | Framework | Command |
|---|---|---|---|
| Backend unit tests | `app/core/src/test/`, `app/common/src/test/`, `app/proprietary/src/test/` | JUnit 5 | `./gradlew test` |
| Frontend unit tests | `frontend/src/` | Vitest | `cd frontend && npm test` |
| Frontend E2E tests | `frontend/` | Playwright | `cd frontend && npm run test:e2e` |
| BDD tests | `testing/cucumber/` | Cucumber | Via Gradle |
| AI engine tests | `engine/tests/` | pytest | `cd engine && pytest` |
| Docker CI/CD | `test_cicd.yml` | Docker Compose | Compose-based integration |
| Test driver | `testing/testdriver/` | — | End-to-end test orchestration |

### 11.2 Translation Validation

Stirling-PDF includes automated translation quality checks:

| Validator | Purpose |
|---|---|
| TOML validator | Validates TOML translation file syntax |
| JSON structure validator | Ensures translation JSON files have consistent structure |
| Placeholder validator | Verifies `{0}`, `{1}`, etc. placeholders match across translations |

### 11.3 CI/CD Test Configuration

The `test_cicd.yml` Docker Compose file sets up a test environment with API key authentication enabled, allowing automated integration testing against a running container.

> [!TIP]
> Run the full test suite before submitting PRs: `./gradlew build test spotlessCheck` for backend, and `cd frontend && npm run test && npm run lint` for frontend.

---

## 12. Troubleshooting

### 12.1 Container Fails to Start

**Error:** Container exits immediately or health check fails.

**Cause:** Insufficient memory for JVM startup, misconfigured `SYSTEM_ROOTURIPATH`, or port conflict.

**Solution:**
1. Check logs: `docker logs stirling-pdf`
2. Verify memory: ensure at least 512 MB available
3. Check port availability: `docker ps` for conflicts on 8080
4. If using `SYSTEM_ROOTURIPATH`, ensure it starts with `/` and has no trailing slash

**Prevention:** Always configure `healthcheck.start_period` to at least 60 seconds to allow JVM warm-up.

### 12.2 LibreOffice Conversion Failures

**Error:** `file-to-pdf`, `pdf-to-word`, or similar endpoints return 500 errors.

**Cause:** LibreOffice not installed (standard/ultra-lite image), UNO server not running, or session limit exceeded.

**Solution:**
1. Verify image type: use fat image or install LibreOffice manually
2. Check UNO server: `docker exec stirling-pdf ps aux | grep soffice`
3. If remote UNO: verify shared `/tmp/stirling-pdf` volume and network connectivity
4. Increase session limit: `PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT=4`

**Prevention:** Use the fat Docker image for deployments requiring document conversion.

### 12.3 OCR Returns Empty Text

**Error:** `ocr-pdf` endpoint produces a PDF with no recognized text.

**Cause:** Missing Tesseract language data for the document's language.

**Solution:**
1. Install required language: `TESSERACT_LANGS=eng,fra,deu` (rebuild container)
2. Or mount traineddata files: `-v ./tessdata:/usr/share/tessdata`
3. Verify language availability inside container: `ls /usr/share/tessdata/`

**Prevention:** Pre-install all expected languages via `TESSERACT_LANGS`.

### 12.4 Large File Upload Fails

**Error:** 413 Request Entity Too Large or upload timeout.

**Cause:** `SYSTEM_MAXFILESIZE` too low, or reverse proxy body size limit.

**Solution:**
1. Increase `SYSTEM_MAXFILESIZE` (in MB)
2. Match reverse proxy limit: `client_max_body_size 500M;` in Nginx
3. Increase proxy timeout for large files

**Prevention:** Set consistent limits across Stirling-PDF config and reverse proxy.

### 12.5 Endpoints Show as Disabled

**Error:** UI shows certain operations as unavailable.

**Cause:** Missing external tool dependency, or group disabled via configuration.

**Solution:**
1. Check endpoint status via API: `GET /api/v1/info/status`
2. Review disable reason (CONFIG vs DEPENDENCY)
3. For DEPENDENCY: install the required tool or switch to fat image
4. For CONFIG: review `settings.yml` and `ENDPOINTS_GROUPS_TO_REMOVE`

**Prevention:** Use the fat Docker image to ensure all dependencies are present.

### 12.6 Split Frontend Cannot Reach Backend

**Error:** Frontend shows connection errors or blank pages.

**Cause:** `VITE_API_BASE_URL` not set or set to unreachable address.

**Solution:**
1. Verify `VITE_API_BASE_URL` points to the backend's actual URL
2. Ensure backend is running and healthy
3. Check network connectivity between frontend and backend containers
4. Verify CORS configuration if frontend and backend are on different domains

**Prevention:** Use Docker Compose networking (service names) for container-to-container communication.

> [!CAUTION]
> When running in split mode, the backend URL must be accessible from both the frontend container (for SSR/proxying) and the end user's browser (for client-side API calls). Ensure the URL is publicly reachable or configure appropriate proxy rules.

### 12.7 Database Import Constraint Error

**Error:** Database import fails with constraint violation (relates to GitHub issue #4405).

**Cause:** Schema migration conflict or duplicate key in imported data.

**Solution:**
1. Back up existing database before import
2. Verify the import file matches the current schema version
3. If upgrading from an older version, let the application run its migrations first, then import

**Prevention:** Always export/import databases between matching application versions.

### 12.8 Windows SmartScreen Blocks Desktop Installer

**Error:** Windows SmartScreen prevents the desktop installer from running (GitHub issue #5600).

**Cause:** The executable is not yet widely distributed enough to build SmartScreen reputation, or code signing certificate is not recognized.

**Solution:**
1. Click "More info" then "Run anyway" in the SmartScreen dialog
2. Alternatively, right-click the installer, go to Properties, and check "Unblock"
3. For enterprise deployment, add the installer hash to your organization's allow list via Group Policy

**Prevention:** Enterprise administrators should pre-approve the installer via WDAC or AppLocker policies.

---

## 13. API Reference

### 13.1 Authentication

API requests can be authenticated via:

```bash
# Per-user API key
curl -H "X-API-KEY: your-api-key" http://localhost:8080/api/v1/info/status

# Global API key (if SECURITY_CUSTOMGLOBALAPIKEY is set)
curl -H "X-API-KEY: global-key" http://localhost:8080/api/v1/info/status
```

### 13.2 Core Endpoints

The API exposes endpoints matching the 38 operation types listed in Section 10. Each operation accepts multipart form data with the PDF file and operation-specific parameters.

**General pattern:**

```bash
# Example: Merge PDFs
curl -X POST http://localhost:8080/api/v1/general/merge-pdfs \
  -H "X-API-KEY: your-key" \
  -F "fileInput=@file1.pdf" \
  -F "fileInput=@file2.pdf"

# Example: Compress PDF
curl -X POST http://localhost:8080/api/v1/general/compress-pdf \
  -H "X-API-KEY: your-key" \
  -F "fileInput=@document.pdf" \
  -F "optimizeLevel=3"

# Example: OCR
curl -X POST http://localhost:8080/api/v1/misc/ocr-pdf \
  -H "X-API-KEY: your-key" \
  -F "fileInput=@scanned.pdf" \
  -F "languages=eng"
```

### 13.3 Info Endpoints

```bash
# Health/status check
GET /api/v1/info/status

# Application information
GET /api/v1/info
```

### 13.4 AI Engine Endpoints

When the AI engine is running:

```bash
# Orchestrate a natural language request
POST /orchestrate

# Ask questions about a PDF
POST /pdf_questions

# AI-guided PDF editing
POST /pdf_edit

# Draft a specification
POST /draft

# Revise a specification
POST /revise

# Get next action recommendation
POST /next-action

# Examine a document
POST /examine

# Deliberate on a complex request
POST /deliberate

# Health check
GET /health
```

---

## 14. Integration Points

### 14.1 PostHog Analytics

Both the frontend (SaaS module) and the AI engine support PostHog telemetry:

- **AI Engine**: Set `STIRLING_POSTHOG_ENABLED=true`, `STIRLING_POSTHOG_API_KEY`, and `STIRLING_POSTHOG_HOST`
- **Frontend SaaS**: PostHog is integrated in the SaaS deployment module for user behavior analytics

### 14.2 Google Drive

The `GoogleDrivePickerService` in the frontend core enables importing files directly from Google Drive into Stirling-PDF operations.

### 14.3 Stripe Billing

The proprietary frontend module includes Stripe checkout integration for SaaS billing scenarios.

### 14.4 Windows Shell Integration

The Windows thumbnail handler DLL (`stirling_thumbnail_handler.dll`) registers as a COM `IThumbnailProvider` for the `.pdf` file extension, providing native PDF thumbnails in Windows Explorer when the desktop app is installed.

### 14.5 Enterprise Provisioner

The Tauri provisioner tool allows enterprise IT to preconfigure desktop installations:
- Lock the server URL to a specific Stirling-PDF instance
- Prevent users from switching connection modes
- Deploy via standard MSI/MSIX enterprise deployment tools

---

## 15. Known Issues

| Issue | Status | Description |
|---|---|---|
| #1612 | Open | Split PDF operation removes input fields from the resulting documents |
| #4405 | Open | Database import fails with constraint violation errors |
| #5951 | Open | Docker image crash under certain conditions |
| #6120 | Open | False positive virus detection on v2.9.2 binaries |
| #5600 | Open | Windows SmartScreen blocks the desktop installer |
| #6123 | Open | French translation issues in certain UI strings |

> [!WARNING]
> Issue #6120 (false positive virus detection) affects v2.9.2 specifically. If your security software flags the Docker image or desktop binary, verify the checksum against the official release and add an exception if it matches.

---

## 16. Quick Reference

### 16.1 Minimal Docker Run

```bash
docker run -d -p 8080:8080 stirlingtools/stirling-pdf:latest
```

### 16.2 Production Docker Compose

```yaml
version: "3.8"
services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest-fat
    ports:
      - "8080:8080"
    volumes:
      - ./configs:/configs
      - ./logs:/logs
      - ./tessdata:/usr/share/tessdata
      - ./customFiles:/customFiles
      - ./pipeline:/pipeline
    environment:
      - DOCKER_ENABLE_SECURITY=true
      - SECURITY_ENABLELOGIN=true
      - FAT_DOCKER=true
      - SYSTEM_MAXFILESIZE=200
      - SYSTEM_DEFAULTLOCALE=en-US
      - TESSERACT_LANGS=eng,fra,deu,spa
      - METRICS_ENABLED=true
      - STIRLING_JVM_PROFILE=balanced
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/api/v1/info/status"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
```

### 16.3 Key Paths Inside Container

| Path | Purpose |
|---|---|
| `/configs/settings.yml` | Primary configuration |
| `/logs/` | Application logs |
| `/usr/share/tessdata/` | OCR language data |
| `/customFiles/` | UI customization |
| `/pipeline/` | Automation pipelines |
| `/tmp/stirling-pdf/` | Temporary files (shared for remote UNO) |

### 16.4 Contributing Checklist

```bash
./gradlew spotlessApply   # Format Java code
./gradlew test            # Run backend tests
cd frontend && npm test   # Run frontend tests
./gradlew build           # Full build verification
```

---

_Generated May 2026 from Stirling-Tools/Stirling-PDF at 79f4748. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
