Bondery Docs

Configuration

Operators configure the stack with BONDERY_* names. Copy deploy/bondery/.env.example to .env — that file is generated from packages/helpers/src/env/manifest.ts (deployExample metadata). Do not hand-edit the example; change the manifest and run pnpm run env -- --write-examples.

Core secrets

VariablePurpose
BONDERY_PRIVATE_BETTER_AUTH_SECRETSBetter Auth versioned signing secrets (version:secret, highest version first)
BONDERY_PRIVATE_POSTGRES_PASSWORDPostgres password (compose db service)
BONDERY_PRIVATE_API_KEY_PEPPERAPI key hashing pepper
BONDERY_PRIVATE_REDIS_URLredis://redis:6379 in the default stack. Stores rate-limit counters, sync wake pub/sub, WebSocket tickets (sync:ws-ticket:*), and Better Auth secondary storage (bondery:auth:* — sessions and verification records, dual-written with Postgres).

DATABASE_URL

DATABASE_URL is the standard Postgres connection string the API uses for everything that touches the database: Prisma ORM (@bondery/db), Better Auth sessions, and the pg-boss job queue.

postgresql://postgres:<password>@db:5432/bondery
ContextWho sets it
Self-host composeYou set BONDERY_PRIVATE_POSTGRES_PASSWORD in .env; compose derives DATABASE_URL for the api service automatically — you do not need to paste the URL into .env.
Local developmentYou set DATABASE_URL in root .env.local (see Environment configuration).
WebappDoes not use DATABASE_URL — it talks to the API over HTTP.

Used in: apps/api (Prisma client, pg-boss), packages/db (migrations), and one-off migration scripts under packages/db/scripts/.

Domains

Set hostnames only:

BONDERY_INFRA_API_DOMAIN=api.example.com
BONDERY_INFRA_WEBAPP_DOMAIN=app.example.com

Compose derives public https://… URLs and Traefik Host() rules. Do not set BONDERY_PUBLIC_*_URL in the stack .env unless you have a non-standard setup.

OAuth (Better Auth)

Auth runs on the API (/auth/*). The API is its own OAuth issuer (baseURL = BONDERY_PUBLIC_API_URL). Webapp, mobile, and the Chrome extension are independent OAuth 2.1 + PKCE clients.

  1. Set BONDERY_PRIVATE_AUTH_GITHUB_* and BONDERY_PRIVATE_AUTH_LINKEDIN_*.

  2. In GitHub / LinkedIn developer settings, callback URL:

    https://<BONDERY_INFRA_API_DOMAIN>/auth/callback/github (or /linkedin)

  3. Generate and set values for BONDERY_PUBLIC_WEBAPP_OAUTH_CLIENT_ID, BONDERY_PRIVATE_WEBAPP_OAUTH_CLIENT_SECRET, BONDERY_PUBLIC_OAUTH_CLIENT_ID (extension), and BONDERY_PRIVATE_WEBAPP_SESSION_SECRET (≥32 chars) — e.g. openssl rand -hex 32. These are arbitrary values you choose, not issued by anything.

  4. Set BONDERY_INFRA_CHROME_EXTENSION_ID so the API allows the extension redirect URI.

    OAuth clients are upserted automatically when api pre_start runs release-migrate (right after prisma migrate deploy). There is no separate registration step or session cookie required.

  5. Set BONDERY_PRIVATE_PLATFORM_ADMIN_EMAILS to a comma-separated list of operator account emails. Matching users are promoted to user.role = admin when api pre_start runs release-migrate. Optional break-glass: BONDERY_PRIVATE_PLATFORM_ADMIN_USER_IDS (comma-separated UUIDs).

See Secrets management for production secret storage and rotation runbooks.

Storage

Object storage uses SeaweedFS (S3-compatible gateway). The API uploads via private S3 credentials; browsers load public objects from BONDERY_PUBLIC_STORAGE_URL.

VariablePurpose
BONDERY_PRIVATE_S3_ENDPOINTInternal S3 endpoint. Compose derives http://${BONDERY_INFRA_TRAEFIK_PREFIX}-storage:8333 (do not use http://seaweedfs-s3:8333 — that DNS name collides on shared dokploy-network). Local dev: http://127.0.0.1:8333.
BONDERY_PRIVATE_S3_REGIONS3 region label (e.g. eu-central-1)
BONDERY_PRIVATE_S3_ACCESS_KEY_ID / BONDERY_PRIVATE_S3_SECRET_ACCESS_KEYS3 credentials (same pair seeds the seaweedfs-s3 gateway config)
BONDERY_PUBLIC_STORAGE_URLPublic base URL for avatar/logo reads (Traefik → storage domain in prod; http://127.0.0.1:8333 locally)
BONDERY_INFRA_STORAGE_DOMAINHostname for Traefik routing to the S3 gateway (Compose only)

Buckets: avatars (contact photos) and linkedin-logos (cached LinkedIn company/school logos). Created and given anonymous read policy by api pre_startensure-storage-buckets.

On every deploy, api pre_start runs release-migrate (schema, functions, OAuth clients, platform admins) then ensure-storage-buckets before the main API process starts. See Installation and Dokploy deployment.

Local development parity

Contributors use the same variable names in root .env.local. See Environment configuration.

On this page