Repository navigation
Expand file tree
/
Copy path.env.example
More file actions
358 lines (320 loc) · 19.8 KB
/
Copy path.env.example
File metadata and controls
358 lines (320 loc) · 19.8 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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# ─────────────────────────────────────────────
# App Edition
# ─────────────────────────────────────────────
# community | enterprise | cloud
NEXT_PUBLIC_EDITION=community
# Required when NEXT_PUBLIC_EDITION=enterprise | cloud. See docs/licensing.md.
# The signed license token issued by the vendor. Verified fully offline against
# the public key baked into the app. It anchors this deployment's license identity.
# LICENSE_KEY=
# Vendor endpoint used by the hourly online license refresh.
# LICENSE_REFRESH_URL=https://chatbotx.io/api/licenses/refresh
# Set false for air-gapped installs that use a long-lived offline token.
# LICENSE_REFRESH_ENABLED=true
# ─────────────────────────────────────────────
# Platform Admin
# ─────────────────────────────────────────────
# Email address that can access /manage (platform admin UI).
# Required when NEXT_PUBLIC_EDITION=community or enterprise.
# PLATFORM_ADMIN_EMAIL=admin@example.com
# Require each workspace owner to opt in before platform admins can access it.
# Enterprise deployments can set false to grant platform admins support access
# to every workspace. Community deployments always require consent.
# SUPPORT_ACCESS_REQUIRE_CONSENT=true
# ─────────────────────────────────────────────
# Authentication
# ─────────────────────────────────────────────
# Secret used to sign sessions and tokens.
# Must be a 32-byte base64 string. Generate with:
# openssl rand -base64 32
BETTER_AUTH_SECRET=VLu1KcS63DTTnZU3Dh/ykI9Ld26YQXy/1IMJdZf/kHI=
# Public URL of the builder app (used for OAuth redirects and email links).
BETTER_AUTH_URL=http://localhost:3123
# Disable self-service account creation. Valid invitation links remain usable.
# AUTH_DISABLE_SIGNUP=false
#
# Native iOS "Sign in with Apple" (POST /api/auth/mobile/token, grantType
# "id_token"). Comma-separated iOS bundle IDs accepted as the identity token's
# audience; white-label brands each have their own. Unset disables the grant.
# Verification is native (Apple's public keys), so no Services ID or .p8 key.
# APPLE_APP_BUNDLE_IDS=com.example.app
#
# Optional single OIDC/OAuth 2.0 provider for enterprise deployments.
# Enable only with a valid enterprise license and complete provider credentials.
#
# Recommended: OIDC Discovery. This is the smallest supported configuration:
# enable flag + client id + client secret + discovery URL. It discovers the
# authorization, token, and userinfo endpoints automatically.
# Register this redirect URI at the IdP (broker URL falls back to the builder
# URL): <NEXT_PUBLIC_BROKER_URL>/api/auth/callback/oidc
# Deployments set up before Better Auth 1.7 registered
# /api/auth/oauth2/callback/oidc and must update it at the IdP.
# AUTH_OAUTH_ENABLED=false
# AUTH_OAUTH_CLIENT_ID=
# AUTH_OAUTH_CLIENT_SECRET=
# AUTH_OAUTH_DISCOVERY_URL=https://idp.example.com/.well-known/openid-configuration
#
# Advanced: use only when the provider does not expose OIDC Discovery. Both
# authorization and token endpoints are required; userinfo is optional.
# AUTH_OAUTH_AUTH_URL=
# AUTH_OAUTH_TOKEN_URL=
# AUTH_OAUTH_USERINFO_URL=
#
# Comma-separated OAuth scopes. Defaults to openid,email,profile.
# AUTH_OAUTH_SCOPES=openid,email,profile
# Trust an IdP that omits email_verified to link an existing account. This
# weakens account-linking verification; leave false unless the IdP is trusted.
# Also marks the user email-verified on first sign-in through this IdP.
# AUTH_OAUTH_TRUST_EMAIL=false
# Better Auth 1.7 binds the ID token to a nonce. Set true only for an IdP that
# does not echo the nonce claim (weakens replay protection).
# AUTH_OAUTH_DISABLE_NONCE_BINDING=false
# The sign-in button defaults to "SSO"; its logo is optional.
# NEXT_PUBLIC_AUTH_OAUTH_DISPLAY_NAME=SSO
# NEXT_PUBLIC_AUTH_OAUTH_LOGO_URL=
# ─────────────────────────────────────────────
# Encryption
# ─────────────────────────────────────────────
# Active 32-byte key (hex, 64 chars) used to encrypt developer-app secrets at rest.
# Generate with: openssl rand -hex 32
# MUST be overridden in production.
ENCRYPTION_KEY=16fca8032c77c99a42197a57bce0cf1275c110ab1385f8eb6942665ed317a973
# ─────────────────────────────────────────────
# Database
# ─────────────────────────────────────────────
DATABASE_URL=postgresql://chatbotx:secretkey@localhost:5432/chatbotx?schema=public
# Maximum PostgreSQL connections per process. `worker standalone` and
# `worker core` default `DATABASE_POOL_MAX` to 80 and `SHARD_POOL_MAX` to 40 because all worker concurrency shares
# one process; raise pool limits or lower worker concurrency while keeping total
# connections below PostgreSQL's max_connections.
# DATABASE_POOL_MAX=10
# SHARD_POOL_MAX=10
# ─────────────────────────────────────────────
# Message Sharding (optional — for horizontal scaling)
# ─────────────────────────────────────────────
# Set to "true" to enable sharded message storage.
# ENABLE_MESSAGE_SHARDING=false
# Shared password for all shard connections (overridden per-shard if needed).
# MESSAGE_SHARDS_PASSWORD=
# Set to "true" to require SSL on shard connections.
# MESSAGE_SHARDS_SSL=false
# ─────────────────────────────────────────────
# Redis
# ─────────────────────────────────────────────
REDIS_URL=redis://localhost:6379
# Optional dedicated Redis for realtime streams and revoke markers. Set this
# identically on builder, worker, and realtime; it falls back to REDIS_URL.
# REDIS_REALTIME_URL=redis://redis-realtime:6379
# Stored media
# Re-encode received photos (JPEG) and contact avatars (WebP) to cut
# object-storage size: inline before the first write when the image is small,
# otherwise by a background job. Images sent as files keep their original.
# "off" stops both and makes queued jobs no-ops; objects already stored are
# left as they are.
STORED_IMAGE_OPTIMIZATION=on
# Tuning (defaults shown). Longest side in px, quality 1-100, and the minimum
# saving (%) for the re-encode to replace the original.
# STORED_IMAGE_MEDIA_MAX_DIMENSION=1600
# STORED_IMAGE_MEDIA_QUALITY=80
# STORED_IMAGE_MEDIA_MIN_SAVING_PERCENT=20
# STORED_IMAGE_AVATAR_MAX_DIMENSION=256
# STORED_IMAGE_AVATAR_QUALITY=80
# STORED_IMAGE_AVATAR_MIN_SAVING_PERCENT=10
# Larger images are never decoded (memory guard); slow encodes give up.
# STORED_IMAGE_MAX_INPUT_MEGAPIXELS=16
# STORED_IMAGE_ENCODE_TIMEOUT_SECONDS=2
# Inline encoding limits; anything larger goes to the background job.
# Concurrency is per process; 0 leaves every image to the job.
# STORED_IMAGE_INLINE_MAX_MB=2
# STORED_IMAGE_INLINE_MAX_MEGAPIXELS=8
# STORED_IMAGE_INLINE_AVATAR_MAX_MEGAPIXELS=4
# STORED_IMAGE_INLINE_CONCURRENCY=2
# Background job: skip attachments under the floor and sources over the ceiling.
# STORED_IMAGE_JOB_MIN_SOURCE_KB=32
# STORED_IMAGE_JOB_MAX_SOURCE_MB=10
# Split Redis per role (optional — each falls back to REDIS_URL if unset).
# `REDIS_QUEUE_URL` moves the hot queues (integration, chat, notification, low,
# callTranscription, whatsappVoipSignaling) and the event-bus Streams/plain-KV users
# sharing the hot connection. `REDIS_SEQUENCE_URL` keeps sequence scheduling separate.
# Set REDIS_CACHE_URL to route cache reads to a separate VM.
# REDIS_CACHE_URL=redis://redis-cache:6379
# REDIS_SEQUENCE_URL=redis://redis-sequence:6379
# REDIS_QUEUE_URL=redis://redis-queue:6379
# Set REDIS_QUEUE_BULK_URL to further split bulk queues (aiAgent, heavy, default,
# schedule, trigger, webhook, quota). It falls back to REDIS_QUEUE_URL, then REDIS_URL.
# Drain existing bulk jobs and restart every producer/consumer before cutover.
# REDIS_QUEUE_BULK_URL=redis://redis-queue-bulk:6379
# ─────────────────────────────────────────────
# Worker Tuning
# ─────────────────────────────────────────────
# MAC admission defaults to the atomic live-counter strategy.
# Set to lock for operational rollback; atomic and lock may run side by side,
# so a rolling restart is safe.
# QUOTA_MAC_ADMISSION=atomic
# Webhook and integration handling are I/O-bound; other workers use their default.
# WEBHOOK_WORKER_CONCURRENCY=50
# Integration containers are memory-constrained (~2GB each in an 8-per-16GB-host
# layout) and share the queue with heavy coexist sync jobs; keep this modest.
# INTEGRATION_WORKER_CONCURRENCY=10
# CHAT_WORKER_CONCURRENCY=5
# PROFILE_SNAPSHOT_JOBS_PER_SECOND=10
# NOTIFICATION_WORKER_CONCURRENCY=10
# Snowflake ID place id (0-15). Every process that writes to the database
# (builder, each worker replica, realtime, mcp) should get a DIFFERENT value so
# two processes minting an id in the same millisecond cannot collide. Unset →
# a random slot in 1-15 is drawn at startup (0 is reserved for pre-fix
# processes so a rolling deploy never overlaps them).
# SNOWFLAKE_PLACE_ID=0
# Expo Push Service. Expo needs no credential to send, so EXPO_PUSH_ENABLED is
# the explicit kill switch (defaults to true). EXPO_ACCESS_TOKEN is only
# needed if Expo's "enhanced push security" is enabled on the project.
# EXPO_PUSH_ENABLED=true
# EXPO_ACCESS_TOKEN=
# ─────────────────────────────────────────────
# JavaScript Executor
# ─────────────────────────────────────────────
# Internal HTTP endpoint used by workers to run execute-javascript flow steps.
JAVASCRIPT_EXECUTOR_URL=http://localhost:3210
# Static bearer token shared only by workers and the executor (minimum 32 chars).
# MUST be overridden in production.
JAVASCRIPT_EXECUTOR_TOKEN=change-me-in-production-at-least-32-chars
# Maximum isolated-vm executions handled concurrently by one executor process.
# Keep this aligned with the executor's CPU allocation (the dev stack uses 2).
# MAX_CONCURRENCY=2
# Production hardening: never publish port 3210; attach the executor only to an
# internal network; set memory/CPU limits; use cap_drop: [ALL], read_only: true,
# and no-new-privileges. Scale independently with:
# docker service scale javascript-executor=N
# The executor exposes no network APIs to user code, preventing outbound SSRF.
# ─────────────────────────────────────────────
# S3 / Object Storage
# ─────────────────────────────────────────────
S3_ACCESS_KEY_ID=chatbotx
S3_SECRET_ACCESS_KEY=secretkey
S3_BUCKET=chatbotx
S3_REGION=us-west-2
# Custom endpoint for S3-compatible storage (e.g. RustFS, MinIO).
# Leave unset to use AWS S3.
S3_ENDPOINT=http://localhost:9000
# ─────────────────────────────────────────────
# In-app WhatsApp calling (VoIP)
# ─────────────────────────────────────────────
# TURN relay. Required for real calls — without it media never flows and Meta
# ends the call as failed. Must be publicly reachable over UDP; localhost and
# HTTP tunnels cannot work. coturn REST/HMAC (`use-auth-secret`) only.
# See docs/whatsapp-calling-voip.md.
# TURN_URL=turn:turn.example.com:3478
# TURN_STATIC_SECRET=<that relay's static-auth-secret>
# ─────────────────────────────────────────────
# SMTP / Email
# ─────────────────────────────────────────────
# Connection URL: smtp[s]://user:pass@host:port
SMTP_SERVER=smtp://username:password@localhost:1025
SMTP_FROM=no-reply@localhost
# HMAC secret shared between builder and realtime to sign/verify short-lived
# (60s) JWTs. The workspace/guest connect token travels as a `?token=` query
# param on the WebSocket URL, not a header; `Authorization: Bearer <token>` is
# used only by the gateway's presence report back to the builder.
# MUST be overridden in production (minimum 32 characters, or the gateway
# fails to boot).
REALTIME_BROADCAST_SECRET=insecure-default-realtime-broadcast-secret-change-me
# Per-process realtime socket cap. Over the cap the gateway closes new
# connections with code 4003 and a retryAfter hint instead of degrading.
# REALTIME_MAX_CONNECTIONS=10000
# Guest sub-pool of the total cap above, across the whole server.
# REALTIME_MAX_GUEST_CONNECTIONS=8000
# Member connections allowed for one workspace.
# REALTIME_MAX_CONNECTIONS_PER_WORKSPACE=500
# Guest connections allowed for one workspace, across every guest conversation.
# REALTIME_MAX_GUEST_CONNECTIONS_PER_WORKSPACE=1000
# Connections allowed for one guestConversationId.
# REALTIME_MAX_CONNECTIONS_PER_GUEST=5
# Forces every connection to periodically re-handshake (fresh token mint,
# re-checked membership/permissions) — see docs/realtime.md's close-code table.
# REALTIME_CONNECTION_LIFETIME_MS=1800000
# Realtime publishers and the gateway use REDIS_REALTIME_URL when it is set.
# Switching it drops up to five minutes of replay history and active revoke markers.
#
# The gateway reports agent presence to the builder with the shared secret above.
# See docs/realtime.md for stream retention, replay, and close-code semantics.
# ─────────────────────────────────────────────
# Public URLs (Next.js)
# ─────────────────────────────────────────────
# Canonical public URL of the builder app.
NEXT_PUBLIC_BUILDER_URL=http://localhost:3123
# Force generated public URLs to use HTTPS.
# This does not configure TLS or redirect incoming HTTP traffic.
# FORCE_PUBLIC_HTTPS=false
# Optional: dedicated, brand-neutral broker host (GHL/LeadConnector-style). The
# canonical provider-facing origin for BOTH OAuth redirect_uris AND host-validated
# webhooks (WhatsApp/Meta, TikTok) — providers cannot reach a white-label custom
# domain. This is the SINGLE redirect_uri you register with every OAuth provider
# (Google/Facebook SSO, TikTok, Google Sheets, …). All white-label callbacks land
# here and are relayed back to the originating reseller domain. Register exactly:
# <broker>/api/auth/callback/google <broker>/api/auth/callback/facebook
# <broker>/integrations/<channel>/callback <broker>/integrations/<channel>/webhook
# Defaults to NEXT_PUBLIC_BUILDER_URL when unset (single-domain deploys).
# NEXT_PUBLIC_BROKER_URL=https://broker.example.com
# Optional: override the storage base URL used by the browser.
# Defaults to the S3_ENDPOINT value resolved server-side.
# Useful when the storage service is reachable under a different host locally.
# NEXT_PUBLIC_INTERNAL_STORAGE_URL=http://localhost:9000/chatbotx/
# Optional: public-facing storage domain (e.g. CDN, external S3 proxy, or whitelabel storage).
# When set, all public file URLs are served from this domain instead of <APP_URL>/storage/.
# Per-user overrides can also be set via PlatformSetting.storageUrl in the database.
# NEXT_PUBLIC_STORAGE_URL=https://cdn.example.com/
# Optional: realtime HTTP proxy target for local development.
# This value is only used by the builder server.
# REALTIME_PROXY_URL=http://localhost:1999
# Optional: local MCP server proxy target for development.
# MCP_PROXY_URL=http://localhost:3333
# Optional: public MCP base URL. Defaults to <NEXT_PUBLIC_BUILDER_URL>/mcp.
# Must be HTTPS unless it is a loopback host (localhost/127.0.0.1).
# MCP_PUBLIC_URL=https://app.chatbotx.io/mcp
# Optional: Pancake chat page id for the builder app support widget.
# Only renders on the canonical NEXT_PUBLIC_BUILDER_URL domain.
# NEXT_PUBLIC_PANCAKE_CHAT_PAGE_ID=web_chatbotx
# ─────────────────────────────────────────────
# Scheduler & Runtime
# ─────────────────────────────────────────────
# Sequence-scheduler buckets this instance polls (0-255): an inclusive range
# ("0-255") or a comma list ("0,5,200").
SCHEDULER_BUCKET_RANGE=0-255
# How often the sequence producer polls each bucket, in ms (100-10000, default
# 5000). Idle Redis cost is buckets x 2 x 1000 / interval commands per second
# (256 buckets: ~102/s at 5000). Without backlog a due dispatch waits up to one
# interval plus tick time, once per sequence step (consecutive zero-delay steps
# each add one); backlog or contention adds more.
# Only processes that run the producer use it (`worker standalone`, `all`,
# `sequence-producer`), but every worker process rejects a value outside
# 100-10000 at startup.
# SCHEDULER_TICK_INTERVAL_MS=5000
# Increase Node.js heap for large workloads. Set per-process, not globally.
# NODE_OPTIONS="--max_old_space_size=4096"
# ─────────────────────────────────────────────
# Logging
# ─────────────────────────────────────────────
# Log verbosity: error | warn | info | debug
LOG_LEVEL=debug
# Promotes opt-in diagnostic lines (e.g. sanitized webhook request bodies) from
# debug to info, so they survive LOG_LEVEL=info in production without turning
# on every other debug line. Enable briefly; log content may include redacted
# customer data.
LOG_DEBUG=false
# ─────────────────────────────────────────────
# Messenger conversation routing
# ─────────────────────────────────────────────
# App id of the automated-assistant app a Messenger conversation is handed back
# to ("return to bot"). Unset = return-to-bot is refused and a hand-back to this
# app never starts the handover resume flow.
# FACEBOOK_BUSINESS_AI_APP_ID=
# Channels whose webhook keeps the provider's media URL instead of downloading
# the media (comma separated). The bytes are downloaded, re-encoded and stored
# the first time the inbox, an AI reader or a flow needs them; until then the
# provider must still serve them, so unsent/revoked media is lost for good.
# Empty = download at webhook time everywhere. Applies to media on the
# provider's own CDN only; stickers/GIFs from other hosts are always downloaded.
LIVE_MEDIA_LAZY_CHANNELS=messenger,instagram
# Same for contact profile pictures: not downloaded when the contact is created,
# fetched the first time something needs the picture.
LIVE_AVATAR_LAZY_CHANNELS=messenger,instagram