Files
warmbly/deploy/config/env.example
T
Matthew Meszaros a7518a8558 docs: refresh the documentation site, fix inaccurate claims and contact addresses, add SEO primitives (#90)
* feat: rewrite the self-hosting docs against repo ground truth: turn the deployment guide into a full self-host guide (quick start with first-admin bootstrap via make grant-admin, .env secrets with exact key formats, PUBLIC_HOST derivation and HTTPS reverse-proxy vars, provider switches with build-tag caveats, mailbox OAuth, remote worker enrollment via SSH or wmenroll tokens, real CI image tags, upgrades and backups), rewrite the events page around the real NATS/Kafka bus topics and {type,body} envelopes, fix Kafka-era and make-target claims in architecture/local-development/deploy README, add API_PUBLIC_URL and drop the dead LOG_DISCORD_WEBHOOK_URL in env.example, and remove the docker-compose.kafka.yml comment pointing at a file that does not exist

* feat: make the self-hosting docs visual and skimmable by adding a Mermaid MDX component (client-rendered, theme-aware) to the docs site, condensing the self-host guide around a control-plane topology diagram, a worker enrollment sequence diagram, a dashboard screenshot, and symptom/check troubleshooting + optional-subsystem tables, and adding an execution-plane flowchart to the architecture page

* feat: stop the docs root flashing a 'Continue to the Warmbly docs' link before redirecting by navigating with an inline location.replace that runs during HTML parse, and demoting the visible link and meta refresh to no-JS fallbacks inside noscript

* feat: cut docs bulk and duplication by deleting three orphaned API pages that were stale forks of the reference section and were unreachable from the sidebar (porting their unique social sign-in, promo-code, and referral endpoints into api/reference/account-org.mdx as compact tables), condensing the deliverability and warmup guides to roughly half their length around tables instead of prose, replacing prose em dashes across the guides and MCP pages, and adding the required trailing slashes to internal links in 24 files

* feat: condense the sequences guide by about 40 percent, folding the switch-step deciders and branch conditions into tables and cutting restated prose while keeping every rule about threading, instant branches, reply matching, and stop on reply

* feat: condense the automations, unibox, advisor, and expressions guides by roughly 40 percent each, folding trigger lists, action catalogs, sending controls, and advisor checks into tables, adding a trigger-condition-action flow diagram to automations, and cutting restated prose while preserving every threshold, permission boundary, and rule

* feat: condense the mailboxes, campaigns, analytics, and team-roles guides by roughly 45 percent each, replacing prose walks through providers, rotation modes, lead statuses, counting rules, A/B confidence, and the permission matrix with compact tables and collapsing the four-way role grid into one capability table plus a one-line mapping

* feat: condense the AI-steps, security, and contacts-CRM guides by roughly 40 percent, turning sign-in methods, AI step modes, switch deciders, credit and failure behavior, import field mappings, and deal views into tables while keeping every safety boundary and dedupe rule

* feat: condense the meetings, notifications, AI-credits, and AI-assistant guides by roughly 40 percent, merging notification categories and their defaults into one table, collapsing credit costs, spend controls, and plan allowances into tables, and tightening the assistant page around its approval and permission boundaries

* feat: condense the integrations, collaboration, zapier, and make guides by roughly 35 percent, grouping the thirty-row Zapier and Make action lists into eight labelled areas, folding CRM default field mappings and presence indicators into tables, and promoting the destructive-action and unattended-delete warnings into callouts

* fix: correct three factual errors in the development docs: NOTIFICATION_EMAIL_DAILY_CAP=0 means uncapped rather than disabled (overEmailBudget returns false at limit<=0, so documenting it as a kill switch inverted the behavior), and the worker-SSH and warmup-pool migration citations in architecture.mdx pointed at pre-squash filenames that no longer exist or now belong to unrelated migrations, so both now cite the tables in 000001_baseline.up.sql

* feat: add the missing docs SEO primitives: a build-time sitemap.xml covering all 64 pages, a robots.txt that points at it and keeps the llms.mdx and og mirrors out of the index as duplicate content, and per-page canonical plus richer OpenGraph URL/title/description metadata

* fix: use the single real team@warmbly.com address everywhere a human is told to write in, replacing the invented hello/sales/legal/support inboxes across the marketing site, the transactional email footer, and the admin outreach composer default Reply-To (which pointed replies at a mailbox that does not exist), and collapse the contact page's two-inbox framing into one inbox with one published response time
2026-08-05 10:37:27 +02:00

173 lines
7.5 KiB
Plaintext

# ============================================
# Warmbly environment reference
# ============================================
# Defaults are no-cloud: with just the four secrets in the "Required" block set,
# Warmbly runs with no AWS, GCP, Stripe, or Kafka. Each subsystem is a provider
# switch — flip one to opt into a cloud service.
#
# Config priority: env var first, then AWS SSM/Secrets Manager (only when
# AWS_CONFIG_ENABLED=true).
# ============================================
# === Required ===
APP_ENV=dev # dev | production
# JWT / session signing. Min 32 chars. MUST match the realtime service JWT_SECRET.
AUTH_SECRET=change-me-min-32-characters-long
# 64 hex chars (32 bytes). Seals mailbox SMTP/IMAP credentials at rest.
# BACK IT UP — losing it makes connected mailboxes unrecoverable. `openssl rand -hex 32`
CREDENTIALS_ENCRYPTION_KEY=
# Shared token for the backend internal API (workers + tracking use it).
INTERNAL_API_TOKEN=change-me-internal-token
PRIMARY_DB=postgres://warmbly:warmbly@localhost:5432/warmbly_dev?sslmode=disable
REDIS=redis://localhost:6379
# === Provider switches (no-cloud defaults) ===
AWS_CONFIG_ENABLED=false # true => read secrets from AWS SSM/Secrets Manager
# Event bus. nats (default): one small JetStream binary. kafka: build the images
# with GO_TAGS=kafka / CARGO_FEATURES=kafka and set KAFKA_* below.
EVENTBUS_PROVIDER=nats
NATS_URL=nats://localhost:4222
# NATS_STREAM_NAME=warmbly
# NATS_SUBJECT_PREFIX=warmbly
# Serialization. json is required with NATS and wherever workers run. avro is
# only for a Kafka + Schema Registry deployment.
CODEC_PROVIDER=json
# Encryption root key. local (default): AES master key below. aws: AWS KMS.
KMS_PROVIDER=local
# base64 32 bytes. BACK IT UP — losing it is unrecoverable. `make gen-key`
KMS_LOCAL_MASTER_KEY=
# KMS_LOCAL_MASTER_KEY_FILE=/run/secrets/kms_master_key # alternative to the inline key
# KMS_AWS_KEY_ID=alias/warmbly # when KMS_PROVIDER=aws
# Blob storage. filesystem (default): a local dir. s3: any S3-compatible store.
BLOB_PROVIDER=filesystem
BLOB_FS_ROOT=/data/blobs # shared between backend + workers (same host / shared volume)
# Public URL base for avatars/logos served by the backend's /public route.
BLOB_PUBLIC_BASE_URL=http://localhost:8080/public
# For BLOB_PROVIDER=s3 (AWS / MinIO / R2 / B2):
# BLOB_BUCKET=warmbly
# AWS_ENDPOINT_URL_S3=http://minio:9000 # non-AWS endpoint
# AWS_REGION=us-east-1
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# Delayed tasks (campaign ticks, scheduled sends). local (default): an in-process
# Postgres poller — no external service. gcloud: GCP Cloud Tasks.
TASKS_PROVIDER=local
# TASKS_LOCAL_POLL_INTERVAL=1s
# When TASKS_PROVIDER=gcloud, also set:
# CLOUD_TASKS_QUEUE_NAME=projects/<p>/locations/<l>/queues/<q>
# CLOUD_TASKS_WEBHOOK_URL=https://<api-host>/webhook/email
# GOOGLE_APPLICATION_CREDENTIALS_JSON=<service-account-email>
# Billing. none (default): no Stripe, every feature unlocked, no trial expiry.
# stripe: wire the Stripe integration (keys below required).
BILLING_PROVIDER=none
# STRIPE_SECRET_KEY=
# STRIPE_WEBHOOK_SECRET=
# STRIPE_PUBLISHABLE_KEY=
# Captcha. Auto-off when TURNSTILE_SECRET is unset; set CAPTCHA_PROVIDER=turnstile
# + TURNSTILE_SECRET to require Cloudflare Turnstile on auth endpoints.
# CAPTCHA_PROVIDER=none
# TURNSTILE_SECRET=
# === Backend API ===
API_HOST=0.0.0.0:8080 # binds all interfaces already
GIN_MODE=release # debug | release
# With the shipped docker-compose.yml, set PUBLIC_HOST to your LAN IP or domain
# and APP_URL / CORS_ALLOW_ORIGINS / WEBSOCKET_URL / TRACKING_DOMAIN / the VITE_*
# frontend URLs all derive from it. Set them explicitly if you're not using that
# compose (e.g. behind a reverse proxy on https://your-domain).
# PUBLIC_HOST=192.168.1.50
# API_PUBLIC_URL is the compose input for the API base the frontends and blob
# URLs use (falls back to http://<PUBLIC_HOST>:8080); set it explicitly behind
# a reverse proxy. ENV_LABEL labels the admin panel (compose: WARMBLY_ENV_LABEL).
# API_PUBLIC_URL=https://api.example.com
# ENV_LABEL=production
APP_URL=http://localhost:5173
CORS_ALLOW_ORIGINS=http://localhost:5173,http://localhost:5174
WEBSOCKET_URL=ws://localhost:4000/socket/websocket
ENCRYPTED_KEYS_PROVIDER=postgres # backend/consumer: postgres; workers: http (below)
GEODB_PATH=/app/data/GeoLite2-City.mmdb # optional in dev
# === Mailbox connections ===
# Gmail mailboxes need YOUR Google Cloud OAuth client (a "Web application" client)
# with authorized redirect URI <API_HOST>/addresses/google/callback. Set on the
# backend AND every worker. Leave unset to connect mailboxes only via SMTP/IMAP.
BOX_GOOGLE_CLIENT_ID=
BOX_GOOGLE_CLIENT_SECRET=
# Microsoft 365 / Outlook OAuth client (redirect <API_HOST>/addresses/outlook/callback):
BOX_OUTLOOK_CLIENT_ID=
BOX_OUTLOOK_CLIENT_SECRET=
# === Social sign-in (all optional; email+password / passkeys work standalone) ===
# GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET / GOOGLE_REDIRECT_URI are the LOGIN client,
# separate from the BOX_GOOGLE_* mailbox client above.
# GOOGLE_CLIENT_ID=
# GOOGLE_CLIENT_SECRET=
# GOOGLE_REDIRECT_URI=
# GOOGLE_IOS_CLIENT_ID=
# APPLE_APP_ID=
# APPLE_TEAM_ID=
# APPLE_KEY_ID=
# APPLE_KEY_SECRET=
# Passkeys (WebAuthn): derived from APP_URL when unset. Changing the RP ID
# invalidates enrolled passkeys, so keep it stable per deployment.
# WEBAUTHN_RP_ID=app.example.com
# WEBAUTHN_RP_ORIGINS=https://app.example.com
# === Worker (each worker process) ===
# Workers hold no relational DB; they reach DEKs over the backend internal API.
# ENCRYPTED_KEYS_PROVIDER=http
# ENCRYPTED_KEYS_BACKEND_URL=http://backend:8080
# ENCRYPTED_KEYS_WORKER_TOKEN=<same as INTERNAL_API_TOKEN>
# WORKER_ID=<uuid> # stable identity; otherwise derived from hostname
# === Notification email (outbound platform mail) ===
EMAIL_NAME=Warmbly
EMAIL_ADDRESS=noreply@example.com
TRACKING_DOMAIN=localhost:3000
SMTP_HOST=mailpit # a real SMTP relay in production
SMTP_PORT=1025
# === Tracking service (open/click) ===
TRACKING_HOST=0.0.0.0
TRACKING_PORT=3000
# Resolves opaque /c/<id> click tickets via the backend internal API.
# BACKEND_INTERNAL_URL=http://backend:8080
TRACKING_RATE_LIMIT_PER_MIN=300
# === Realtime service (Elixir/Phoenix) ===
PHX_HOST=localhost
PORT=4000
JWT_SECRET=change-me-min-32-characters-long # MUST equal the backend AUTH_SECRET
SECRET_KEY_BASE=change-me-phoenix-secret-key-base-min-64-characters-long
DATABASE_URL=postgres://warmbly:warmbly@localhost:5432/warmbly_dev?sslmode=disable
REDIS_URL=redis://localhost:6379
# Realtime transport. false (default): Redis bridge, no cloud. Read identically by
# backend, consumer, and realtime — never set true on one side only.
PUBSUB_ENABLED=false
CHECK_ORIGIN=false
# When PUBSUB_ENABLED=true (Google Pub/Sub): also set GCP_PROJECT_ID +
# GOOGLE_APPLICATION_CREDENTIALS_JSON on every service.
# GCP_PROJECT_ID=
# === AI provider (optional; omit all to run with AI features off) ===
# Set on the backend AND consumer. Self-host bills your provider directly, so the
# credit ledger is bypassed (unlimited) when BILLING_PROVIDER=none.
# AI_PROVIDER= # openai | openrouter | groq | ollama | anthropic | custom
# AI_API_KEY=
# AI_MODEL=
# AI_BASE_URL= # required for custom
# SEARCH_PROVIDER= # optional web-search tool
# SEARCH_API_URL=
# SEARCH_API_KEY=
# === Observability ===
# Optional in dev; REQUIRED (fatal at boot) on every Go service when APP_ENV=prod.
# SENTRY_DSN=