# Environment variables This table covers the variables in `.env.example`, their Docker Compose mappings, and runtime variables read directly by the API, UI, AI service, or test harness. Blank means no repository default; “conditional” means required only when that feature/provider is enabled. ## Database and application | Variable | Required | Service | Secret | Default | Description | |---|---|---|---|---|---| | `DATABASE_PROVIDER` | Production | Compose/API | No | `sqlite` | `sqlite`, `mariadb`, or `mysql`; also selects the backup path. | | `JOBTRACKER_CONNECTION_STRING` | Conditional | API | Yes | — | Server database connection string; ignored for SQLite. | | `APP_PUBLIC_BASE_URL` | Production | API/UI | No | — | Canonical external origin for links, callbacks, cookies, billing, and host validation. | | `APP_VERSION` | No | API | No | — | Release/version metadata. | | `APP_COMMIT_SHA` | No | API | No | — | Release commit metadata. | | `APP_BUILD_STAMP` | No | API | No | — | Release build timestamp metadata. | | `NEXT_PUBLIC_API_BASE_URL` | No | UI build | No | `/api` | Browser-visible API origin; leave blank for nginx same-origin proxy. | ## Authentication, identity, and billing | Variable | Required | Service | Secret | Default | Description | |---|---|---|---|---|---| | `AUTH_JWT_KEY` | Production | API | Yes | — | Local JWT signing key; required when auth is required. | | `AUTH_ADMIN_EMAIL` | Conditional | API | No | — | Seed/admin account email. | | `AUTH_ADMIN_PASSWORD` | Conditional | API | Yes | — | Seed/admin account password. | | `AUTH_ALLOW_REGISTRATION` | No | API | No | `false` | Enables local self-registration. | | `AUTH_REQUIRE_EMAIL_VERIFICATION` | No | API | No | `true` | Requires verified local-account email before sign-in. | | `ACCOUNT_DELETION_ENABLED` | No | API | No | `false` | Self-service deletion gate; keep disabled until retention/restore policy is approved. | | `TURNSTILE_SITE_KEY` | Conditional | API/UI | No | — | Public Turnstile site key. | | `TURNSTILE_SECRET_KEY` | Conditional | API | Yes | — | Server-side Turnstile verification secret. | | `AUTH_GOOGLE_CLIENT_ID` | Conditional | API/UI | No | — | Google sign-in client ID. | | `AUTH_MICROSOFT_CLIENT_ID` | Conditional | API/UI | No | — | Microsoft sign-in client ID. | | `AUTH_MICROSOFT_TENANT` | No | API/UI | No | `common` | Microsoft sign-in tenant policy; distinct from Graph tenant. | | `STRIPE_SECRET_KEY` | Conditional | API | Yes | — | Hosted Checkout/portal server key. | | `STRIPE_PRICE_PREMIUM` | Conditional | API | No | — | Recurring Premium Stripe Price ID (`price_...`). | | `STRIPE_WEBHOOK_SECRET` | Conditional | API | Yes | — | Signed billing webhook secret. | ## Mail-provider connections | Variable | Required | Service | Secret | Default | Description | |---|---|---|---|---|---| | `GOOGLE_GMAIL_CLIENT_SECRET` | Conditional | API | Yes | — | Gmail OAuth client secret. | | `MICROSOFT_CLIENT_ID` | Conditional | API | No | — | Microsoft Graph mail application ID; separate from sign-in ID. | | `MICROSOFT_CLIENT_SECRET` | Conditional | API | Yes | — | Microsoft Graph OAuth secret. | | `MICROSOFT_TENANT_ID` | Conditional | API | No | — | Graph mailbox tenant; separate from `AUTH_MICROSOFT_TENANT`. | ## AI and document processing | Variable | Required | Service | Secret | Default | Description | |---|---|---|---|---|---| | `AI_SERVICE_BASE_URL` | Docker | API | No | `http://ai-service:8001` | Internal FastAPI service URL. | | `AI_SERVICE_TOKEN` | Docker/prod | API/AI | Yes | — | Shared backend-to-sidecar token; required by Compose except `/health`. | | `OLLAMA_BASE_URL` | No | AI | No | `http://ollama:11434` | Ollama endpoint. | | `OLLAMA_MODEL` | No | AI | No | `qwen2.5:7b` | Local Ollama model. | | `AI_PROVIDER` | No | API/AI | No | `ollama` | Structured CV provider: `ollama`, `gemini`, or `groq`. | | `EXTERNAL_AI_ENABLED` | No | API/AI | No | `false` | Administrator gate for external processing. | | `AI_ROUTING_MODE` | No | API/AI | No | `local_first` | `local_only`, `local_first`, or `external_only`. | | `EXTERNAL_AI_ALLOWED_TASKS` | No | AI | No | CV task list | Allowlisted external task types. | | `EXTERNAL_AI_MAX_PROMPT_CHARS` | No | AI | No | `24000` | External prompt-size ceiling. | | `LOCAL_AI_CIRCUIT_FAILURE_THRESHOLD` | No | AI | No | `3` | Local-provider failures before circuit opens. | | `LOCAL_AI_CIRCUIT_OPEN_SECONDS` | No | AI | No | `30` | Circuit-open duration. | | `PARSER_TIMEOUT_SECONDS` | No | AI | No | `25` | Parser wall-clock budget. | | `PARSER_CPU_SECONDS` | No | AI | No | `20` | Linux parser CPU budget. | | `PARSER_MEMORY_MIB` | No | AI | No | `512` | Linux parser address-space budget. | | `PARSER_STALE_WORK_SECONDS` | No | AI | No | `3600` | Age at which stale parser work is reconciled. | | `GEMINI_API_KEY` | Conditional | AI | Yes | — | Gemini provider key. | | `GEMINI_MODEL` | No | AI | No | `gemini-2.0-flash` | Gemini model. | | `GROQ_API_KEY` | Conditional | AI | Yes | — | Groq provider key. | | `GROQ_MODEL` | No | AI | No | `llama-3.3-70b-versatile` | Groq model. | | `WORKER_AI_OPERATIONS_ENABLED` | No | API | No | `false` | Durable AI worker gate. | | `AI_QUEUE_WORKER_CONCURRENCY` | No | API | No | `1` | AI worker concurrency. | | `AI_QUEUE_GLOBAL_CAPACITY` | No | API | No | `100` | Global queued-operation capacity. | | `AI_QUEUE_PER_USER_CAPACITY` | No | API | No | `10` | Per-user queued-operation capacity. | | `AI_QUEUE_DEADLINE_MINUTES` | No | API | No | `15` | Queue deadline. | | `AI_QUEUE_OPERATION_TIMEOUT_SECONDS` | No | API | No | `300` | Operation timeout. | ## Ingress, deployment, maintenance, and backups | Variable | Required | Service | Secret | Default | Description | |---|---|---|---|---|---| | `WEB_PROXY_SUBNET` | Production | Compose | No | `172.31.250.0/29` | Dedicated nginx/backend network; verify no overlap. | | `INGRESS_PROXY_CIDRS` | Production | Frontend | No | — | Trusted reverse-proxy socket peers. | | `MAINTENANCE_GITEA_BASE_URL` | No | API | No | `https://git.cesnimda.uk` | Gitea API base for allowlisted maintenance jobs. | | `MAINTENANCE_GITEA_OWNER` | No | API | No | `cesnimda` | Gitea owner. | | `MAINTENANCE_GITEA_REPOSITORY` | No | API | No | `jobtrackingapp` | Gitea repository. | | `MAINTENANCE_GITEA_TOKEN` | Conditional | API | Yes | — | Narrowly scoped workflow-dispatch token. | | `BACKUP_TIMEZONE` | No | Ops | No | `Europe/Oslo` | Backup schedule timezone. | | `BACKUP_DAILY_RETENTION_DAYS` | No | Ops | No | `30` | Daily recovery-set retention. | | `BACKUP_MONTHLY_RETENTION_COUNT` | No | Ops | No | `12` | Monthly recovery-set count. | | `BACKUP_RCLONE_REMOTE` | No | Ops | Yes/depends | — | Optional encrypted remote destination. | ## Email and workers | Variable | Required | Service | Secret | Default | Description | |---|---|---|---|---|---| | `EMAIL_ENABLED` | No | API | No | `false` | Enables SMTP delivery. | | `EMAIL_SMTP_HOST` | Conditional | API | No | `smtp.gmail.com` | SMTP host. | | `EMAIL_SMTP_PORT` | Conditional | API | No | `587` | SMTP port. | | `EMAIL_SMTP_USER` | Conditional | API | No | — | SMTP username. | | `EMAIL_SMTP_PASSWORD` | Conditional | API | Yes | — | SMTP password/app password. | | `EMAIL_FROM` | No | API | No | SMTP user | Sender address. | | `EMAIL_FROM_NAME` | No | API | No | `Jobbjakt` | Sender display name. | | `EMAIL_FOLLOWUPREMINDERS_ENABLED` | No | API | No | `false` | Reminder-email gate. | | `EMAIL_FOLLOWUPREMINDERS_UPCOMINGDAYS` | No | API | No | `2` | Reminder look-ahead days. | | `EMAIL_SMTP_ENABLE_SSL` | No | API | No | `true` | SMTP TLS setting. | | `EMAIL_SMTP_TIMEOUT_MS` | No | API | No | `15000` | SMTP timeout. | | `WORKER_RULES_ENABLED` | No | API | No | `false` | Rules/ghosting worker gate. | | `WORKER_FOLLOWUP_REMINDERS_ENABLED` | No | API | No | `false` | Reminder worker gate. | | `WORKER_SAVED_SEARCH_ALERTS_ENABLED` | No | API | No | `true` | Saved-search alert worker gate. | | `SAVED_SEARCH_INTERVAL_HOURS` | No | API | No | `6` | Saved-search interval. | | `WORKER_DAILY_EXPORT_ENABLED` | No | API | No | `false` | Daily export worker gate. | | `WORKER_JOB_ENRICHMENT_ENABLED` | No | API | No | `false` | Job enrichment worker gate. | ## Runtime-only variables The source also accepts `CV_FORCE_AI_NORMALIZER`, `CV_PDF_BROWSER_PATH`, `PARSER_TEMP_ROOT`, `GEMINI_BASE_URL`, `GROQ_BASE_URL`, `AI_SERVICE_SKIP_MODEL_LOAD`, and `AI_SERVICE_EAGER_MODEL_LOAD`. These are local/diagnostic/sidecar overrides and are intentionally not in the operator `.env.example`; see the relevant AI and testing guides. `GOOGLE_GMAIL_REDIRECT_URI` and `MICROSOFT_REDIRECT_URI` were present in the pre-cleanup local `.env` but have no current Compose/source consumer; they are retained locally for review and intentionally omitted from the template. `REACT_APP_API_BASE_URL` and `REACT_APP_GOOGLE_CLIENT_ID` are obsolete CRA names and must not be added back.