# ------------------------------ # Compose + Database # ------------------------------ POSTGRES_DB=scholar POSTGRES_USER=scholar POSTGRES_PASSWORD=change-me DATABASE_URL=postgresql+asyncpg://scholar:scholar@db:5432/scholar # Optional override. If empty, tests derive "_test". TEST_DATABASE_URL= SCHOLARR_IMAGE=justinzeus/scholarr:latest # ------------------------------ # App Runtime + Networking # ------------------------------ APP_NAME=scholarr APP_HOST=0.0.0.0 APP_PORT=8000 APP_HOST_PORT=8000 APP_RELOAD=0 MIGRATE_ON_START=1 FRONTEND_ENABLED=1 FRONTEND_DIST_DIR=/app/frontend/dist # ------------------------------ # Database Pool # ------------------------------ DATABASE_POOL_MODE=auto DATABASE_POOL_SIZE=5 DATABASE_POOL_MAX_OVERFLOW=10 DATABASE_POOL_TIMEOUT_SECONDS=30 # ------------------------------ # Frontend Dev Overrides # ------------------------------ FRONTEND_HOST_PORT=5173 CHOKIDAR_USEPOLLING=1 VITE_DEV_API_PROXY_TARGET=http://app:8000 # ------------------------------ # Auth + Session # ------------------------------ SESSION_SECRET_KEY=replace-with-a-long-random-secret-at-least-32-characters SESSION_COOKIE_SECURE=1 LOGIN_RATE_LIMIT_ATTEMPTS=5 LOGIN_RATE_LIMIT_WINDOW_SECONDS=60 # ------------------------------ # HTTP Security Headers + CSP # ------------------------------ SECURITY_HEADERS_ENABLED=1 SECURITY_X_CONTENT_TYPE_OPTIONS=nosniff SECURITY_X_FRAME_OPTIONS=DENY SECURITY_REFERRER_POLICY=strict-origin-when-cross-origin SECURITY_PERMISSIONS_POLICY=accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), microphone=(), payment=(), usb=() SECURITY_CROSS_ORIGIN_OPENER_POLICY=same-origin SECURITY_CROSS_ORIGIN_RESOURCE_POLICY=same-origin SECURITY_CSP_ENABLED=1 SECURITY_CSP_POLICY=default-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; img-src 'self' data: https:; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; connect-src 'self'; object-src 'none' SECURITY_CSP_DOCS_POLICY=default-src 'self'; img-src 'self' data: https:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; connect-src 'self' https:; object-src 'none'; frame-ancestors 'none' SECURITY_CSP_REPORT_ONLY=0 SECURITY_STRICT_TRANSPORT_SECURITY_ENABLED=0 SECURITY_STRICT_TRANSPORT_SECURITY_MAX_AGE=31536000 SECURITY_STRICT_TRANSPORT_SECURITY_INCLUDE_SUBDOMAINS=1 SECURITY_STRICT_TRANSPORT_SECURITY_PRELOAD=0 # ------------------------------ # Logging # ------------------------------ LOG_LEVEL=INFO LOG_FORMAT=console LOG_REQUESTS=1 LOG_UVICORN_ACCESS=0 LOG_REQUEST_SKIP_PATHS=/healthz LOG_REDACT_FIELDS= # ------------------------------ # Scheduler + Ingestion Safety # ------------------------------ SCHEDULER_ENABLED=1 SCHEDULER_TICK_SECONDS=60 SCHEDULER_QUEUE_BATCH_SIZE=10 INGESTION_AUTOMATION_ALLOWED=1 INGESTION_MANUAL_RUN_ALLOWED=1 INGESTION_MIN_RUN_INTERVAL_MINUTES=15 INGESTION_MIN_REQUEST_DELAY_SECONDS=2 INGESTION_NETWORK_ERROR_RETRIES=1 INGESTION_RETRY_BACKOFF_SECONDS=1.0 INGESTION_MAX_PAGES_PER_SCHOLAR=30 INGESTION_PAGE_SIZE=100 INGESTION_ALERT_BLOCKED_FAILURE_THRESHOLD=1 INGESTION_ALERT_NETWORK_FAILURE_THRESHOLD=2 INGESTION_ALERT_RETRY_SCHEDULED_THRESHOLD=3 INGESTION_SAFETY_COOLDOWN_BLOCKED_SECONDS=1800 INGESTION_SAFETY_COOLDOWN_NETWORK_SECONDS=900 INGESTION_CONTINUATION_QUEUE_ENABLED=1 INGESTION_CONTINUATION_BASE_DELAY_SECONDS=120 INGESTION_CONTINUATION_MAX_DELAY_SECONDS=3600 INGESTION_CONTINUATION_MAX_ATTEMPTS=6 # ------------------------------ # Scholar Images + Name Search Safety # ------------------------------ SCHOLAR_IMAGE_UPLOAD_DIR=/var/lib/scholarr/uploads SCHOLAR_IMAGE_UPLOAD_MAX_BYTES=2000000 SCHOLAR_NAME_SEARCH_ENABLED=1 SCHOLAR_NAME_SEARCH_CACHE_TTL_SECONDS=21600 SCHOLAR_NAME_SEARCH_BLOCKED_CACHE_TTL_SECONDS=300 SCHOLAR_NAME_SEARCH_CACHE_MAX_ENTRIES=512 SCHOLAR_NAME_SEARCH_MIN_INTERVAL_SECONDS=8.0 SCHOLAR_NAME_SEARCH_INTERVAL_JITTER_SECONDS=2.0 SCHOLAR_NAME_SEARCH_COOLDOWN_BLOCK_THRESHOLD=1 SCHOLAR_NAME_SEARCH_COOLDOWN_SECONDS=1800 SCHOLAR_NAME_SEARCH_ALERT_RETRY_COUNT_THRESHOLD=2 SCHOLAR_NAME_SEARCH_ALERT_COOLDOWN_REJECTIONS_THRESHOLD=3 # ------------------------------ # OA Enrichment + PDF Resolution # ------------------------------ UNPAYWALL_ENABLED=1 UNPAYWALL_EMAIL= UNPAYWALL_TIMEOUT_SECONDS=4.0 UNPAYWALL_MIN_INTERVAL_SECONDS=0.6 UNPAYWALL_MAX_ITEMS_PER_REQUEST=20 UNPAYWALL_RETRY_COOLDOWN_SECONDS=1800 UNPAYWALL_PDF_DISCOVERY_ENABLED=1 UNPAYWALL_PDF_DISCOVERY_MAX_CANDIDATES=5 UNPAYWALL_PDF_DISCOVERY_MAX_HTML_BYTES=500000 PDF_AUTO_RETRY_INTERVAL_SECONDS=86400 PDF_AUTO_RETRY_FIRST_INTERVAL_SECONDS=3600 PDF_AUTO_RETRY_MAX_ATTEMPTS=3 CROSSREF_ENABLED=1 CROSSREF_MAX_ROWS=10 CROSSREF_TIMEOUT_SECONDS=8.0 CROSSREF_MIN_INTERVAL_SECONDS=0.6 CROSSREF_MAX_LOOKUPS_PER_REQUEST=8 # ------------------------------ # Startup Bootstrap + DB Wait # ------------------------------ BOOTSTRAP_ADMIN_ON_START=0 BOOTSTRAP_ADMIN_EMAIL= BOOTSTRAP_ADMIN_PASSWORD= BOOTSTRAP_ADMIN_FORCE_PASSWORD=0 DB_WAIT_TIMEOUT_SECONDS=60 DB_WAIT_INTERVAL_SECONDS=2