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=development 8PORT=4000 9WEB_URL=http://localhost:3000 10API_URL=http://localhost:4000 11REALTIME_URL=ws://localhost:4001 12PUBLIC_BASE_URL=http://localhost:3000 13# TASK-0131: the public origin that SERVES the SSO protocol surface 14# (/saml/*, /sso/*, later /scim/*) — these are browser bindings mounted by 15# the API outside /api/v1. In two-origin dev (web :3000 + api :4000) this 16# must be the API origin, or the IdP's POST to the ACS and the browser 17# start/authorize GETs will 404 on the web origin. 18# Leave UNSET/empty for single-origin deployments (the reference nginx 19# fronts web + api under one host — WEB_URL serves both). 20SSO_ORIGIN=http://localhost:4000 21 22# --- Reverse proxy (two domains) — see infrastructure/caddy/Caddyfile ------- 23# Deployment: <app-domain> = the app origin (UI + /api/v1/* + /realtime + 24# S3 presigned URLs); <api-domain> = direct backend API surface (webhook 25# deliveries, API-key clients, /api/v1/docs, IdP SCIM/ACS). The BROWSER talks 26# only to <app-domain>, so the host-scoped httpOnly `factory_refresh` cookie 27# (no Domain= attr) satisfies the web middleware's session gate without 28# cross-host cookie sharing. Leave the localhost values for local dev. 29# Two-domain deploy: CORS_ORIGINS/WEB_ORIGIN/NEXT_PUBLIC_API_URL → 30# https://<app-domain> (…/api/v1); NEXT_PUBLIC_WS_URL → wss://<app-domain>; 31# WEBHOOK_BASE_URL → https://<api-domain>/api/v1. 32CORS_ORIGINS=http://localhost:3000 33WEB_ORIGIN=http://localhost:3000 34WEBHOOK_BASE_URL=http://localhost:4000/api/v1 35# NEXT_PUBLIC_*: inlined into the web bundle at `next dev`/`build` startup. 36NEXT_PUBLIC_API_URL=http://localhost:4000/api/v1 37NEXT_PUBLIC_WS_URL=ws://localhost:4001 38NEXT_PUBLIC_APP_URL=http://localhost:3000 39 40# Database (PostgreSQL) 41DATABASE_URL=postgresql://factory:factory@localhost:5432/factory?schema=public 42# Read replica (Phase 15 — OPTIONAL). When set, db.read() (tree loads, record 43# listing/table views, search) routes to this URL and db.write() stays on 44# DATABASE_URL. Permission decisions + If-Match/baseVersion version checks are 45# NEVER replica reads (write-then-read-your-write always hits the primary). 46# In staging this is the PgBouncer `reader` pool on the read replica 47# (infrastructure/kubernetes/postgres/replica.yaml). Leave EMPTY in dev. 48DATABASE_REPLICA_URL= 49# Per-app PgBouncer pool_size share (Phase 15). PgBouncer (transaction mode) 50# owns connection pooling — Prisma 5.22 has no client-side pool — so this is 51# the app's share of the pooler, NOT a Prisma option (see 52# docs/development/deployment.md §3.1 pooling + perf-report §6). 53DATABASE_POOL_SIZE=20 54# Perf-cache gate (Phase 15): auto = on only in production (off in dev/tests), 55# on = force on, off = force off. See docs/development/perf-report.md §5. 56PERF_CACHE=auto 57 58# Redis (caching, queues, presence) 59REDIS_URL=redis://localhost:6379 60 61# Auth / Sessions 62JWT_SECRET=change-me-to-a-long-random-string 63JWT_EXPIRES_IN=15m 64REFRESH_TOKEN_SECRET=change-me-to-another-long-random-string 65REFRESH_TOKEN_TTL_DAYS=30 66SESSION_SECRET=change-me-session-secret 67BCRYPT_ROUNDS=12 68 69# S3-compatible object storage (MinIO in local dev) — TASK-0101. 70# Two PRIVATE buckets (no public access; served only via signed URLs): 71# S3_BUCKET_FILES — uploaded objects, `files/{ws}/{fileId}/{v}/{name}` layout 72# S3_BUCKET_THUMBS — thumbnail/preview artifacts, `thumbs/{ws}/{fileId}/{size}/{name}` 73S3_ENDPOINT=http://localhost:9000 74S3_ACCESS_KEY=minioadmin 75S3_SECRET_KEY=minioadmin 76S3_BUCKET_FILES=factory-files 77S3_BUCKET_THUMBS=factory-thumbs 78# Legacy alias for S3_BUCKET_FILES (older .env files). 79S3_BUCKET=factory-files 80S3_REGION=us-east-1 81S3_FORCE_PATH_STYLE=true 82# Signed-URL lifetime in seconds (15 min default). 83S3_SIGN_EXPIRY_SECONDS=900 84# ClamAV (TASK-0102). Empty CLAMD_SOCKET = dev mode (scan skipped + WARN). 85# Docker profile: CLAMAV_HOST=clamav (or localhost from the host) + CLAMAV_PORT. 86CLAMD_SOCKET= 87CLAMAV_HOST= 88CLAMAV_PORT=3310 89 90# Search (OpenSearch) 91SEARCH_URL=http://localhost:9200 92SEARCH_USERNAME= 93SEARCH_PASSWORD= 94SEARCH_INDEX_PREFIX=factory 95# Content-index dense_vector tuning (TASK-0099 — dimensions are immutable per 96# index; a change rolls a new index via `pnpm search:reindex`). HNSW: m / 97# ef_construction, dimension = the embedding model's output (1536 = 98# text-embedding-3-small). 99SEARCH_VECTOR_DIMENSION=1536 100SEARCH_KNN_M=16 101SEARCH_KNN_EF_CONSTRUCTION=100 102 103# AI gateway (Phase 12 — provider-agnostic; ONE env block, zero app-code 104# change to swap providers). Provider matrix (AI_PROVIDER): 105# openai OpenAI API (chat: AI_MODEL; embeddings: AI_EMBEDDING_MODEL) 106# anthropic Anthropic API (embeddings fall through to the fallback provider) 107# google Google Gemini (chat: gemini-1.5-pro) 108# oss OpenAI-compatible self-hosted endpoint (AI_BASE_URL required) 109# custom customer endpoint (AI_BASE_URL + optional extra headers) 110# mock CI/dev deterministic mock — no network; the capability suite and 111# local dev run the full gateway surface offline (never production) 112AI_PROVIDER=openai 113AI_BASE_URL=https://api.openai.com/v1 114AI_API_KEY= 115AI_MODEL=gpt-4o 116AI_EMBEDDING_MODEL=text-embedding-3-small 117# Embedding provider for the `embed:chunks` worker job. With the Phase-12 118# gateway wired, a configured provider runs the real embed path; EMPTY still 119# skips (no AiEmbedding rows, chunk docs' vector stays null) for dev without 120# an API key. 121AI_EMBEDDING_PROVIDER= 122# --- Optional stream/plan tuning (all OPTIONAL — empty = the built-in 123# --- defaults; raise them for SLOW REASONING MODELS, e.g. OSS vLLM: a long 124# --- silent thinking phase before the plan + a plan JSON larger than 4096 125# --- tokens) --- 126# AI page-generation total cap in ms (default 120000). A complex plan from a 127# reasoning model can take ~2-3 min (silent thinking first); raise to 600000. 128AI_GENERATE_TIMEOUT_MS= 129# Max gap between streamed BYTES in ms (default 30000). A reasoning model's 130# silent thinking phase can exceed 30 s of no bytes (observed 39 s) → mid- 131# stream 504. Raise to 90000 for such models. 132AI_STREAM_IDLE_MS= 133# Platform default for the per-call maxOutputTokens clamp (default 4096). 134# Reasoning models spend ~9k tokens THINKING before the answer; a complex 135# generation plan needs ~15k+ total → raise to 32000 so the plan JSON is not 136# truncated mid-stream. A workspace's settings.ai.budgets.maxOutputTokens 137# still wins over this platform default. 138AI_MAX_OUTPUT_TOKENS= 139# (Advanced) fetch-level response cap in ms (default 60000). 140AI_STREAM_TIMEOUT_MS= 141 142# Email (SMTP) 143SMTP_HOST=localhost 144SMTP_PORT=587 145SMTP_USER= 146SMTP_PASSWORD= 147SMTP_FROM="AI Software Factory <no-reply@example.com>" 148 149# Realtime 150REALTIME_PORT=4001 151REALTIME_HEARTBEAT_MS=30000 152YJS_STORAGE_PREFIX=yjs 153# Shared service token for the internal endpoints (`/internal/*`, TASK-0092 154# slice 2): the realtime gateway authenticates to the api's internal block 155# endpoints (hydration read + the flush's CAS persist) with this bearer 156# token. Empty (default) = the internal endpoints are CLOSED (fail-closed). 157INTERNAL_SERVICE_TOKEN= 158 159# Webhooks 160WEBHOOK_RETRY_MAX=8 161WEBHOOK_TIMEOUT_MS=10000 162 163# Rate limiting 164RATE_LIMIT_WINDOW_MS=60000 165RATE_LIMIT_MAX=300 166 167# Observability (optional; enable in Phase 15) 168OTEL_ENABLED=false 169OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 170 171# Encryption (application-level secret encryption, at-rest secrets) 172MASTER_ENCRYPTION_KEY= 173