Skip to main content

Backend Configuration

Complete reference for all environment variables consumed by the Go backend. The authoritative source is internal/app/env-setup.go (API server) and internal/app/env-setup-worker.go (eventsync worker).

Phase 0 note: per-variable descriptions, valid values, and environment-specific requirements to be filled in during baseline generation.

Environment groups

GroupEnv structPurpose
CoreRuntime environment label (local, dev, prod)
CookieCookieEnvSession cookie signing and encryption keys, domain, Gin mode
WebsiteWebsiteEnvFrontend base URL (used for redirect URIs)
LiveKitLiveKitEnvLiveKit Cloud API key/secret, server URL, project and region
WorkOSWorkOSEnvAuthKit API key, client ID, SSO/OAuth redirect URIs, webhook secret
WebSocketWebSocketEnvOffice-router Worker base URL, JWT issuer/audience/private key
R2 FilesR2EnvCloudflare R2 credentials and bucket for recording temp storage
R2 AvatarsR2AvatarEnvSeparate R2 bucket and public URL for user/org avatar storage
CloudflareCloudflareEnvCloudflare Worker URL (office-router)
GoogleGoogleEnvGoogle OAuth credentials (Calendar integration)
AvatarAvatarEnvAvatar processing config
Org LogoOrgLogoEnvOrg logo processing config
RecordingRecordingEnvRecording pipeline config
GrafanaGrafanaEnvGrafana Mimir push endpoint and credentials
SupabaseSupabaseEnvJWT secret (used to validate Supabase-issued tokens)
WebhookWebhookEnvInbound webhook signing secret (WorkOS events)
CORSCORSEnvPer-environment browser origin allowlist for credentialed CORS
SentrySentryEnvError reporting DSN, release tag, and performance-tracing sample rate

Worker-specific overrides

The eventsync worker binary reads the same env file as the API server but supports one override:

  • WORKER_POSTGRES_URL — if set, replaces POSTGRES_URL for the worker process. Used to point the worker at a dedicated database while the API server continues using the main one.

Notes

  • All secrets (keys, signing secrets, credentials) are managed as org-level GitHub Actions secrets and injected at deploy time by Sevalla. No secrets are committed to the repository.
  • Local development uses a .env file loaded by godotenv. The file is gitignored; obtain values from the shared secrets store.
  • The GIN_MODE variable controls Gin's behaviour: debug locally, release in production. Setting debug in production degrades performance and enables verbose output.

Variable reference

Audited from internal/app/env-setup.go (API) and the worker loader against actual read sites. Req = required (boot fails if missing); Opt = optional, with the default shown. Two binaries load different subsets: the API (cmd/api) loads the full set via LoadEnvVariables(); the worker (cmd/worker) loads a minimal subset via LoadWorkerEnvVariables().

Loader invariant: LoadEnvVariables() contains only variables that are both required and actually used — no dead loads. Optional knobs with a safe built-in default are the one exception. Per-environment values (local / staging / prod) live with the run dev tooling, not here; this section documents meaning, location, and necessity.

App / runtime

VariableReqMeaningRead at
APP_ENVOpt (prod)Environment name (local/development/staging/prod). Gates pilot-invite endpoints and prod-only logging sinks.env-setup.go, cmd/api/main.go, internal/app/slog-setup.go
GIN_MODEReqGin mode (debug/release/test). release flips cookies to secure/prod behaviour.pkg/token/manager.go
APP_DOMAINReqCookie domain for the auth cookie.pkg/token

Cookies & token encryption

VariableReqMeaningRead at
COOKIE_HASH_KEYReqHMAC key for signed cookies (securecookie).pkg/token
COOKIE_BLOCK_KEYReqAES key for encrypted cookies (securecookie).pkg/token
TOKEN_ENCRYPTION_KEY_V1ReqHex-encoded AES-256 key (must decode to 32 bytes) for encrypting refresh tokens at rest in user_sessions / user_integrations.pkg/token/manager.go, pkg/token/aead.go

Frontend / WorkOS auth

