# --- Local Docker (docker-compose.local.yml) --- # KV_REDIS_URL_US_EAST_1 is set in compose; override here only if needed. # KV_REDIS_URL_US_EAST_1=redis://redis:6379 # KV_REDIS_URL_EU_WEST_1=redis://redis:6379 # when BUTTERBASE_REGIONS includes eu-west-1 # Host-side control-api: KV_REDIS_URL_US_EAST_1=redis://localhost:6379 # Control Plane DB (Cluster A) CONTROL_DB_URL=postgresql://butterbase:butterbase_dev@control-plane-db:5432/butterbase_control # Multi-region Phase 1: Platform DB primary + standby # In Phase 1, both URLs may point at the same DB if you have not yet provisioned a standby. # The failover script swaps PLATFORM_DB_ACTIVE_SIDE and restarts processes. NEON_PLATFORM_PRIMARY_URL=postgresql://butterbase:butterbase_dev@localhost:5433/butterbase_control NEON_PLATFORM_STANDBY_URL= PLATFORM_DB_ACTIVE_SIDE=primary # Multi-region region identification (required at startup, no defaults). # - BUTTERBASE_REGIONS: comma-separated list of all supported regions globally. # - BUTTERBASE_REGION: this instance's region. In production on Fly, leave UNSET; # each machine derives it from FLY_REGION via BUTTERBASE_FLY_REGION_MAP. # - BUTTERBASE_FLY_REGION_MAP: only relevant when BUTTERBASE_REGION is unset. # Maps Fly IATA codes to your Butterbase region names. BUTTERBASE_REGIONS=us-east-1 BUTTERBASE_REGION=us-east-1 # BUTTERBASE_FLY_REGION_MAP=iad:us-east-1,lhr:eu-west-1 # production-only # Failover script (scripts/failover-platform-db.ts) requires these for promote/failback: # NEON_PLATFORM_PROJECT_ID= # Neon project id of the primary # NEON_PLATFORM_STANDBY_PROJECT_ID= # Neon project id of the standby # PLATFORM_FLY_APPS=butterbase-platform # comma-separated Fly app names to restart # Per-region runtime DB project IDs (one per region in BUTTERBASE_REGIONS). # Required at startup. Each region's runtime DB holds the hot-path tables that # customer apps read on every request (apps, app_users, app_oauth_*, etc.). NEON_RUNTIME_PROJECT_ID_US_EAST_1=postgresql://butterbase:butterbase_dev@localhost:5437/butterbase_runtime_us # NEON_RUNTIME_PROJECT_ID_EU_WEST_1=postgresql://... # add when EU region launches # Data Plane DB (Cluster B) DATA_PLANE_DB_HOST=data-plane-db DATA_PLANE_DB_PORT=5432 DATA_PLANE_DB_USER=butterbase DATA_PLANE_DB_PASSWORD=butterbase_dev # PgBouncer PGBOUNCER_HOST=pgbouncer PGBOUNCER_PORT=6432 # Control API (local compose publishes 4000 on the host) CONTROL_API_PORT=4000 NODE_ENV=development # New chats inherit the personal preference before this fallback. DASHBOARD_ASSISTANT_MODEL=deepseek/deepseek-v4.1-flash # Background Office checks inherit the organization preference first. OPERATOR_MODEL=deepseek/deepseek-v4.1-flash # Auth Service AUTH_SERVICE_PORT=4200 AUTH_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef # AWS — S3 / Cloudflare R2 (not used for SES) # Uses IAM roles in production; credentials below are for local development AWS_REGION=us-east-1 AWS_ACCESS_KEY_ID=your_r2_key_here AWS_SECRET_ACCESS_KEY=your_r2_secret_here # AWS SES (separate IAM keys from R2). Optional locally: with NODE_ENV=development # (or EMAIL_DEV_CONSOLE_FALLBACK=true) a failed send is logged to stdout, OTP # codes included. An unset NODE_ENV does NOT enable that fallback. # If AWS_REGION=auto for R2, set SES_REGION to a real AWS region (e.g. us-east-1). SES_AWS_ACCESS_KEY_ID=your_ses_key_here SES_AWS_SECRET_ACCESS_KEY=your_ses_secret_here # SES_FROM_EMAIL must be verified in SES (same region as SES_REGION). SES_FROM_EMAIL=noreply@butterbase.com SES_FROM_NAME=Butterbase # Optional: SES configuration set attached to every send (bounce/complaint routing). # SES_CONFIGURATION_SET= # Optional: log emails to stdout when SES fails, outside NODE_ENV=development. # EMAIL_DEV_CONSOLE_FALLBACK=true # Sentry (Error Tracking) SENTRY_DSN=https://your-dsn@sentry.io/project-id # AWS S3 Storage S3_BUCKET_NAME=butterbase-app-storage # LocalStack (for local development) # Required for localstack/localstack:latest (2026.03+): https://app.localstack.cloud/settings/auth-tokens LOCALSTACK_AUTH_TOKEN= S3_ENDPOINT=http://localhost:4566 S3_FORCE_PATH_STYLE=true # Neon (production only — leave empty for local development) # NEON_API_KEY= # Neon Console > Account > API Keys # NEON_DATA_PROJECT_ID= # neonctl projects list → butterbase-apps project ID # Stripe (Billing) STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key_here STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here STRIPE_CONNECT_WEBHOOK_SECRET=whsec_your_connect_webhook_secret_here # Redis (Usage Metering) REDIS_URL=redis://localhost:6379 # Dashboard URL (for billing redirects) DASHBOARD_URL=http://localhost:3000 # Office frontend origins (CORS). OFFICE_URL is the legacy single origin; # OFFICE_ALLOWED_ORIGINS is a comma-separated list (demo + customer). OFFICE_URL=http://localhost:3100 OFFICE_ALLOWED_ORIGINS= # OpenRouter (AI Features) OPENROUTER_API_KEY=sk-or-v1-your_openrouter_key_here # NEON_DATA_DATABASE_OWNER= # Optional; default butterbase (role is auto-created on the branch if missing). Use neondb_owner to use Neon’s default role instead. # Deno Runtime URL (defaults to http://deno-runtime:7133 in local Docker) # DENO_RUNTIME_URL=https://butterbase-runtime.fly.dev # Full connection string for cron-scheduler and deno-runtime # In local dev, compose sets this automatically. In production, use the Neon connection string. # CONTROL_PLANE_URL=postgresql://butterbase:***@localhost:5432/butterbase_control # Phase 3: shared secret for region-to-region internal calls (lease grant) and # cron-scheduler -> control-api calls (drain trigger, orphan cleanup). # Rotate quarterly. Set the same value on every Fly app. BUTTERBASE_INTERNAL_SECRET=dev-internal-secret-change-me # The region whose runtime DB is in the same Neon project as the platform DB. # Other regions route lease-grant requests to this region's control-api. BUTTERBASE_PLATFORM_REGION=us-east-1 # Phase 3: lease tuning BUTTERBASE_LEASE_SIZE_USD=1.00 # required when running control-api outside compose BUTTERBASE_LEASE_REFILL_THRESHOLD_USD=0.20 BUTTERBASE_LEASE_TTL_SECONDS=300 BUTTERBASE_LEASE_RECLAIM_GRACE_SECONDS=30 DEFAULT_FREE_PLAN_AI_CREDITS_USD=5.00 # required when running control-api outside compose BUTTERBASE_OUTBOX_DRAIN_INTERVAL_MS=1000 BUTTERBASE_OUTBOX_LAG_ALERT_SECONDS=30 # URL of the control-api in BUTTERBASE_PLATFORM_REGION. Other regions call # this for lease grants. CONTROL_PLANE_URL_PLATFORM_REGION=http://control-api.us-east-1.internal:4000 # Phase 4: per-region Neon data project IDs. One entry per region in BUTTERBASE_REGIONS. NEON_DATA_PROJECT_ID_US_EAST_1=local-dev-data-project # Legacy fallback used only for region "local" (kept so dev defaults still work). NEON_DATA_PROJECT_ID=local-dev-data-project # Phase 5: move-app saga MOVE_APP_DRIVER_ENABLED=true MOVE_APP_STEP_TIMEOUT_SECONDS=1800 # Per-region intermediate dump storage (R2 or S3-compatible) MOVE_APP_DUMP_BUCKET=butterbase-move-app-dumps-local R2_ENDPOINT= # AI Gateway Markup AI_MARKUP_PERCENT=0 # markup as percentage; set per your pricing strategy # Suggestions Notification SUGGESTIONS_NOTIFICATION_EMAIL= # email for platform suggestions/feedback # Idle free-app reaper: disabled until explicitly configured. Requires runtime # migrations 056 and 059 and a shared REDIS_URL across all control-api replicas. # Start with a two-week dry run; public traffic, not cron, records activity. # BUTTERBASE_IDLE_PAUSE_DAYS=28 # BUTTERBASE_IDLE_PAUSE_DRY_RUN=true # BUTTERBASE_IDLE_PAUSE_WARN_DAYS=7 # BUTTERBASE_IDLE_PAUSE_REMINDER_DAYS=3 # smaller than WARN_DAYS; 0 disables reminder # Without an override: min(3, WARN_DAYS - 1), preserving shorter warning windows. # BUTTERBASE_IDLE_PAUSE_GRACE_DAYS=5 # BUTTERBASE_IDLE_PAUSE_MIN_VISITORS=3 # BUTTERBASE_IDLE_PAUSE_PLANS=playground # BUTTERBASE_IDLE_PAUSE_MAX_PER_TICK=25 # BUTTERBASE_IDLE_PAUSE_MAX_FRACTION=0.2 # SKIP_IDLE_PAUSE_REAPER=1