Secrets redacted. This is a live environment file. Variable names and comments are shown; every value is replaced with a blurred bar before it reaches your browser — the secret is never transmitted.
1# --------------------------------------------------------------------------- 2# AI Software Factory — environment configuration 3# Copy to .env and fill in real values. NEVER commit secrets to source control. 4# --------------------------------------------------------------------------- 5 6# App 7NODE_ENV= 8PORT= 9WEB_URL= 10# Server-to-server base (realtime → API internal endpoints, web /health/ready 11# probe). Loopback by design: these are local service-to-service calls, not 12# browser-facing — the public origin for browsers is NEXT_PUBLIC_API_URL above. 13API_URL= 14REALTIME_URL= 15PUBLIC_BASE_URL= 16 17# --- Reverse proxy (Caddy) — keep in sync with the /etc/caddy/Caddyfile --- 18# Topology: 19# notion.filps.com = THE app origin. Caddy serves the web UI and reverse- 20# proxies /api/v1/*, /saml/*, /sso/*, /realtime* and the S3 bucket 21# prefixes (/factory-files/*, /factory-thumbs/* → the S3 shim :9000) 22# to the local service ports. The BROWSER talks only to this 23# origin, so the host-scoped httpOnly `factory_refresh` cookie (no 24# Domain= attr — see apps/api/src/common/cookies.ts) satisfies the web 25# middleware's session gate (apps/web/src/middleware.ts) without any 26# cross-host cookie sharing. 27# aiops.filps.com = direct access to the backend API (webhook deliveries, 28# API-key clients, /docs, programmatic use). Not browser-facing. 29CORS_ORIGINS= 30WEB_ORIGIN= 31SSO_ORIGIN= 32WEBHOOK_BASE_URL= 33# Browser-facing bases (NEXT_PUBLIC_* are inlined into the web bundle at 34# `next dev` startup). 35NEXT_PUBLIC_API_URL= 36NEXT_PUBLIC_WS_URL= 37NEXT_PUBLIC_APP_URL= 38 39# Database (PostgreSQL) 40 41# Redis (caching, queues, presence) 42 43# Auth / Sessions 44JWT_EXPIRES_IN= 45REFRESH_TOKEN_TTL_DAYS= 46BCRYPT_ROUNDS= 47 48# S3-compatible object storage (local: the S3 shim at :9000, reached THROUGH 49# the frontend origin — see S3_ENDPOINT below) — TASK-0101 (two private 50# buckets; `S3_BUCKET` is the legacy alias for S3_BUCKET_FILES). 51S3_BUCKET_FILES= 52S3_BUCKET_THUMBS= 53S3_BUCKET= 54S3_REGION= 55S3_FORCE_PATH_STYLE= 56S3_SIGN_EXPIRY_SECONDS= 57# ClamAV (dev mode = empty; Docker profile sets CLAMAV_HOST=clamav:3310) 58CLAMD_SOCKET= 59CLAMAV_HOST= 60CLAMAV_PORT= 61 62# Search (OpenSearch) 63SEARCH_USERNAME= 64SEARCH_PASSWORD= 65SEARCH_INDEX_PREFIX= 66# Content-index dense_vector tuning (TASK-0099 — dimensions are immutable per 67# index; a change rolls a new index via `pnpm search:reindex`). HNSW: m / 68# ef_construction, dimension = the embedding model's output (1536 = 69# text-embedding-3-small). 70SEARCH_VECTOR_DIMENSION= 71SEARCH_KNN_M= 72SEARCH_KNN_EF_CONSTRUCTION= 73 74# AI gateway (provider-agnostic; any OpenAI-compatible endpoint works) 75# Wired to the OpenAI-compatible self-hosted gateway (key from 76# ai-api-key.txt in the repo root). The key only grants `qwen3.8-27B` (a vLLM 77# reasoning model); embeddings 403 for this key, so AI_EMBEDDING_PROVIDER 78# stays EMPTY and the embed:chunks job skips (vectors stay null). 79AI_PROVIDER= 80AI_BASE_URL= 81AI_API_KEY= 82AI_MODEL= 83AI_EMBEDDING_MODEL= 84# Embedding provider for the `embed:chunks` job (TASK-0099). EMPTY (default) 85# = no real provider wired: the job logs "embedding disabled (Phase 12)" and 86# skips (the chunk docs' vector stays null). Set to a provider name to record 87# placeholder AiEmbedding cache rows until Phase 12 wires the real call. 88AI_EMBEDDING_PROVIDER= 89# --- OSS-reasoning-model tuning (qwen3.8-27B via vLLM; root-cause fixes) --- 90# Page-generation total cap (default 120 s): the forced generatePlan tool 91# call still needs ~130 s for a detailed plan (long silent reasoning phase 92# first). 600 s leaves generous margin; the client can cancel earlier. 93AI_GENERATE_TIMEOUT_MS= 94# Max gap between streamed BYTES (default 30 s): the model's silent thinking 95# phase produced a 39 s gap in probes → mid-stream 504 the gateway cannot 96# retry. 90 s covers it. 97AI_STREAM_IDLE_MS= 98# Output-token clamp (default 4096): the model emits ~9 k reasoning tokens 99# BEFORE the plan JSON; a 4096 clamp truncated the plan mid-stream. 100AI_MAX_OUTPUT_TOKENS= 101 102# Email (SMTP) 103SMTP_HOST= 104SMTP_PORT= 105SMTP_USER= 106SMTP_PASSWORD= 107SMTP_FROM= 108 109# Realtime 110REALTIME_PORT= 111REALTIME_HEARTBEAT_MS= 112YJS_STORAGE_PREFIX= 113# Shared service token for the internal endpoints (`/internal/*`, TASK-0092 114# slice 2): the realtime gateway authenticates to the api's internal block 115# endpoints (hydration read + the flush's CAS persist) with this bearer 116# token. Empty (default) = the internal endpoints are CLOSED (fail-closed). 117 118# Webhooks 119WEBHOOK_RETRY_MAX= 120WEBHOOK_TIMEOUT_MS= 121# DEV-ONLY (E2E exit scenario, TASK-0130): allow loopback delivery URLs and a 122# short retry backoff so the visible-retries window is observable in ~15s. 123# The canonical production defaults are 30s/15min (proven by the integration 124# suite on a mocked clock). Remove these lines to restore. 125WEBHOOK_ALLOW_PRIVATE= 126WEBHOOK_BACKOFF_BASE_MS= 127WEBHOOK_BACKOFF_MAX_MS= 128 129# Rate limiting 130# NOTE: the realtime app reads RATE_LIMIT_WINDOW_MS / RATE_LIMIT_MAX. The API 131# guard (apps/api/src/common/guards/rate-limit.guard.ts) reads a DIFFERENT pair 132# — RATE_LIMIT_API / RATE_LIMIT_AUTH (per user/min) — so the two lines above 133# do NOT affect the API. The API guard's defaults (100/min, 10/min) throttle 134# the local full-stack E2E (which legitimately makes many calls), so they are 135# raised high here for local dev/E2E only (this .env is gitignored; CI sets its 136# own). Recorded in the Phase 11 gap report as a pre-existing env-naming split. 137RATE_LIMIT_WINDOW_MS= 138RATE_LIMIT_MAX= 139RATE_LIMIT_API= 140RATE_LIMIT_AUTH= 141 142# Observability (optional; enable in Phase 15) 143OTEL_ENABLED= 144OTEL_EXPORTER_OTLP_ENDPOINT= 145 146# Encryption (application-level secret encryption, at-rest secrets) 147DATABASE_URL= 148REDIS_URL= 149SEARCH_URL= 150# Public S3 base: the shim at :9000 behind the app origin. Caddy routes 151# the two bucket prefixes (/factory-files/*, /factory-thumbs/*) to 152# 127.0.0.1:9000 preserving Host (no path rewrite). MUST be a bare 153# origin (no path): both S3 clients (packages/storage, worker) derive 154# the signed `host` header from the endpoint authority, and the worker 155# client builds URLs as `origin + path`. Presigned URLs + the browser's 156# direct upload XHR are then SAME-ORIGIN with the web app (CSP `img-src`/ 157# `connect-src` `'self'` covers them — no CSP change needed). SigV4 158# survives the proxy because the signed host = endpoint authority and 159# Caddy forwards the original Host unchanged. 160S3_ENDPOINT= 161S3_ACCESS_KEY= 162S3_SECRET_KEY= 163JWT_SECRET= 164REFRESH_TOKEN_SECRET= 165SESSION_SECRET= 166MASTER_ENCRYPTION_KEY= 167INTERNAL_SERVICE_TOKEN= 168INTERNAL_TEST_SEAM= 169