VariableReqMeaningRead at
WEBSITE_BASE_URLReqPublic frontend base URL; used to build invite links.internal/features/user/service/generate_pilot_invite.go, internal/features/membership/service/invitelink.go
WORKOS_API_KEYReqWorkOS server API key.setupWorkOS → WorkOS SDK
WORKOS_CLIENT_IDReqWorkOS client id; also the expected JWT audience/issuer for access-token validation.setupWorkOS, token validator
WORKOS_SSO_REDIRECT_URIReqSign-in SSO callback (enterprise/SSO flow).internal/features/authentication/service/discoverauth.go, oauth.go
WORKOS_REDIRECT_URI_WEBReqSign-in callback for web social auth (Google/Microsoft via web client). Distinct flow from the SSO callback.internal/features/authentication/service/oauth.go
WORKOS_INTEGRATIONS_REDIRECT_URIReqOAuth callback for Google Calendar integration connect/finalize.internal/features/calendar/google/service/connectcalendar.go, finalizecalendar.go
WORKOS_FAKE_LOGOUT_REDIRECT_URIReqPost-logout ReturnTo: where WorkOS sends the browser after sign-out. Must be a user-facing frontend URL.internal/features/session/service/logout.go

Logout wiring note. WORKOS_FAKE_LOGOUT_REDIRECT_URI is the logout ReturnTo. It currently points at a placeholder GET /login stub (cmd/api/main.go); replace the stub (and consider renaming the variable to WORKOS_LOGOUT_REDIRECT_URI) once a real logged-out page exists.

LiveKit

VariableReqMeaningRead at
LIVEKIT_API_KEYReqLiveKit Cloud API key.setupLivekit → LiveKit SDK
LIVEKIT_API_SECRETReqLiveKit Cloud API secret.setupLivekit
LIVEKIT_URLReqLiveKit Cloud websocket URL.setupLivekit
LIVEKIT_PROJECTOpt (default)Project label applied to Prometheus metrics and PromQL analytics queries.pkg/metrics/livekit.go, internal/features/analytics/service/panels.go
LIVEKIT_REGIONOpt (global)Region label, same usage as project.same as above

CORS

VariableReqMeaningRead at
CORS_ALLOWED_ORIGINSReqComma-separated, exact-match browser origin allowlist (scheme+host+port, no trailing slash). Because auth uses credentialed (cookie) CORS, * is forbidden and an empty/unset list fails closed at boot.internal/app/env-setup.go (getRequiredCSV) → pkg/middleware/cors.go

Cloudflare R2 (storage)

VariableReqMeaningRead at
R2_ACCESS_KEYReqR2 access key (S3-compatible).setupR2Config
R2_SECRET_KEYReqR2 secret key.setupR2Config
R2_REGIONOpt (auto)Region passed to the AWS SDK config.internal/platform/cloudflare/r2/client.go
R2_ENDPOINTReqR2 S3 endpoint.setupR2Config
R2_BUCKETReqGeneral storage bucket (recordings, etc.).setupR2Config
R2_PUBLIC_BASE_URLReqPublic base URL used to build object URLs.internal/platform/cloudflare/r2/client.go, internal/features/shared/imageupload/service.go
R2_AVATAR_BUCKETReqSeparate bucket for avatars/logos.setupR2AvatarClient
R2_AVATAR_PUBLIC_BASE_URLReqPublic base URL for avatar/logo objects.avatar client
R2_STORAGE_RETENTION_DAYSOpt (90)Days an R2 recording file is retained before storage expiry.recording service
R2_FORCE_PATH_STYLEOpt (false)Path-style S3 addressing for the LiveKit egress upload. false (prod) = virtual-hosted; the dev stack sets true because MinIO on a localhost endpoint has no bucket-subdomain DNS. Egress-only.setupR2Configinternal/platform/livekit/client.go

Google

VariableReqMeaningRead at
GOOGLE_CLIENT_IDReqGoogle OAuth client id (Calendar integration).setupGoogle
GOOGLE_CLIENT_SECRETReqGoogle OAuth client secret.setupGoogle

