a08b103271
Merges origin/main (v0.156.0) into the classification feature branch, properly resolving all 23 merge conflicts: - Auto-generated files (BUILD_DATE, VERSION, etc.): accept main's version - Non-classification files (SharePoint, QR auth, session mgmt, mobile): accept main's version - Classification files (api/__init__.py, models.py, migrations/env.py, conftest.py): keep classification additions alongside main's content Previously the branch was incorrectly removing files from main (SharePoint integration, QR scanner, session management). This merge properly preserves all main branch content while maintaining the classification feature additions. Migration chain validated: 038_add_classification_rules chains from 037_add_user_sessions_and_qr_challenges. Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
640 lines
29 KiB
Bash
640 lines
29 KiB
Bash
# **Core Settings**
|
||
WORKDIR=/workdir
|
||
DATABASE_URL=sqlite:///./app/database.db
|
||
REDIS_URL=redis://redis:6379/0
|
||
EXTERNAL_HOSTNAME=docuelevate.example.com
|
||
GOTENBERG_URL=http://gotenberg:3000
|
||
ALLOW_FILE_DELETE=true # Allow deletion of file records
|
||
COMPLIANCE_ENABLED=true # Enable compliance templates dashboard (GDPR, HIPAA, SOC 2)
|
||
|
||
# **System Reset / Factory Reset**
|
||
# FACTORY_RESET_ON_STARTUP=false # Wipe all user data on every startup (demo/testing only)
|
||
# ENABLE_FACTORY_RESET=false # Show the System Reset page in admin UI
|
||
|
||
# **Logging**
|
||
# LOG_LEVEL controls the Python root-logger level.
|
||
# Accepted values: DEBUG, INFO, WARNING, ERROR, CRITICAL (default: INFO).
|
||
# When DEBUG=true and LOG_LEVEL is not set, the level is automatically lowered to DEBUG.
|
||
# LOG_LEVEL=INFO
|
||
# DEBUG=false
|
||
|
||
# Log output format: "text" (human-readable, default) or "json" (structured JSON lines).
|
||
# Use "json" when shipping logs to Grafana Loki, Splunk, ELK, Datadog, or any SIEM.
|
||
# LOG_FORMAT=text
|
||
|
||
# Forward application logs to a syslog receiver (in addition to stdout).
|
||
# Useful for traditional (non-container) deployments and centralised SIEM ingestion.
|
||
# LOG_SYSLOG_ENABLED=false
|
||
# LOG_SYSLOG_HOST=localhost
|
||
# LOG_SYSLOG_PORT=514
|
||
# LOG_SYSLOG_PROTOCOL=udp # udp | tcp
|
||
|
||
# **UI / Appearance**
|
||
# Default colour scheme: system (follow OS), light, or dark
|
||
# Individual users can always override with the navbar dark-mode toggle.
|
||
# UI_DEFAULT_COLOR_SCHEME=system
|
||
|
||
# **Batch Processing Settings**
|
||
# Control throttling behavior for the /processall endpoint to prevent overwhelming downstream APIs
|
||
PROCESSALL_THROTTLE_THRESHOLD=20 # Number of files above which throttling is applied (default: 20)
|
||
PROCESSALL_THROTTLE_DELAY=3 # Delay in seconds between each task submission when throttling (default: 3)
|
||
|
||
# **Task Retry Settings**
|
||
# Failed tasks are automatically retried with exponential backoff and jitter.
|
||
# TASK_RETRY_MAX_RETRIES=3 # Max retry attempts per task (default: 3)
|
||
# TASK_RETRY_DELAYS=60,300,900 # Countdown (seconds) before each retry; 1 min, 5 min, 15 min
|
||
# TASK_RETRY_JITTER=true # Add ±20% random jitter to prevent thundering-herd (default: true)
|
||
|
||
# **Client-Side Upload Throttling**
|
||
# Controls pacing when the browser uploads files (especially large directory drops).
|
||
# The browser auto-detects rate-limit (HTTP 429) responses and backs off accordingly.
|
||
UPLOAD_CONCURRENCY=3 # Max simultaneous uploads from the browser (default: 3)
|
||
UPLOAD_QUEUE_DELAY_MS=500 # Delay (ms) between starting each upload slot (default: 500)
|
||
|
||
# **File Upload Size Limits** (Security - see SECURITY_AUDIT.md)
|
||
# Maximum file upload size in bytes. Default: 1GB (1073741824 bytes)
|
||
# Prevents resource exhaustion attacks. Adjust based on your server capacity.
|
||
MAX_UPLOAD_SIZE=1073741824
|
||
|
||
# Maximum size for a single file chunk in bytes (optional)
|
||
# If set and a file exceeds this size, it will be split into smaller chunks for processing
|
||
# Default: None (no splitting). Example: 104857600 for 100MB chunks
|
||
# MAX_SINGLE_FILE_SIZE=104857600
|
||
|
||
# **Request Body Size Limit** (Security - see SECURITY_AUDIT.md)
|
||
# Maximum request body size in bytes for non-file-upload requests (JSON, form data, etc.).
|
||
# Default: 1MB (1048576 bytes). File uploads are governed by MAX_UPLOAD_SIZE above.
|
||
# Prevents memory exhaustion from oversized JSON/form payloads.
|
||
# MAX_REQUEST_BODY_SIZE=1048576
|
||
|
||
# **Security Headers** (see SECURITY_AUDIT.md and docs/DeploymentGuide.md)
|
||
# Disabled by default since most deployments use a reverse proxy (Traefik, Nginx, etc.)
|
||
# that already adds these headers. Set to true only if deploying directly without a reverse proxy.
|
||
# SECURITY_HEADERS_ENABLED=false
|
||
|
||
# If you enable security headers, you can also configure individual headers:
|
||
# Strict-Transport-Security (HSTS) - Forces HTTPS connections
|
||
# Only effective when served over HTTPS. Disable if not using HTTPS or if proxy adds this header
|
||
# SECURITY_HEADER_HSTS_ENABLED=true
|
||
# SECURITY_HEADER_HSTS_VALUE="max-age=31536000; includeSubDomains"
|
||
|
||
# Content-Security-Policy (CSP) - Controls resource loading
|
||
# Customize based on your application's resource loading needs
|
||
# Default allows self-hosted resources, inline scripts/styles, and external images
|
||
# SECURITY_HEADER_CSP_ENABLED=true
|
||
# SECURITY_HEADER_CSP_VALUE="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;"
|
||
|
||
# X-Frame-Options - Prevents clickjacking attacks
|
||
# Options: DENY (no framing), SAMEORIGIN (same origin framing only), ALLOW-FROM uri
|
||
# SECURITY_HEADER_X_FRAME_OPTIONS_ENABLED=true
|
||
# SECURITY_HEADER_X_FRAME_OPTIONS_VALUE="DENY"
|
||
|
||
# X-Content-Type-Options - Prevents MIME sniffing
|
||
# Always set to 'nosniff' when enabled
|
||
# SECURITY_HEADER_X_CONTENT_TYPE_OPTIONS_ENABLED=true
|
||
|
||
# **CORS (Cross-Origin Resource Sharing)** (see SECURITY_AUDIT.md – Infrastructure Security)
|
||
# Disabled by default: most deployments rely on a reverse proxy (Traefik, Nginx, etc.) to inject
|
||
# CORS headers. Set CORS_ENABLED=true only if DocuElevate is exposed directly without a proxy,
|
||
# or if your proxy does not handle CORS. When enabled, only list the exact origins that need access.
|
||
#
|
||
# Rationale for reverse-proxy-first approach:
|
||
# Traefik/Nginx already set Access-Control-Allow-Origin (and related headers) for every response,
|
||
# so adding the middleware here would duplicate headers. When this flag is False the application
|
||
# trusts the proxy layer to enforce CORS policy; set it to True for standalone / direct-access
|
||
# deployments only.
|
||
#
|
||
# CORS_ENABLED=false
|
||
#
|
||
# Comma-separated list of allowed origins (use * to allow all - not recommended with credentials)
|
||
# CORS_ALLOWED_ORIGINS=https://app.example.com,https://admin.example.com
|
||
#
|
||
# Allow cookies / Authorization headers in cross-origin requests
|
||
# Must be False when CORS_ALLOWED_ORIGINS=* (browser security requirement)
|
||
# CORS_ALLOW_CREDENTIALS=false
|
||
#
|
||
# Allowed HTTP methods (comma-separated)
|
||
# CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,OPTIONS,PATCH
|
||
#
|
||
# Allowed request headers (use * to allow all)
|
||
# CORS_ALLOWED_HEADERS=*
|
||
|
||
# **Audit Logging & SIEM Integration** (see docs/ConfigurationGuide.md#audit-logging)
|
||
# Enable HTTP request audit logging middleware
|
||
AUDIT_LOGGING_ENABLED=true
|
||
# Include client IP in audit log entries (disable for GDPR-sensitive deployments)
|
||
AUDIT_LOG_INCLUDE_CLIENT_IP=true
|
||
|
||
# Forward audit events to an external SIEM system (Syslog, Splunk, Logstash, Grafana, etc.)
|
||
# AUDIT_SIEM_ENABLED=false
|
||
# AUDIT_SIEM_TRANSPORT=syslog # syslog | http
|
||
# AUDIT_SIEM_SYSLOG_HOST=localhost
|
||
# AUDIT_SIEM_SYSLOG_PORT=514
|
||
# AUDIT_SIEM_SYSLOG_PROTOCOL=udp # udp | tcp
|
||
# AUDIT_SIEM_HTTP_URL= # e.g. https://splunk:8088/services/collector/event
|
||
# AUDIT_SIEM_HTTP_TOKEN= # Bearer / HEC token
|
||
# AUDIT_SIEM_HTTP_CUSTOM_HEADERS= # Comma-separated Key:Value pairs
|
||
|
||
# **Rate Limiting** (see SECURITY_AUDIT.md and docs/API.md)
|
||
# Protects against DoS attacks and API abuse by limiting request rates per IP/user
|
||
# Enabled by default - highly recommended for production
|
||
RATE_LIMITING_ENABLED=true
|
||
|
||
# Default rate limit for all API endpoints (format: count/period)
|
||
# Periods can be: second, minute, hour, day
|
||
# Default: 100 requests per minute per IP/user
|
||
RATE_LIMIT_DEFAULT=100/minute
|
||
|
||
# Rate limit for file upload endpoints
|
||
# Allows faster uploads while still preventing abuse
|
||
# Default: 600 uploads per minute per IP/user
|
||
RATE_LIMIT_UPLOAD=600/minute
|
||
|
||
# Rate limit for authentication endpoints
|
||
# Strict limit to prevent brute force attacks
|
||
# Default: 10 attempts per minute per IP
|
||
RATE_LIMIT_AUTH=10/minute
|
||
|
||
# Note: Processing endpoints (OCR, metadata extraction) use built-in queue throttling
|
||
# via Celery task queue to control processing rates and prevent upstream API overloads.
|
||
# No additional API-level rate limit is needed for processing endpoints.
|
||
|
||
# **Authentication**
|
||
AUTH_ENABLED=true
|
||
# Generate a secure random string, for example:
|
||
# python -c "import secrets; print(secrets.token_hex(32))"
|
||
SESSION_SECRET=b39fd43f68d0491ca942f28a16e484b1e763fe9accf4445ca2669a5f3b179eb4
|
||
|
||
# Session lifetime in days (default: 30). Common values: 30, 60, 90.
|
||
# Determines how long a user stays logged in before needing to re-authenticate.
|
||
# SESSION_LIFETIME_DAYS=30
|
||
# Override with a custom value (takes precedence over SESSION_LIFETIME_DAYS):
|
||
# SESSION_LIFETIME_CUSTOM_DAYS=
|
||
|
||
# Time-to-live in seconds for QR code login challenges (default: 120 = 2 minutes).
|
||
# QR_LOGIN_CHALLENGE_TTL_SECONDS=120
|
||
|
||
ADMIN_USERNAME=admin
|
||
ADMIN_PASSWORD=your_secure_password
|
||
ADMIN_GROUP_NAME=admin
|
||
|
||
# **Multi-User Mode**
|
||
# When enabled, each user has their own document space with isolated uploads,
|
||
# search, and file management. Requires AUTH_ENABLED=true.
|
||
MULTI_USER_ENABLED=false
|
||
# Allow users to self-register with an email address and password.
|
||
# Set to true to enable the /signup page. Requires MULTI_USER_ENABLED=true.
|
||
# When SMTP is configured, a verification email is sent before the account is activated.
|
||
# Without SMTP, accounts are activated immediately upon registration.
|
||
# ALLOW_LOCAL_SIGNUP=false
|
||
# Default upload limit per user per day (0 = unlimited)
|
||
DEFAULT_DAILY_UPLOAD_LIMIT=0
|
||
# Show unowned documents (owner_id=NULL) to all users (true) or only admins (false)
|
||
UNOWNED_DOCS_VISIBLE_TO_ALL=true
|
||
# Auto-assign this owner ID to documents ingested without a session (e.g. IMAP, API)
|
||
# Leave empty/unset to keep them unowned until claimed.
|
||
# DEFAULT_OWNER_ID=
|
||
|
||
# **Subscription / Quota Settings**
|
||
# Soft-limit overage buffer in percent (0–200). Announced quota is multiplied by (1 + percent/100)
|
||
# for actual enforcement. E.g. 20 means a 150-doc/month plan enforces at 180. 0 = enforce exactly.
|
||
# Per-plan overage_percent set in the Plan Designer overrides this global default.
|
||
# SUBSCRIPTION_OVERAGE_PERCENT=20
|
||
|
||
# **OpenID Connect/Authentik Settings**
|
||
AUTHENTIK_CLIENT_ID=<yourAuthentikAppClientID>
|
||
AUTHENTIK_CLIENT_SECRET=<yourAuthentikClientSecret>
|
||
AUTHENTIK_CONFIG_URL=<ConfigUrlOfYourApp, e.g. https://authentik.example.com/application/o/docuelevate/.well-known/openid-configuration>
|
||
OAUTH_PROVIDER_NAME="Authentik SSO"
|
||
|
||
# **Social Login Providers**
|
||
# Enable one or more social login providers to let users sign in with existing accounts.
|
||
# Each provider requires separate OAuth credentials. See docs/SocialLoginSetup.md for details.
|
||
|
||
# Google Sign-In (https://console.cloud.google.com/apis/credentials)
|
||
# SOCIAL_AUTH_GOOGLE_ENABLED=false
|
||
# SOCIAL_AUTH_GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
|
||
# SOCIAL_AUTH_GOOGLE_CLIENT_SECRET=your-google-client-secret
|
||
|
||
# Microsoft Sign-In / Azure AD (https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps)
|
||
# SOCIAL_AUTH_MICROSOFT_ENABLED=false
|
||
# SOCIAL_AUTH_MICROSOFT_CLIENT_ID=your-microsoft-application-id
|
||
# SOCIAL_AUTH_MICROSOFT_CLIENT_SECRET=your-microsoft-client-secret
|
||
# SOCIAL_AUTH_MICROSOFT_TENANT=common # common | organizations | consumers | <tenant-id>
|
||
|
||
# Apple Sign-In (https://developer.apple.com/account/resources)
|
||
# SOCIAL_AUTH_APPLE_ENABLED=false
|
||
# SOCIAL_AUTH_APPLE_CLIENT_ID=com.example.docuelevate
|
||
# SOCIAL_AUTH_APPLE_TEAM_ID=ABCDE12345
|
||
# SOCIAL_AUTH_APPLE_KEY_ID=FGHIJ67890
|
||
# SOCIAL_AUTH_APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
|
||
|
||
# Dropbox Sign-In (https://www.dropbox.com/developers/apps)
|
||
# SOCIAL_AUTH_DROPBOX_ENABLED=false
|
||
# SOCIAL_AUTH_DROPBOX_CLIENT_ID=your-dropbox-app-key
|
||
# SOCIAL_AUTH_DROPBOX_CLIENT_SECRET=your-dropbox-app-secret
|
||
|
||
# **AI/ML Services**
|
||
# Select your AI provider: openai | azure | anthropic | gemini | ollama | openrouter | portkey | litellm
|
||
AI_PROVIDER=openai
|
||
# Model override (optional – falls back to OPENAI_MODEL when not set)
|
||
# AI_MODEL=gpt-4o-mini
|
||
|
||
# --- OpenAI (AI_PROVIDER=openai) ---
|
||
OPENAI_API_KEY="<OPENAI_API_KEY>"
|
||
OPENAI_BASE_URL=https://api.openai.com/v1
|
||
OPENAI_MODEL=gpt-4o-mini
|
||
|
||
# --- Anthropic Claude (AI_PROVIDER=anthropic) ---
|
||
# ANTHROPIC_API_KEY=sk-ant-...
|
||
# AI_MODEL=claude-3-5-sonnet-20241022
|
||
|
||
# --- Google Gemini (AI_PROVIDER=gemini) ---
|
||
# GEMINI_API_KEY=AIza...
|
||
# AI_MODEL=gemini-1.5-pro
|
||
|
||
# --- Ollama local LLMs (AI_PROVIDER=ollama) ---
|
||
# OLLAMA_BASE_URL=http://localhost:11434
|
||
# AI_MODEL=llama3.2
|
||
|
||
# --- OpenRouter (AI_PROVIDER=openrouter) ---
|
||
# OPENROUTER_API_KEY=sk-or-...
|
||
# AI_MODEL=anthropic/claude-3.5-sonnet
|
||
|
||
# --- Portkey AI Gateway (AI_PROVIDER=portkey) ---
|
||
# PORTKEY_API_KEY=pk-...
|
||
# PORTKEY_VIRTUAL_KEY=vk-... # optional – routes to provider credentials in Portkey vault
|
||
# PORTKEY_CONFIG=pc-... # optional – saved Config ID for fallbacks / load balancing
|
||
|
||
# --- Azure OpenAI (AI_PROVIDER=azure) ---
|
||
# OPENAI_API_KEY=<azure-key>
|
||
# OPENAI_BASE_URL=https://my-resource.openai.azure.com
|
||
# AZURE_OPENAI_API_VERSION=2024-02-01
|
||
# AI_MODEL=gpt-4o # deployment name in Azure
|
||
|
||
# **Document Translation**
|
||
# After processing, documents whose detected language differs from the default
|
||
# target language are automatically translated. Only the original and this
|
||
# default-language version are persisted; other translations are on-the-fly.
|
||
# Users can override this in their profile settings.
|
||
# DEFAULT_DOCUMENT_LANGUAGE=en
|
||
|
||
# Azure Document Intelligence (OCR – separate from AI provider above)
|
||
# **Email Settings (shared SMTP – password reset, verification, and system notifications)**
|
||
EMAIL_HOST=smtp.example.com
|
||
EMAIL_PORT=587
|
||
EMAIL_USERNAME=docuelevate@example.com
|
||
EMAIL_PASSWORD=your_secure_email_password
|
||
EMAIL_USE_TLS=True
|
||
EMAIL_SENDER=DocuElevate System <docuelevate@example.com>
|
||
# EMAIL_DEFAULT_RECIPIENT is not used for document delivery (see DEST_EMAIL_* below)
|
||
|
||
# **Email Destination Settings (dedicated SMTP for document delivery)**
|
||
# These settings are intentionally separate from the shared EMAIL_* settings above.
|
||
# Configuring EMAIL_HOST for password reset / notifications does NOT automatically
|
||
# enable the email destination – you must set DEST_EMAIL_HOST to activate it.
|
||
# DEST_EMAIL_ENABLED=true # Set to false to disable email delivery without removing credentials
|
||
DEST_EMAIL_HOST=smtp.example.com
|
||
DEST_EMAIL_PORT=587
|
||
DEST_EMAIL_USERNAME=docuelevate@example.com
|
||
DEST_EMAIL_PASSWORD=your_secure_email_password
|
||
DEST_EMAIL_USE_TLS=True
|
||
DEST_EMAIL_SENDER=DocuElevate Delivery <docuelevate@example.com>
|
||
DEST_EMAIL_DEFAULT_RECIPIENT=recipient@example.com
|
||
|
||
# **Watch Folder Ingestion**
|
||
# DocuElevate can automatically monitor directories (local, FTP, SFTP, and cloud providers) for new files.
|
||
#
|
||
# Local watch folders — works with any mounted path (SMB/CIFS, NFS, local disk, etc.)
|
||
# Set WATCH_FOLDERS to a comma-separated list of absolute paths inside the container.
|
||
WATCH_FOLDERS=
|
||
WATCH_FOLDER_POLL_INTERVAL=1
|
||
WATCH_FOLDER_DELETE_AFTER_PROCESS=false
|
||
|
||
# FTP ingest — poll an FTP directory for new files (uses FTP connection settings above)
|
||
FTP_INGEST_ENABLED=false
|
||
FTP_INGEST_FOLDER=
|
||
FTP_INGEST_DELETE_AFTER_PROCESS=false
|
||
|
||
# SFTP ingest — poll an SFTP directory for new files (uses SFTP connection settings above)
|
||
SFTP_INGEST_ENABLED=false
|
||
SFTP_INGEST_FOLDER=
|
||
SFTP_INGEST_DELETE_AFTER_PROCESS=false
|
||
|
||
# Dropbox ingest — poll a Dropbox folder (uses Dropbox OAuth credentials above)
|
||
DROPBOX_INGEST_ENABLED=false
|
||
DROPBOX_INGEST_FOLDER=
|
||
DROPBOX_INGEST_DELETE_AFTER_PROCESS=false
|
||
|
||
# Google Drive ingest — poll a Google Drive folder (uses Google Drive credentials above)
|
||
GOOGLE_DRIVE_INGEST_ENABLED=false
|
||
GOOGLE_DRIVE_INGEST_FOLDER_ID=
|
||
GOOGLE_DRIVE_INGEST_DELETE_AFTER_PROCESS=false
|
||
|
||
# OneDrive ingest — poll a OneDrive folder (uses OneDrive MSAL credentials above)
|
||
ONEDRIVE_INGEST_ENABLED=false
|
||
ONEDRIVE_INGEST_FOLDER_PATH=
|
||
ONEDRIVE_INGEST_DELETE_AFTER_PROCESS=false
|
||
|
||
# Nextcloud ingest — poll a Nextcloud folder (uses Nextcloud WebDAV credentials above)
|
||
NEXTCLOUD_INGEST_ENABLED=false
|
||
NEXTCLOUD_INGEST_FOLDER=
|
||
NEXTCLOUD_INGEST_DELETE_AFTER_PROCESS=false
|
||
|
||
# Amazon S3 ingest — poll an S3 prefix (uses S3/AWS credentials above)
|
||
S3_INGEST_ENABLED=false
|
||
S3_INGEST_PREFIX=
|
||
S3_INGEST_DELETE_AFTER_PROCESS=false
|
||
|
||
# WebDAV ingest — poll a WebDAV folder (uses WebDAV credentials above)
|
||
WEBDAV_INGEST_ENABLED=false
|
||
WEBDAV_INGEST_FOLDER=
|
||
WEBDAV_INGEST_DELETE_AFTER_PROCESS=false
|
||
|
||
# **IMAP Settings**
|
||
# DocuElevate polls these mailboxes for new email attachments and automatically ingests them.
|
||
# No manual forwarding required — DocuElevate acts as an IMAP *client*.
|
||
# For HP Scanners / Scan-to-Email: configure the scanner to send to a dedicated mailbox,
|
||
# then point DocuElevate at that mailbox using the settings below.
|
||
IMAP1_HOST=mail.example.com
|
||
IMAP1_PORT=993
|
||
IMAP1_USERNAME=<IMAP1_USERNAME>
|
||
IMAP1_PASSWORD=<IMAP1_PASSWORD>
|
||
IMAP1_SSL=true
|
||
IMAP1_POLL_INTERVAL_MINUTES=5
|
||
IMAP1_DELETE_AFTER_PROCESS=false
|
||
|
||
IMAP2_HOST=imap.gmail.com
|
||
IMAP2_PORT=993
|
||
IMAP2_USERNAME=<IMAP2_USERNAME>
|
||
IMAP2_PASSWORD=<IMAP2_PASSWORD>
|
||
IMAP2_SSL=true
|
||
IMAP2_POLL_INTERVAL_MINUTES=10
|
||
IMAP2_DELETE_AFTER_PROCESS=false
|
||
|
||
# IMAP Readonly Mode (Feature Flag)
|
||
# When true, IMAP processing will fetch and process attachments but will NOT modify
|
||
# the mailbox state (no starring, labeling, deleting, or flag changes).
|
||
# Use for pre-production instances that share a mailbox with production.
|
||
IMAP_READONLY_MODE=false
|
||
|
||
# Controls which attachment types are ingested from IMAP emails.
|
||
# 'documents_only' (default) – PDFs and office files only; images are skipped.
|
||
# 'all' – all supported file types including images.
|
||
# Per-user IMAP accounts can override this global default.
|
||
IMAP_ATTACHMENT_FILTER=documents_only
|
||
|
||
# **Storage/Document Services**
|
||
# Amazon S3
|
||
# S3_ENABLED=true # Set to false to disable S3 uploads without removing credentials
|
||
AWS_REGION=us-east-1
|
||
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
|
||
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
||
S3_BUCKET_NAME=my-document-bucket
|
||
S3_FOLDER_PREFIX=documents/uploads/2023/ # Organizes files in this subfolder
|
||
S3_STORAGE_CLASS=STANDARD
|
||
S3_ACL=private
|
||
|
||
# NextCloud
|
||
# NEXTCLOUD_ENABLED=true # Set to false to disable NextCloud uploads without removing credentials
|
||
NEXTCLOUD_UPLOAD_URL=https://nextcloud.example.com/remote.php/dav/files/<USERNAME>
|
||
NEXTCLOUD_FOLDER="<NEXTCLOUD_FOLDER_PATH>"
|
||
NEXTCLOUD_USERNAME=<NEXTCLOUD_USERNAME>
|
||
NEXTCLOUD_PASSWORD=<NEXTCLOUD_PASSWORD>
|
||
|
||
# Paperless-ngx
|
||
# PAPERLESS_ENABLED=true # Set to false to disable Paperless uploads without removing credentials
|
||
PAPERLESS_HOST=https://paperless.example.com
|
||
PAPERLESS_NGX_API_TOKEN=<PAPERLESS_API_TOKEN>
|
||
# Optional: Name of the custom field in Paperless-ngx to store the "absender" (sender) value
|
||
# If set, the extracted sender information will be automatically set as a custom field in Paperless
|
||
# Example: PAPERLESS_CUSTOM_FIELD_ABSENDER=Absender
|
||
# PAPERLESS_CUSTOM_FIELD_ABSENDER=
|
||
|
||
# Optional: JSON mapping of metadata fields to Paperless custom field names
|
||
# This allows you to map multiple extracted metadata fields to custom fields in Paperless
|
||
# The mapping format is: {"metadata_field_name": "PaperlessCustomFieldName", ...}
|
||
# Available metadata fields: absender, empfaenger, correspondent, document_type, language,
|
||
# kommunikationsart, kommunikationskategorie, reference_number, etc.
|
||
# Example: PAPERLESS_CUSTOM_FIELDS_MAPPING={"absender": "Sender", "empfaenger": "Recipient", "language": "Language", "correspondent": "Correspondent"}
|
||
# PAPERLESS_CUSTOM_FIELDS_MAPPING=
|
||
|
||
# Dropbox
|
||
# DROPBOX_ENABLED=true # Set to false to disable Dropbox uploads without removing credentials
|
||
DROPBOX_APP_KEY=<DROPBOX_APP_KEY>
|
||
DROPBOX_APP_SECRET=<DROPBOX_APP_SECRET>
|
||
DROPBOX_REFRESH_TOKEN=<DROPBOX_REFRESH_TOKEN>
|
||
DROPBOX_FOLDER="/Documents/Uploads"
|
||
|
||
# Google Drive
|
||
# GOOGLE_DRIVE_ENABLED=true # Set to false to disable Google Drive uploads without removing credentials
|
||
# Service Account Method:
|
||
GOOGLE_DRIVE_CREDENTIALS_JSON={"type":"service_account","project_id":"your-project","private_key_id":"key-id","private_key":"-----BEGIN PRIVATE KEY-----\nYOUR_PRIVATE_KEY\n-----END PRIVATE KEY-----\n","client_email":"service-account@project.iam.gserviceaccount.com","client_id":"client-id","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/service-account%40project.iam.gserviceaccount.com"}
|
||
GOOGLE_DRIVE_FOLDER_ID=<YOUR_FOLDER_ID>
|
||
GOOGLE_DRIVE_DELEGATE_TO=<OPTIONAL_USER_EMAIL>
|
||
|
||
# OAuth Method (Alternative):
|
||
GOOGLE_DRIVE_USE_OAUTH=false # Set to true to use OAuth instead of service account
|
||
GOOGLE_DRIVE_CLIENT_ID=your-oauth-client-id # Required for OAuth method
|
||
GOOGLE_DRIVE_CLIENT_SECRET=your-oauth-client-secret # Required for OAuth method
|
||
GOOGLE_DRIVE_REFRESH_TOKEN=your-oauth-refresh-token # Required for OAuth method
|
||
|
||
# OneDrive
|
||
# ONEDRIVE_ENABLED=true # Set to false to disable OneDrive uploads without removing credentials
|
||
ONEDRIVE_CLIENT_ID=your-client-id
|
||
ONEDRIVE_CLIENT_SECRET=your-client-secret
|
||
ONEDRIVE_TENANT_ID=common
|
||
ONEDRIVE_REFRESH_TOKEN=your-refresh-token
|
||
ONEDRIVE_FOLDER_PATH=Documents/Uploads
|
||
|
||
# SharePoint
|
||
SHAREPOINT_CLIENT_ID=your-client-id
|
||
SHAREPOINT_CLIENT_SECRET=your-client-secret
|
||
SHAREPOINT_TENANT_ID=common
|
||
SHAREPOINT_REFRESH_TOKEN=your-refresh-token
|
||
SHAREPOINT_SITE_URL=https://tenant.sharepoint.com/sites/sitename
|
||
SHAREPOINT_DOCUMENT_LIBRARY=Documents
|
||
SHAREPOINT_FOLDER_PATH=Uploads
|
||
|
||
# WebDAV
|
||
# WEBDAV_ENABLED=true # Set to false to disable WebDAV uploads without removing credentials
|
||
WEBDAV_URL=https://webdav.example.com/path
|
||
WEBDAV_USERNAME=webdav_user
|
||
WEBDAV_PASSWORD=your_secure_webdav_password
|
||
WEBDAV_FOLDER=/Documents/Uploads
|
||
WEBDAV_VERIFY_SSL=True
|
||
|
||
# FTP
|
||
# FTP_ENABLED=true # Set to false to disable FTP uploads without removing credentials
|
||
# Security Note: FTP_USE_TLS=True is strongly recommended for secure connections
|
||
# Set FTP_ALLOW_PLAINTEXT=False in production to prevent unencrypted FTP
|
||
FTP_HOST=ftp.example.com
|
||
FTP_PORT=21
|
||
FTP_USERNAME=ftp_user
|
||
FTP_PASSWORD=your_secure_ftp_password
|
||
FTP_FOLDER=/Documents/Uploads
|
||
FTP_USE_TLS=True
|
||
FTP_ALLOW_PLAINTEXT=True
|
||
|
||
# SFTP
|
||
# SFTP_ENABLED=true # Set to false to disable SFTP uploads without removing credentials
|
||
# Security Note: Host key verification is enabled by default (False)
|
||
# Only set to True in development/testing environments if needed
|
||
# When false, configure SSH known_hosts for proper host key verification
|
||
SFTP_HOST=sftp.example.com
|
||
SFTP_PORT=22
|
||
SFTP_USERNAME=sftp_user
|
||
SFTP_PASSWORD=your_secure_sftp_password
|
||
# SFTP_PRIVATE_KEY=/path/to/private_key.pem
|
||
# SFTP_PRIVATE_KEY_PASSPHRASE=optional_passphrase
|
||
SFTP_FOLDER=/Documents/Uploads
|
||
SFTP_DISABLE_HOST_KEY_VERIFICATION=False # Default is False (secure); set to True only for testing
|
||
|
||
# iCloud Drive
|
||
# ICLOUD_ENABLED=true # Set to false to disable iCloud uploads without removing credentials
|
||
# Requires an Apple ID with iCloud Drive enabled.
|
||
# For accounts with two-factor authentication (most accounts), generate an
|
||
# app-specific password at https://appleid.apple.com/account/manage
|
||
ICLOUD_USERNAME=your_apple_id@example.com
|
||
ICLOUD_PASSWORD=your-app-specific-password
|
||
ICLOUD_FOLDER=Documents/Uploads
|
||
# ICLOUD_COOKIE_DIRECTORY=/path/to/cookie/dir # Optional: defaults to ~/.pyicloud
|
||
|
||
# **HTTP Request Settings**
|
||
# Timeout for HTTP requests - set higher to handle large PDF files (up to 1GB)
|
||
HTTP_REQUEST_TIMEOUT=120 # Timeout in seconds (default: 120 for large file operations)
|
||
|
||
# **Notification Settings**
|
||
# Configure notification services using Apprise URL format
|
||
# See https://github.com/caronc/apprise#supported-notifications
|
||
# Examples:
|
||
# - Discord: discord://webhook_id/webhook_token
|
||
# - Telegram: tgram://bot_token/chat_id
|
||
# - Email: mailto://user:pass@example.com
|
||
# - Pushover: pover://user_key/app_token
|
||
# - Slack: slack://tokenA/tokenB/tokenC
|
||
# - Matrix: matrix://username:password@domain/#room
|
||
|
||
# You can specify multiple notification URLs by separating them with commas
|
||
NOTIFICATION_URLS=discord://webhook_id/webhook_token,mailto://user:pass@gmail.com,tgram://bot_token/chat_id
|
||
|
||
# Control when notifications are sent
|
||
NOTIFY_ON_TASK_FAILURE=True
|
||
NOTIFY_ON_CREDENTIAL_FAILURE=True
|
||
NOTIFY_ON_STARTUP=True
|
||
NOTIFY_ON_SHUTDOWN=False
|
||
NOTIFY_ON_FILE_PROCESSED=True
|
||
|
||
# Webhooks – Notify external systems via HTTP POST on document events.
|
||
# Individual webhooks (URL, events, secret) are managed via /api/webhooks/.
|
||
WEBHOOK_ENABLED=True
|
||
|
||
# Uptime Kuma
|
||
UPTIME_KUMA_URL=https://status.example.com/api/push/abcdef123456?status=up
|
||
UPTIME_KUMA_PING_INTERVAL=5
|
||
|
||
# Backup & Restore
|
||
# Enable automatic scheduled backups (hourly, daily, weekly)
|
||
BACKUP_ENABLED=True
|
||
# Directory for local backup archives (defaults to <WORKDIR>/backups)
|
||
# BACKUP_DIR=/data/backups
|
||
# Optional remote destination: s3, dropbox, google_drive, onedrive, nextcloud, webdav, ftp, sftp, email
|
||
# BACKUP_REMOTE_DESTINATION=s3
|
||
# Sub-folder used when uploading backup archives to the remote destination
|
||
BACKUP_REMOTE_FOLDER=backups
|
||
# Retention: number of snapshots to keep per tier
|
||
BACKUP_RETAIN_HOURLY=96 # 4 days of hourly snapshots
|
||
BACKUP_RETAIN_DAILY=21 # 3 weeks of daily snapshots
|
||
BACKUP_RETAIN_WEEKLY=13 # ~3 months of weekly snapshots
|
||
|
||
# **Full-Text Search (Meilisearch)**
|
||
# URL for the Meilisearch instance.
|
||
# Default is "http://meilisearch:7700" — the Docker Compose / K8s service name —
|
||
# so container-to-container networking works without extra configuration.
|
||
# Override to "http://localhost:7700" only when running the API process outside Docker.
|
||
MEILISEARCH_URL=http://meilisearch:7700
|
||
# Optional master/API key for secured Meilisearch instances
|
||
# MEILISEARCH_API_KEY=your_master_key_here
|
||
MEILISEARCH_INDEX_NAME=documents
|
||
ENABLE_SEARCH=True
|
||
|
||
# **Duplicate Detection**
|
||
# Exact duplicate detection (SHA-256) is always on during document processing.
|
||
# The settings below control near-duplicate detection (same scanned content,
|
||
# different hash) and the visibility of deduplication steps.
|
||
ENABLE_DEDUPLICATION=True
|
||
SHOW_DEDUPLICATION_STEP=True
|
||
# Minimum cosine similarity score (0–1) for two documents to be flagged as
|
||
# near-duplicates. 0.85 means 85 % semantic overlap. Lower = more matches.
|
||
NEAR_DUPLICATE_THRESHOLD=0.85
|
||
|
||
# **PDF/A Archival Conversion**
|
||
# When enabled, PDF/A copies of both the original ingested file and the processed
|
||
# file are created and saved alongside the standard copies. This may double or
|
||
# triple storage but provides better legal coverage with time-stamped archival copies.
|
||
# Uses ocrmypdf with Ghostscript for the conversion.
|
||
ENABLE_PDFA_CONVERSION=false
|
||
# PDF/A format variant: 1 = PDF/A-1b, 2 = PDF/A-2b (default), 3 = PDF/A-3b
|
||
PDFA_FORMAT=2
|
||
# Upload original-file PDF/A variant to all configured storage providers
|
||
PDFA_UPLOAD_ORIGINAL=false
|
||
# Upload processed-file PDF/A variant to all configured storage providers
|
||
PDFA_UPLOAD_PROCESSED=false
|
||
# Subfolder name appended to each provider's folder for PDF/A uploads
|
||
# e.g. if Dropbox folder is '/Documents' this puts PDF/A files into '/Documents/pdfa'
|
||
PDFA_UPLOAD_FOLDER=pdfa
|
||
# Google Drive folder ID for PDF/A uploads (uses folder IDs, not paths)
|
||
# Leave empty to use the same folder as regular uploads
|
||
GOOGLE_DRIVE_PDFA_FOLDER_ID=
|
||
# RFC 3161 timestamping of PDF/A files (creates .tsr proof-of-existence files)
|
||
PDFA_TIMESTAMP_ENABLED=false
|
||
# Timestamp Authority URL (default: FreeTSA, a free RFC 3161 TSA)
|
||
PDFA_TIMESTAMP_URL=https://freetsa.org/tsr
|
||
# Model used to generate text embeddings for document similarity.
|
||
# Must be supported by your OpenAI-compatible API endpoint.
|
||
EMBEDDING_MODEL=text-embedding-3-small
|
||
# Maximum tokens to send to the embedding model. Set below the model's
|
||
# context window (e.g. 8000 for an 8192-token model).
|
||
EMBEDDING_MAX_TOKENS=8000
|
||
|
||
# **Support / Help Center – Zammad Integration**
|
||
# Base URL of your Zammad instance (required for chat and ticket form).
|
||
# ZAMMAD_URL=https://zammad.example.com
|
||
# Show a live-chat widget on the Help Center page (requires an online Zammad agent).
|
||
# ZAMMAD_CHAT_ENABLED=false
|
||
# Zammad chat topic ID (see Zammad → Channels → Chat → Topics).
|
||
# ZAMMAD_CHAT_ID=1
|
||
# Show a "Submit a Ticket" feedback form on the Help Center page.
|
||
# ZAMMAD_FORM_ENABLED=false
|
||
# Support e-mail address displayed on the Help Center page.
|
||
# SUPPORT_EMAIL=support@example.com
|
||
|
||
# **Observability – Sentry Error & Performance Monitoring**
|
||
# Sentry DSN – obtain from https://sentry.io (Project → Settings → Client Keys).
|
||
# Leave commented out (or set to empty) to disable Sentry entirely.
|
||
# SENTRY_DSN=https://<key>@o<org>.ingest.sentry.io/<project>
|
||
#
|
||
# Environment label shown in the Sentry dashboard (e.g. development / staging / production).
|
||
# SENTRY_ENVIRONMENT=production
|
||
#
|
||
# Fraction of requests to capture for performance tracing (0.0–1.0).
|
||
# 0.0 disables tracing; 1.0 captures every request. Default: 0.1 (10 %).
|
||
# SENTRY_TRACES_SAMPLE_RATE=0.1
|
||
#
|
||
# Fraction of profiled transactions to send to Sentry (0.0–1.0).
|
||
# Profiling is only active when SENTRY_TRACES_SAMPLE_RATE > 0. Default: 0.0 (disabled).
|
||
# SENTRY_PROFILES_SAMPLE_RATE=0.0
|
||
#
|
||
# Attach PII (IP addresses, user agents) to Sentry events.
|
||
# Disable (default) to stay GDPR/CCPA compliant.
|
||
# SENTRY_SEND_DEFAULT_PII=false
|
||
|
||
# **Mobile App – Push Notifications**
|
||
# Push notifications are delivered via Expo's push notification service
|
||
# (https://expo.dev/notifications) which routes to APNs (iOS) and FCM (Android).
|
||
# No additional credentials are required on the server side.
|
||
# The mobile app registers its Expo push token via POST /api/mobile/register-device.
|
||
#
|
||
# To use native FCM/APNs directly (without Expo relay), replace the
|
||
# send_expo_push_notification function in app/utils/push_notification.py.
|