Repository navigation
Expand file tree
/
Copy path.env.example
More file actions
219 lines (191 loc) · 15.9 KB
/
Copy path.env.example
File metadata and controls
219 lines (191 loc) · 15.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# Formbricks Hub Configuration
# Copy this file to .env and update the values as needed.
# Config is loaded via cleanenv: .env is optional; environment variables override .env values.
# API Key for authentication (required)
# This key is used to authenticate requests to protected endpoints
# The server will fail to start if this is not set
API_KEY=your-secret-api-key-here
# Postgres host port for docker-compose (optional). Default: 5432. Override only if 5432 is in use (e.g. POSTGRES_PORT=5433); keep DATABASE_URL in sync.
# POSTGRES_PORT=5432
# Hub image tag for docker-compose migration container (optional). Default: 0.8.7.
# Use a pinned release tag, not latest, so migration tooling is reproducible.
# HUB_IMAGE_TAG=0.8.7
# Database connection URL (optional). Port must match POSTGRES_PORT when you override it.
# Default: postgres://postgres:postgres@localhost:5432/test_db?sslmode=disable
# Format: postgres://username:password@host:port/database?sslmode=disable
DATABASE_URL=postgres://postgres:postgres@localhost:5432/test_db?sslmode=disable
# Database connection pool (optional). For multi-instance: instances * DATABASE_MAX_CONNS must be below Postgres max_connections.
# DATABASE_MAX_CONNS=25
# DATABASE_MIN_CONNS=0
# DATABASE_MAX_CONN_LIFETIME_SECONDS=3600
# DATABASE_MAX_CONN_IDLE_TIME_SECONDS=1800
# DATABASE_HEALTH_CHECK_PERIOD_SECONDS=60
# DATABASE_CONNECT_TIMEOUT_SECONDS=10
# HTTP server port (optional)
# Default: 8080
PORT=8080
# Public base URL advertised in runtime OpenAPI responses (optional but recommended for production)
# Set this when Hub is exposed through ingress, TLS termination, a reverse proxy, or a path prefix.
# Examples:
# PUBLIC_BASE_URL=https://hub.example.com
# PUBLIC_BASE_URL=https://example.com/hub
# PUBLIC_BASE_URL=
# Logging level (optional)
# Default: info
# Valid values: debug, info, warn, error
LOG_LEVEL=info
# LOG_FORMAT=json
# Taxonomy service integration (optional; beta)
# TAXONOMY_SERVICE_URL is the internal URL Hub uses to call the standalone taxonomy service.
# TAXONOMY_SERVICE_TOKEN is sent by Hub as Authorization: Bearer <token> to the taxonomy service.
# HUB_INTERNAL_API_TOKEN protects Hub internal taxonomy APIs called by the taxonomy service.
# These values are server-side secrets/config only; do not expose them to browsers.
# TAXONOMY_SERVICE_URL=http://localhost:8000
# TAXONOMY_SERVICE_TOKEN=dev-taxonomy-service-token
# HUB_INTERNAL_API_TOKEN=dev-hub-internal-api-token
#
# Stuck-run reaper (only runs when the taxonomy service is configured):
# TAXONOMY_STUCK_RUN_TIMEOUT_SECONDS: max seconds a pending/running run may go without its updated_at
# being bumped (via the internal heartbeat endpoint) before the reaper force-fails it (default
# 1800 = 30 min, safe for older taxonomy images that do not heartbeat through terminal callbacks).
# After deploying a heartbeat-capable image, this may be reduced while retaining several heartbeat
# intervals of headroom above the longest expected Hub callback.
# TAXONOMY_REAPER_INTERVAL_SECONDS: seconds between reaper sweeps for stuck runs (default 60).
# TAXONOMY_STUCK_RUN_TIMEOUT_SECONDS=1800
# TAXONOMY_REAPER_INTERVAL_SECONDS=60
# Message publisher: event channel buffer size (optional). Default: 1024
MESSAGE_PUBLISHER_QUEUE_MAX_SIZE=16384
# Message publisher: per-event processing timeout in seconds (optional). Default: 10
MESSAGE_PUBLISHER_PER_EVENT_TIMEOUT_SECONDS=10
# Graceful shutdown timeout in seconds (optional). Default: 30
SHUTDOWN_TIMEOUT_SECONDS=30
# River worker (hub-worker only). API does not run workers; these affect job execution and cleanup.
# RIVER_JOB_TIMEOUT_SECONDS: max time a job may run before context is cancelled. 0 = River default (1m).
# RIVER_RESCUE_STUCK_JOBS_AFTER_SECONDS: time after which a running job is considered stuck and retried/discarded. 0 = River default (1h).
# RIVER_COMPLETED_JOB_RETENTION_SECONDS: how long to keep completed jobs before cleanup; -1 = disable. Default: 86400 (24h).
# RIVER_CLIENT_ID: optional identifier for this worker (logs, attempted_by); empty = auto-generated.
# RIVER_JOB_TIMEOUT_SECONDS=0
# RIVER_RESCUE_STUCK_JOBS_AFTER_SECONDS=0
# RIVER_COMPLETED_JOB_RETENTION_SECONDS=86400
# RIVER_CLIENT_ID=
# Webhook max fan-out per event (optional)
# Max number of webhook jobs enqueued per event; excess is capped and logged. Default: 500
WEBHOOK_MAX_FAN_OUT_PER_EVENT=500
# Webhook max count (optional)
# Max total webhooks allowed; creation returns 403 Forbidden when limit reached. Default: 500
WEBHOOK_MAX_COUNT=500
# Webhook HTTP timeout (optional). Timeout for each delivery POST; job timeout = this + 5s. Default: 15
# WEBHOOK_HTTP_TIMEOUT_SECONDS=15
# Webhook URL blacklist (optional). Comma-separated hosts/IPs that cannot be used as webhook endpoints (SSRF mitigation).
# Default: localhost,127.0.0.1,::1,169.254.169.254 (includes AWS metadata endpoint)
# WEBHOOK_BLACKLIST=localhost,127.0.0.1,::1,169.254.169.254
# Webhook allowed CIDRs (optional). Comma-separated CIDR ranges that re-permit webhook targets the
# SSRF classifier would otherwise reject as private/reserved. Use this when your webhook receivers
# legitimately live on internal addresses -- most commonly a Tailscale tailnet, which is addressed
# out of 100.64.0.0/10. Entries in WEBHOOK_BLACKLIST still win. A malformed entry fails startup.
# Default: empty (no private/reserved range is reachable).
# WEBHOOK_ALLOWED_CIDRS=100.64.0.0/10
# Webhook enqueue retries (optional). When River InsertMany fails, retry with exponential backoff + jitter.
# Defaults: 3 retries, 100ms initial backoff, 2s max backoff.
# WEBHOOK_ENQUEUE_MAX_RETRIES=3
# WEBHOOK_ENQUEUE_INITIAL_BACKOFF_MS=100
# WEBHOOK_ENQUEUE_MAX_BACKOFF_MS=2000
# Embeddings are optional. To enable, set both EMBEDDING_PROVIDER and EMBEDDING_MODEL; if either is unset, embeddings are disabled and no embedding jobs run.
# Providers: openai, google (Gemini Developer API / Google AI Studio), google-gemini (Gemini Enterprise Agent Platform API).
# EMBEDDING_PROVIDER_API_KEY is required for openai and google. For google-gemini, use Google Cloud Application Default Credentials (no API key); set EMBEDDING_GOOGLE_CLOUD_PROJECT and EMBEDDING_GOOGLE_CLOUD_LOCATION.
# Gemini Enterprise Agent Platform API auth (google-gemini): Google Cloud Application Default Credentials (ADC) are used. When running outside Google Cloud (e.g. EKS on AWS, Railway):
# Set GOOGLE_APPLICATION_CREDENTIALS to the path of a Google Cloud service account key JSON file (e.g. mount the key in your pod and set the path).
# Create a service account in Google Cloud with the required model access permissions, download the key, and point GOOGLE_APPLICATION_CREDENTIALS at it.
# Vector size is fixed (768) in code.
# EMBEDDING_PROVIDER=openai
# EMBEDDING_PROVIDER=google-gemini
# EMBEDDING_PROVIDER_API_KEY=sk-... (required for openai and google; not used for google-gemini)
# EMBEDDING_BASE_URL=https://embeddings.example.com/v1 (optional; only supported with EMBEDDING_PROVIDER=openai)
# EMBEDDING_GOOGLE_CLOUD_PROJECT= (required for google-gemini; or use GOOGLE_CLOUD_PROJECT)
# EMBEDDING_GOOGLE_CLOUD_LOCATION= (required for google-gemini, e.g. europe-west3; or use GOOGLE_CLOUD_LOCATION)
# GOOGLE_APPLICATION_CREDENTIALS= (optional; for google-gemini when outside Google Cloud: path to service account key JSON)
# EMBEDDING_MODEL=<model name> (required to enable embeddings; no default)
# EMBEDDING_NORMALIZE=false (optional; L2-normalize vectors client-side; cosine similarity is scale-invariant, so usually unneeded)
# EMBEDDING_MAX_CONCURRENT=5 (worker concurrency; default 5)
# EMBEDDING_MAX_ATTEMPTS=5 (River job attempts before a transient failure is reconciled; default 5)
# EMBEDDING_JOB_TIMEOUT_SECONDS=60 (deadline for one embedding job; independent of other enrichments)
# EMBEDDING_MAX_INPUT_BYTES=12000 (cap on the text sent to the provider, in UTF-8 bytes; over it the input is trimmed to its first N bytes. Embedding models refuse an over-long input outright, which is a terminal failure that leaves the record unsearchable, so this is what keeps long records in the index. 0 = no cap)
# EMBEDDING_BATCH_SIZE=1 (document micro-batch size; 1 disables batching; provider must support batches)
# EMBEDDING_BATCH_MAX_WAIT_MS=25 (maximum time to collect a partial batch; default 25ms)
# EMBEDDING_BATCH_MAX_IN_FLIGHT=1 (maximum concurrent provider batch requests; default 1)
# EMBEDDING_HTTP_DISABLE_KEEP_ALIVES=false (open a new OpenAI-compatible provider connection per request; useful for Kubernetes service distribution)
# EMBEDDING_RECONCILE_ENABLED=false (periodically repair missing, stale and orphaned embeddings: search always, taxonomy when TAXONOMY_SERVICE_URL is set; opt in per deployment)
# EMBEDDING_RECONCILE_INTERVAL_SECONDS=300 (leader-elected sweep interval)
# EMBEDDING_RECONCILE_RETRY_AFTER_SECONDS=900 (cooldown before retrying the same transient failure)
# EMBEDDING_RECONCILE_TARGET_DEPTH=100 (maximum runnable jobs kept in the low-priority repair lane)
# EMBEDDING_RECONCILE_MAX_CONCURRENT=1 (worker concurrency reserved for repaired records)
# Translation (language enrichment) is optional. To enable, set both TRANSLATION_PROVIDER and TRANSLATION_MODEL; if either is unset, translation is disabled and no translation jobs run.
# Open-text feedback (value_text) is translated into each tenant's configured target_language (Hub tenant settings), falling back to TRANSLATION_DEFAULT_LANGUAGE when a tenant has none. Same providers/auth model as embeddings.
# Configure identically in the API and worker processes (the API enqueues, the worker translates); otherwise jobs pile up unprocessed.
# TRANSLATION_PROVIDER=openai
# TRANSLATION_PROVIDER=google-gemini
# TRANSLATION_PROVIDER_API_KEY=sk-... (required for openai and google; not used for google-gemini)
# TRANSLATION_BASE_URL=https://llm.example.com/v1 (optional; only supported with TRANSLATION_PROVIDER=openai)
# TRANSLATION_GOOGLE_CLOUD_PROJECT= (required for google-gemini; or use GOOGLE_CLOUD_PROJECT)
# TRANSLATION_GOOGLE_CLOUD_LOCATION= (required for google-gemini, e.g. europe-west3; or use GOOGLE_CLOUD_LOCATION)
# TRANSLATION_MODEL=<model name> (required to enable translation; no default; e.g. gemini-2.5-flash)
# TRANSLATION_DEFAULT_LANGUAGE= (optional BCP-47 fallback target, e.g. en-US; used when a tenant has no target_language of its own. Empty = per-tenant opt-in only)
# TRANSLATION_MAX_CONCURRENT=5 (worker concurrency; default 5)
# TRANSLATION_MAX_ATTEMPTS=3 (River job retries before failing; default 3)
# TRANSLATION_MAX_INPUT_BYTES=24000 (cap on the text sent to the provider, in UTF-8 bytes; over it the record is SKIPPED, not trimmed — a partial translation stored as complete is wrong — and marked failed_terminal without any provider call. An edit that brings the text back under the cap re-runs it; raising this value later does NOT clear markers already written, so records refused at the old value stay failed until their tenant clears them (POST /v1/tenants/{tenant_id}/enrichments/retry). 0 = no cap)
# Sentiment (sentiment enrichment) is optional. To enable, set both SENTIMENT_PROVIDER and SENTIMENT_MODEL; if either is unset, sentiment is disabled and no sentiment jobs run.
# Open-text feedback (value_text) is classified into a sentiment label (very_negative..very_positive, mixed) + a -1..1 polarity score. Same providers/auth model as embeddings/translation.
# The model must support structured output (OpenAI Structured Outputs / Gemini responseSchema), e.g. gpt-4o / gpt-4o-mini / gemini-2.5-flash; older models without it will fail every job.
# SENTIMENT_PROVIDER=openai
# SENTIMENT_PROVIDER=google
# SENTIMENT_PROVIDER=google-gemini
# SENTIMENT_PROVIDER_API_KEY=sk-... (required for openai and google; not used for google-gemini)
# SENTIMENT_BASE_URL=https://llm.example.com/v1 (optional; only supported with SENTIMENT_PROVIDER=openai)
# SENTIMENT_GOOGLE_CLOUD_PROJECT= (required for google-gemini; or use GOOGLE_CLOUD_PROJECT)
# SENTIMENT_GOOGLE_CLOUD_LOCATION= (required for google-gemini, e.g. europe-west3; or use GOOGLE_CLOUD_LOCATION)
# SENTIMENT_MODEL=<model name> (required to enable sentiment; no default; e.g. gemini-2.5-flash)
# SENTIMENT_MAX_CONCURRENT=5 (worker concurrency; default 5)
# SENTIMENT_MAX_ATTEMPTS=3 (River job retries before failing; default 3)
# SENTIMENT_MAX_INPUT_BYTES=24000 (cap on the text sent to the provider, in UTF-8 bytes; over it the input is trimmed to its first N bytes. 0 = no cap)
# Emotions (emotion enrichment) is optional and independent of sentiment. To enable, set both EMOTIONS_PROVIDER and EMOTIONS_MODEL; if either is unset, emotions is disabled and no emotion jobs run.
# Open-text feedback (value_text) is tagged with zero or more basic emotions (joy, anger, sadness, fear, surprise, disgust) — multi-label, stored as a text[] array. Same providers/auth model as sentiment.
# The model must support structured output (OpenAI Structured Outputs / Gemini responseSchema), e.g. gpt-4o / gpt-4o-mini / gemini-2.5-flash; older models without it will fail every job.
# EMOTIONS_PROVIDER=openai
# EMOTIONS_PROVIDER=google
# EMOTIONS_PROVIDER=google-gemini
# EMOTIONS_PROVIDER_API_KEY=sk-... (required for openai and google; not used for google-gemini)
# EMOTIONS_BASE_URL=https://llm.example.com/v1 (optional; only supported with EMOTIONS_PROVIDER=openai)
# EMOTIONS_GOOGLE_CLOUD_PROJECT= (required for google-gemini; or use GOOGLE_CLOUD_PROJECT)
# EMOTIONS_GOOGLE_CLOUD_LOCATION= (required for google-gemini, e.g. europe-west3; or use GOOGLE_CLOUD_LOCATION)
# EMOTIONS_MODEL=<model name> (required to enable emotions; no default; e.g. gemini-2.5-flash)
# EMOTIONS_MAX_CONCURRENT=5 (worker concurrency; default 5)
# EMOTIONS_MAX_ATTEMPTS=3 (River job retries before failing; default 3)
# EMOTIONS_MAX_INPUT_BYTES=24000 (cap on the text sent to the provider, in UTF-8 bytes; over it the input is trimmed to its first N bytes. 0 = no cap)
# Enrichment reconciler (hub-worker). A periodic sweep that finds eligible records still missing an
# enrichment — never enqueued, crashed mid-flight, or transiently failed past their retries — and
# tops the per-enrichment reconcile queues up to a target depth. Runs on River's elected leader, so
# multiple workers sweep once between them. The event path is unaffected either way: disabling this
# only stops coverage from self-healing.
# Set ENRICHMENT_RECONCILE_ENABLED identically on hub-api AND hub-worker. The sweep runs on the
# worker, but the API reads it to decide whether clearing terminal failures can lead to anything;
# disabling it on the worker alone leaves the API happily clearing markers nothing will act on.
# ENRICHMENT_RECONCILE_ENABLED=true
# ENRICHMENT_RECONCILE_INTERVAL_SECONDS=300
# ENRICHMENT_RECONCILE_TARGET_DEPTH=1000 (per-queue top-up target; clamped to 100000)
# Reconcile-lane concurrency, per enrichment. Reconciled work drains on its own queues with their
# own worker budgets, so a large sweep cannot crowd out a record submitted a moment ago.
# TRANSLATION_RECONCILE_MAX_CONCURRENT=2
# SENTIMENT_RECONCILE_MAX_CONCURRENT=2
# EMOTIONS_RECONCILE_MAX_CONCURRENT=2
# Tenant settings cache (optional): an in-process LRU+TTL over tenant target_language reads on the translation enqueue path.
# Set TENANT_SETTINGS_CACHE_SIZE=0 to disable the cache. Defaults: size 2048, TTL 60s.
# TENANT_SETTINGS_CACHE_SIZE=2048
# TENANT_SETTINGS_CACHE_TTL_SECONDS=60
# Tenant data purge (optional). How long DELETE /v1/tenants/{tenant_id}/data waits for in-flight
# tenant-owned writes to drain before returning a retryable 409 (code tenant_write_conflict).
# Must be a positive integer (seconds); non-positive values fall back to the default. Default: 5
# TENANT_PURGE_LOCK_TIMEOUT_SECONDS=5
# Local River UI basic auth (optional, used by docker compose). Change these for your local setup as needed.
# compose.yml defaults to admin / changeme if these are unset.
RIVER_BASIC_AUTH_USER=admin
RIVER_BASIC_AUTH_PASS=changeme