Grafana Mimir (customer-facing analytics)

VariableReqMeaningRead at
GRAFANA_MIMIR_URLReqMimir query endpoint.internal/features/analytics/service/query_panel.go
GRAFANA_MIMIR_INSTANCE_IDReqMimir tenant/instance id.internal/platform/grafana/mimir/client.go
GRAFANA_MIMIR_API_TOKENReqMimir API token.internal/platform/grafana/mimir/client.go

Supabase / webhooks / uploads

VariableReqMeaningRead at
SUPABASE_JWT_SECRETReqHS256 secret to sign Supabase Realtime JWTs.internal/features/realtime/service/generatetoken.go
WEBHOOK_SUPABASE_SECRETReqShared secret verified (constant-time) on inbound webhook calls (X-Webhook-Secret).internal/features/recording/api/reconcile_handler.go
AVATAR_MAX_UPLOAD_TRIESOpt (3)Per-user avatar upload attempt cap.internal/features/user/service/avatar.go
ORG_LOGO_MAX_UPLOAD_TRIESOpt (5)Per-org logo upload attempt cap.internal/features/organization/service/logo.go
RECORDING_ACCESS_RETENTION_DAYSOpt (20)Days a recording is accessible in-app before access expiry.recording service

Sentry / error reporting

VariableReqMeaningRead at
SENTRY_DSNOpt ("")Sentry project ingest URL. Empty installs a no-op transport (events dropped, no network) — the intended local-dev default.internal/app/sentry-setup.go
SENTRY_RELEASEOpt ("")Build/version identifier tagged on events.internal/app/sentry-setup.go
SENTRY_TRACES_SAMPLE_RATEOpt (1.0)Fraction [0.0–1.0] of transactions captured for performance tracing; tracing is enabled iff the rate is > 0 (so 0 disables it).internal/app/env-setup.go (getFloat) → internal/app/sentry-setup.go

Read directly (outside the loader)

Not in LoadEnvVariables() — read at their point of use.

VariableReqMeaningRead at
POSTGRES_URLReqPostgres/Supabase connection string.internal/database/database.go, internal/database/migrate.go
OTEL_EXPORTER_OTLP_ENDPOINTOptIf set (and APP_ENV is staging/prod), enables OTLP log export.internal/app/slog-setup.go
BETTER_STACK_TOKENOptIf set (staging/prod), enables Better Stack log shipping.internal/app/slog-setup.go
BETTER_STACK_ENDPOINTOpt (https://in.logs.betterstack.com)Better Stack ingest endpoint.internal/app/slog-setup.go

Worker binary — LoadWorkerEnvVariables() (cmd/worker)

VariableReqMeaning
APP_ENVOpt (prod)Environment name.
WORKOS_API_KEYReqWorkOS API key (the worker only needs WorkOS).
WORKOS_CLIENT_IDReqWorkOS client id.
POSTGRES_URLReqDB connection (read directly via database.New).
WORKER_POSTGRES_URLOptIf set, overrides POSTGRES_URL for the worker (separate pool).

Test-only

VariableMeaning
WORKOS_TEST_API_KEYWorkOS key for the eventsync integration test only.
WORKOS_TEST_CLIENT_IDWorkOS client id for the same integration test.

Removed / no longer read

Previously loaded at boot but removed once their only consumers were disabled or deleted (the loader admits no dead loads). Delete these from every environment.

Variable(s)What it wasWhy removed
CF_WORKER_URL, CF_ACCESS_CLIENT_ID, CF_ACCESS_CLIENT_SECRETCloudflare "Notifier" serviceConstructed but never injected into any service and never called; package deleted.
WORKOS_WEBHOOK_SECRETInbound WorkOS webhook verificationThe POST /webhook/workos route was commented out; the handler was unreachable.
JWT_ISSUER, JWT_AUDIENCE, JWT_PRIVATE_KEYRSA signing material for the Cloudflare Durable-Object websocket access tokenThe DO route was commented out; realtime is now served by the live Supabase Realtime path (SUPABASE_JWT_SECRET).