| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- # briven — canonical self-host compose (build-from-source).
- #
- # Post ADR-0002 (docs/ADR/0002-converge-on-doltgres.md): the platform
- # runs on TWO database engines, on purpose:
- #
- # - control plane = DoltGres database briven_control (product line: all Doltgres).
- # sign-in, orgs, projects, billing, secrets, auth. drizzle migrations
- # run at api boot. NEVER points at DoltGres.
- # - data plane = DoltGres (dolthub/doltgresql), env BRIVEN_DATA_PLANE_URL.
- # Postgres-wire, accessed with the `pg` driver, one DATABASE per
- # customer project. Realtime polls DOLT_HASHOF('HEAD') (no LISTEN/NOTIFY).
- #
- # This file supersedes the two earlier conflicting composes:
- # - the old Dolt-MySQL build (dolthub/dolt-sql-server + BRIVEN_URL mysql) —
- # wrong engine, broke the api. REMOVED.
- # - the all-pgvector build (data plane as a 2nd Postgres DB) — wrong data
- # plane. REPLACED by the real DoltGres service below.
- #
- # Dokploy clones the repo and runs `docker compose build` against the local
- # Dockerfiles — no external registry, no GHCR, no docker.sock. Per
- # docs/DOCKER.md §7 / infra/CLAUDE.md: every long-running service caps its
- # log volume via the *briven-logging anchor; no watchtower, no docker_sd,
- # no registry polling on the host.
- #
- # Single-machine layout, ~25 concurrent customer projects. Past that, split
- # the control plane onto one host and the data plane (doltgres + minio) onto
- # another.
- #
- # Required env (drop a `.env` next to this file — see .env.example):
- #
- # BRIVEN_DOMAIN e.g. briven.example.com
- # BRIVEN_BETTER_AUTH_SECRET openssl rand -hex 32
- # BRIVEN_AUDIT_IP_PEPPER openssl rand -hex 32
- # BRIVEN_ENCRYPTION_KEY openssl rand -hex 32
- # BRIVEN_RUNTIME_SHARED_SECRET openssl rand -hex 32
- # BRIVEN_POSTGRES_PASSWORD control-plane Postgres superuser password
- # BRIVEN_DOLTGRES_PASSWORD data-plane DoltGres superuser password
- # BRIVEN_MINIO_ROOT_PASSWORD MinIO root / S3 secret key
- # (optional) BRIVEN_MITTERA_*, BRIVEN_*_CLIENT_ID/SECRET, BRIVEN_POLAR_*,
- # BRIVEN_OLLAMA_*, BRIVEN_MINIO_BUCKET/REGION, BRIVEN_OPEN_SIGNUPS
- #
- # After first boot:
- # 1. Create the first user via the magic-link flow on https://${BRIVEN_DOMAIN}
- # 2. Promote to admin in the control plane:
- # docker exec -it briven-postgres psql -U postgres -d briven_control \
- # -c "UPDATE users SET is_admin = true WHERE id = '...';"
- # 3. Create your first project via the dashboard (provisions a DoltGres DB).
- # Explicit project name so compose resources are deterministically `briven_*`
- # (containers already pin container_name: briven-*). Without this, the project
- # name defaults to the parent directory ("dokploy"), which would create
- # `dokploy_*` volumes — confusingly close to the Dokploy platform's own naming
- # and a trap for host-maintenance tooling. Build AND up must share this name.
- name: briven
- x-logging: &briven-logging
- driver: json-file
- options:
- max-size: '10m'
- max-file: '3'
- services:
- # ─── control plane ────────────────────────────────────────────────────
- postgres:
- image: pgvector/pgvector:pg17
- container_name: briven-postgres
- restart: unless-stopped
- logging: *briven-logging
- environment:
- POSTGRES_PASSWORD: ${BRIVEN_POSTGRES_PASSWORD}
- POSTGRES_DB: briven_control
- volumes:
- - postgres_data:/var/lib/postgresql/data
- # Control-plane init only: enables pgvector + pg_trgm on briven_control.
- # No data-plane DB is created here — the data plane is the doltgres
- # service, with a database per project (see ADR-0002).
- - ./postgres-init:/docker-entrypoint-initdb.d:ro
- healthcheck:
- test: ['CMD-SHELL', 'pg_isready -U postgres -d briven_control']
- interval: 10s
- timeout: 5s
- retries: 5
- start_period: 20s
- networks:
- - briven
- labels:
- - 'briven_logs=true'
- # ─── data plane ───────────────────────────────────────────────────────
- # DoltGres = Postgres-wire, git-for-data. Each customer project is its own
- # DATABASE here, created by the api over the `pg` driver. The default
- # superuser/database is `postgres`/`postgres` (DOLTGRES_* envs override the
- # password).
- #
- # IMAGE IS PINNED BY DIGEST, ON PURPOSE (2026-07-07 maintenance window):
- # `:latest` let a deploy silently swap the database engine under live data
- # (prime suspect in the 2026-07-07 auth.db outage). To upgrade the engine,
- # change the digest here deliberately, in its own reviewed deploy.
- #
- # DATA DIR IS /var/lib/doltgres — NO "ql". The mount below once pointed at
- # /var/lib/doltgresql (typo), so all real data lived in an anonymous volume
- # that a container recreation would orphan. Fixed 2026-07-07 (data migrated
- # into the named volume during the maintenance window). Never change this
- # path without checking `config.yaml` inside the volume.
- doltgres:
- image: dolthub/doltgresql@sha256:0483137d0309598d3b0c111dff85d565077bd91cb0524ce00bb832929d5d5ddc
- container_name: briven-doltgres
- restart: unless-stopped
- logging: *briven-logging
- environment:
- DOLTGRES_USER: postgres
- DOLTGRES_PASSWORD: ${BRIVEN_DOLTGRES_PASSWORD}
- volumes:
- - doltgres_data:/var/lib/doltgres
- # Dolt-native backups land here (written by the server itself); the
- # dolt-backup service triggers them. See that service for details.
- - doltgres_backups:/backups
- healthcheck:
- # pg_isready ships in the doltgresql image and needs no password.
- test: ['CMD-SHELL', 'pg_isready -h 127.0.0.1 -p 5432 -U postgres']
- interval: 10s
- timeout: 5s
- retries: 5
- start_period: 30s
- networks:
- - briven
- labels:
- - 'briven_logs=true'
- # ─── data-plane backup ──────────────────────────────────────────────────
- # REAL DoltGres backup (replaces the old placeholder sleep loop).
- #
- # Why NOT pg_dump: tested 2026-06-26 against dolthub/doltgresql:latest
- # (v0.56.6) — `pg_dump` aborts immediately with
- # "ERROR: SET TRANSACTION is not yet supported"
- # because pg_dump opens a REPEATABLE READ READ ONLY snapshot transaction
- # that DoltGres does not implement. So pg_dump CANNOT back up the data
- # plane. (The control plane is real Postgres and is dumped separately by
- # the host timers in infra/backups/.)
- #
- # What works (verified same day): Dolt's own backup, invoked over the
- # Postgres wire with `SELECT dolt_backup('sync-url', '<file-url>')`. It
- # writes a full, version-history-preserving Dolt archive (manifest +
- # .darc) — re-running it re-syncs in place, so one backup dir per database
- # already contains every commit (time-travel restore, not just a snapshot).
- #
- # This sidecar reuses the doltgresql image (it has `psql`), enumerates the
- # data-plane databases each run, and asks the doltgres SERVER to back each
- # one up into the shared `doltgres_backups` volume.
- #
- # OFF-SITE follow-up: mirroring the `doltgres_backups` volume to MinIO/B2/R2
- # is done today by the host systemd timers in infra/backups/ (mc-based, see
- # briven-backup.sh). Folding an `mc mirror /backups -> minio` step into this
- # service needs an image carrying both psql and mc; tracked as a follow-up.
- dolt-backup:
- # Pinned to the SAME digest as the doltgres service (2026-07-07 window) —
- # the sidecar's psql must always match the server's engine version.
- image: dolthub/doltgresql@sha256:0483137d0309598d3b0c111dff85d565077bd91cb0524ce00bb832929d5d5ddc
- container_name: briven-dolt-backup
- restart: unless-stopped
- logging: *briven-logging
- depends_on:
- doltgres:
- condition: service_healthy
- environment:
- PGHOST: doltgres
- PGPORT: '5432'
- PGUSER: postgres
- PGPASSWORD: ${BRIVEN_DOLTGRES_PASSWORD}
- BRIVEN_BACKUP_INTERVAL_SECONDS: ${BRIVEN_BACKUP_INTERVAL_SECONDS:-86400}
- volumes:
- - doltgres_backups:/backups
- # Read-only view of the server's data dir, ONLY so auth.db (the engine's
- # users/grants file — corrupted once on 2026-07-07, nothing backed it up)
- # can be snapshotted alongside the dolt backups below.
- - doltgres_data:/doltgres-data:ro
- entrypoint: ['/bin/sh', '-c']
- command:
- - |
- set -eu
- echo "dolt-backup: starting (interval=${BRIVEN_BACKUP_INTERVAL_SECONDS:-86400}s)"
- while true; do
- ts="$$(date -u +%Y-%m-%dT%H:%M:%SZ)"
- echo "[dolt-backup $$ts] enumerating data-plane databases"
- # All non-template databases on the doltgres server (one per project,
- # plus the default `postgres`). -tA = tuples only, unaligned.
- dbs="$$(psql -tA -d postgres -c \
- "SELECT datname FROM pg_database WHERE datname NOT IN ('template0','template1')")"
- for db in $$dbs; do
- echo "[dolt-backup $$ts] backing up $$db -> file:///backups/$$db"
- if psql -d "$$db" -c \
- "SELECT dolt_backup('sync-url', 'file:///backups/$$db');" >/dev/null; then
- echo "[dolt-backup $$ts] ok $$db"
- else
- echo "[dolt-backup $$ts] WARN backup failed for $$db"
- fi
- done
- # auth.db snapshot — tiny file, changes only on role/grant edits.
- # Keep the newest 14 copies (2 weeks at the daily default interval).
- if [ -f /doltgres-data/auth.db ]; then
- mkdir -p /backups/auth-db
- if cp /doltgres-data/auth.db "/backups/auth-db/auth.db.$$ts"; then
- echo "[dolt-backup $$ts] ok auth.db snapshot"
- ls -1t /backups/auth-db | tail -n +15 | while read -r old; do
- rm -f "/backups/auth-db/$$old"
- done
- else
- echo "[dolt-backup $$ts] WARN auth.db snapshot failed"
- fi
- else
- echo "[dolt-backup $$ts] WARN auth.db not found in data dir"
- fi
- echo "[dolt-backup $$ts] run complete; sleeping"
- sleep "$${BRIVEN_BACKUP_INTERVAL_SECONDS:-86400}"
- done
- networks:
- - briven
- labels:
- - 'briven_logs=true'
- # ─── shared infra ─────────────────────────────────────────────────────
- redis:
- image: redis:7.4-alpine
- container_name: briven-redis
- restart: unless-stopped
- logging: *briven-logging
- command: redis-server --appendonly yes
- volumes:
- - redis_data:/data
- healthcheck:
- test: ['CMD-SHELL', 'redis-cli ping | grep -q PONG']
- interval: 10s
- timeout: 5s
- retries: 5
- start_period: 10s
- networks:
- - briven
- labels:
- - 'briven_logs=true'
- minio:
- image: minio/minio:latest
- container_name: briven-minio
- restart: unless-stopped
- logging: *briven-logging
- command: server /data --console-address ':9001'
- environment:
- MINIO_ROOT_USER: briven
- MINIO_ROOT_PASSWORD: ${BRIVEN_MINIO_ROOT_PASSWORD}
- volumes:
- - minio_data:/data
- healthcheck:
- test: ['CMD-SHELL', 'curl -fsS http://localhost:9000/minio/health/live || exit 1']
- interval: 15s
- timeout: 5s
- retries: 5
- start_period: 20s
- networks:
- - briven
- - dokploy-network
- labels:
- - 'briven_logs=true'
- - 'traefik.enable=true'
- - 'traefik.docker.network=dokploy-network'
- # Public S3 endpoint — browsers PUT/GET with sigv4-presigned URLs the
- # api mints. The api also reaches MinIO internally at http://minio:9000.
- - 'traefik.http.routers.briven-s3.rule=Host(`s3.${BRIVEN_DOMAIN}`)'
- - 'traefik.http.routers.briven-s3.entrypoints=websecure'
- - 'traefik.http.routers.briven-s3.tls.certresolver=letsencrypt'
- - 'traefik.http.routers.briven-s3.service=briven-s3'
- - 'traefik.http.services.briven-s3.loadbalancer.server.port=9000'
- # One-shot bucket creator. `mc mb --ignore-existing` is idempotent, so this
- # runs every deploy and no-ops after the first. restart: 'no' = one-shot, so
- # per infra/CLAUDE.md it does NOT need the logging cap.
- minio-init:
- image: minio/mc:latest
- container_name: briven-minio-init
- depends_on:
- minio:
- condition: service_healthy
- entrypoint: >
- /bin/sh -c "
- until /usr/bin/mc alias set minio http://minio:9000 briven ${BRIVEN_MINIO_ROOT_PASSWORD} >/dev/null 2>&1; do
- echo 'waiting for minio...'; sleep 2;
- done;
- /usr/bin/mc mb --ignore-existing minio/${BRIVEN_MINIO_BUCKET:-briven};
- echo 'minio bucket ready: ${BRIVEN_MINIO_BUCKET:-briven}';
- "
- restart: 'no'
- networks:
- - briven
- # ─── application services ─────────────────────────────────────────────
- api:
- build:
- context: ../..
- dockerfile: apps/api/Dockerfile
- container_name: briven-api
- restart: unless-stopped
- logging: *briven-logging
- depends_on:
- postgres:
- condition: service_healthy
- doltgres:
- condition: service_healthy
- redis:
- condition: service_healthy
- environment:
- BRIVEN_ENV: production
- BRIVEN_API_PORT: '3001'
- BRIVEN_API_ORIGIN: https://api.${BRIVEN_DOMAIN}
- BRIVEN_WEB_ORIGIN: https://${BRIVEN_DOMAIN}
- BRIVEN_TRUSTED_ORIGINS: https://${BRIVEN_DOMAIN},https://api.${BRIVEN_DOMAIN}
- # Control plane — stock Postgres, postgres.js/drizzle.
- BRIVEN_DATABASE_URL: postgres://postgres:${BRIVEN_DOLTGRES_PASSWORD}@doltgres:5432/briven_control?sslmode=disable
- # Data plane — DoltGres, `pg` driver, database-per-project. The api
- # connects to the default `postgres` database and CREATEs per-project
- # databases on this server.
- BRIVEN_DATA_PLANE_URL: postgres://postgres:${BRIVEN_DOLTGRES_PASSWORD}@doltgres:5432/postgres?sslmode=disable
- BRIVEN_REDIS_URL: redis://redis:6379
- BRIVEN_RUNTIME_URL: http://runtime:3003
- # Without this the api falls back to localhost:3004 and can't reach
- # realtime — surfaces as realtime_stats_failed "Unable to connect".
- BRIVEN_REALTIME_URL: http://realtime:3004
- BRIVEN_RUNTIME_SHARED_SECRET: ${BRIVEN_RUNTIME_SHARED_SECRET}
- BRIVEN_BETTER_AUTH_SECRET: ${BRIVEN_BETTER_AUTH_SECRET}
- BRIVEN_AUDIT_IP_PEPPER: ${BRIVEN_AUDIT_IP_PEPPER}
- BRIVEN_ENCRYPTION_KEY: ${BRIVEN_ENCRYPTION_KEY}
- BRIVEN_MITTERA_API_URL: ${BRIVEN_MITTERA_API_URL:-}
- BRIVEN_MITTERA_API_KEY: ${BRIVEN_MITTERA_API_KEY:-}
- BRIVEN_MITTERA_WEBHOOK_SECRET: ${BRIVEN_MITTERA_WEBHOOK_SECRET:-}
- BRIVEN_GOOGLE_CLIENT_ID: ${BRIVEN_GOOGLE_CLIENT_ID:-}
- BRIVEN_GOOGLE_CLIENT_SECRET: ${BRIVEN_GOOGLE_CLIENT_SECRET:-}
- BRIVEN_GITHUB_CLIENT_ID: ${BRIVEN_GITHUB_CLIENT_ID:-}
- BRIVEN_GITHUB_CLIENT_SECRET: ${BRIVEN_GITHUB_CLIENT_SECRET:-}
- BRIVEN_KONNOS_CLIENT_ID: ${BRIVEN_KONNOS_CLIENT_ID:-}
- BRIVEN_KONNOS_CLIENT_SECRET: ${BRIVEN_KONNOS_CLIENT_SECRET:-}
- BRIVEN_KONNOS_ISSUER: ${BRIVEN_KONNOS_ISSUER:-https://code.konnos.org}
- BRIVEN_DISCORD_CLIENT_ID: ${BRIVEN_DISCORD_CLIENT_ID:-}
- BRIVEN_DISCORD_CLIENT_SECRET: ${BRIVEN_DISCORD_CLIENT_SECRET:-}
- BRIVEN_POLAR_API_BASE: ${BRIVEN_POLAR_API_BASE:-https://api.polar.sh}
- BRIVEN_POLAR_ACCESS_TOKEN: ${BRIVEN_POLAR_ACCESS_TOKEN:-}
- BRIVEN_POLAR_WEBHOOK_SECRET: ${BRIVEN_POLAR_WEBHOOK_SECRET:-}
- BRIVEN_POLAR_PRO_PRODUCT_ID: ${BRIVEN_POLAR_PRO_PRODUCT_ID:-}
- BRIVEN_POLAR_TEAM_PRODUCT_ID: ${BRIVEN_POLAR_TEAM_PRODUCT_ID:-}
- BRIVEN_DOMAIN: ${BRIVEN_DOMAIN}
- BRIVEN_OPEN_SIGNUPS: ${BRIVEN_OPEN_SIGNUPS:-false}
- BRIVEN_OLLAMA_URL: ${BRIVEN_OLLAMA_URL:-}
- BRIVEN_OLLAMA_API_KEY: ${BRIVEN_OLLAMA_API_KEY:-}
- BRIVEN_OLLAMA_MODEL: ${BRIVEN_OLLAMA_MODEL:-qwen2.5-coder:32b}
- BRIVEN_MINIO_ENDPOINT: http://minio:9000
- BRIVEN_MINIO_PUBLIC_ENDPOINT: https://s3.${BRIVEN_DOMAIN}
- BRIVEN_MINIO_ACCESS_KEY: briven
- BRIVEN_MINIO_SECRET_KEY: ${BRIVEN_MINIO_ROOT_PASSWORD}
- BRIVEN_MINIO_BUCKET: ${BRIVEN_MINIO_BUCKET:-briven}
- BRIVEN_MINIO_REGION: ${BRIVEN_MINIO_REGION:-us-east-1}
- healthcheck:
- # /info is documented to never 500 (apps/api/Dockerfile). bun ships in
- # the api image and has a built-in fetch.
- test: ['CMD-SHELL', "bun -e \"fetch('http://localhost:3001/info').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
- interval: 15s
- timeout: 5s
- retries: 5
- start_period: 40s
- networks:
- - briven
- - dokploy-network
- labels:
- - 'briven_logs=true'
- - 'traefik.enable=true'
- - 'traefik.docker.network=dokploy-network'
- - 'traefik.http.routers.briven-api.rule=Host(`api.${BRIVEN_DOMAIN}`)'
- - 'traefik.http.routers.briven-api.entrypoints=websecure'
- - 'traefik.http.routers.briven-api.tls.certresolver=letsencrypt'
- - 'traefik.http.routers.briven-api.service=briven-api'
- - 'traefik.http.services.briven-api.loadbalancer.server.port=3001'
- runtime:
- build:
- context: ../..
- dockerfile: apps/runtime/Dockerfile
- container_name: briven-runtime
- restart: unless-stopped
- logging: *briven-logging
- depends_on:
- api:
- condition: service_started
- doltgres:
- condition: service_healthy
- environment:
- BRIVEN_ENV: production
- BRIVEN_RUNTIME_PORT: '3003'
- BRIVEN_RUNTIME_SHARED_SECRET: ${BRIVEN_RUNTIME_SHARED_SECRET}
- BRIVEN_RUNTIME_EXECUTOR: deno
- BRIVEN_RUNTIME_BUNDLE_DIR: /var/lib/briven/bundles
- BRIVEN_API_INTERNAL_URL: http://api:3001
- # Data plane — DoltGres (the old BRIVEN_URL mysql:// was wrong, removed).
- BRIVEN_DATA_PLANE_URL: postgres://postgres:${BRIVEN_DOLTGRES_PASSWORD}@doltgres:5432/postgres?sslmode=disable
- volumes:
- - runtime_bundles:/var/lib/briven/bundles
- healthcheck:
- # Any HTTP response = process is up (port serving).
- test: ['CMD-SHELL', "bun -e \"fetch('http://localhost:3003/').then(()=>process.exit(0)).catch(()=>process.exit(1))\""]
- interval: 15s
- timeout: 5s
- retries: 5
- start_period: 40s
- networks:
- - briven
- labels:
- - 'briven_logs=true'
- realtime:
- build:
- context: ../..
- dockerfile: apps/realtime/Dockerfile
- container_name: briven-realtime
- restart: unless-stopped
- logging: *briven-logging
- depends_on:
- doltgres:
- condition: service_healthy
- environment:
- BRIVEN_ENV: production
- BRIVEN_REALTIME_PORT: '3004'
- BRIVEN_API_INTERNAL_URL: http://api:3001
- BRIVEN_RUNTIME_SHARED_SECRET: ${BRIVEN_RUNTIME_SHARED_SECRET}
- # Data plane — DoltGres. Realtime polls DOLT_HASHOF('HEAD') per project
- # (no LISTEN/NOTIFY on DoltGres). The old BRIVEN_URL mysql:// was wrong.
- BRIVEN_DATA_PLANE_URL: postgres://postgres:${BRIVEN_DOLTGRES_PASSWORD}@doltgres:5432/postgres?sslmode=disable
- BRIVEN_REALTIME_POLL_MS: '500'
- healthcheck:
- test: ['CMD-SHELL', "bun -e \"fetch('http://localhost:3004/').then(()=>process.exit(0)).catch(()=>process.exit(1))\""]
- interval: 15s
- timeout: 5s
- retries: 5
- start_period: 40s
- networks:
- - briven
- - dokploy-network
- labels:
- - 'briven_logs=true'
- - 'traefik.enable=true'
- - 'traefik.docker.network=dokploy-network'
- - 'traefik.http.routers.briven-realtime.rule=Host(`realtime.${BRIVEN_DOMAIN}`)'
- - 'traefik.http.routers.briven-realtime.entrypoints=websecure'
- - 'traefik.http.routers.briven-realtime.tls.certresolver=letsencrypt'
- - 'traefik.http.services.briven-realtime.loadbalancer.server.port=3004'
- web:
- build:
- context: ../..
- dockerfile: apps/web/Dockerfile
- container_name: briven-web
- restart: unless-stopped
- logging: *briven-logging
- depends_on:
- api:
- condition: service_started
- environment:
- BRIVEN_API_ORIGIN: https://api.${BRIVEN_DOMAIN}
- BRIVEN_WEB_ORIGIN: https://${BRIVEN_DOMAIN}
- NEXT_PUBLIC_BRIVEN_API_ORIGIN: https://api.${BRIVEN_DOMAIN}
- NEXT_PUBLIC_BRIVEN_HAS_GOOGLE_OAUTH: ${BRIVEN_GOOGLE_CLIENT_ID:+true}
- NEXT_PUBLIC_BRIVEN_HAS_GITHUB_OAUTH: ${BRIVEN_GITHUB_CLIENT_ID:+true}
- NEXT_PUBLIC_BRIVEN_HAS_KONNOS_OAUTH: ${BRIVEN_KONNOS_CLIENT_ID:+true}
- NEXT_PUBLIC_BRIVEN_HAS_DISCORD_OAUTH: ${BRIVEN_DISCORD_CLIENT_ID:+true}
- healthcheck:
- # web runs `next start` on node — use node's built-in fetch.
- test: ['CMD-SHELL', "node -e \"fetch('http://localhost:3000/').then(()=>process.exit(0)).catch(()=>process.exit(1))\""]
- interval: 15s
- timeout: 5s
- retries: 5
- start_period: 40s
- networks:
- - briven
- - dokploy-network
- labels:
- - 'briven_logs=true'
- - 'traefik.enable=true'
- - 'traefik.docker.network=dokploy-network'
- - 'traefik.http.routers.briven-web.rule=Host(`${BRIVEN_DOMAIN}`) || Host(`app.${BRIVEN_DOMAIN}`)'
- - 'traefik.http.routers.briven-web.entrypoints=websecure'
- - 'traefik.http.routers.briven-web.tls.certresolver=letsencrypt'
- - 'traefik.http.services.briven-web.loadbalancer.server.port=3000'
- docs:
- build:
- context: ../..
- dockerfile: apps/docs/Dockerfile
- container_name: briven-docs
- restart: unless-stopped
- logging: *briven-logging
- depends_on:
- api:
- condition: service_started
- environment:
- # Used by /status + /api/status/incidents.xml to read live incidents.
- BRIVEN_API_ORIGIN: https://api.${BRIVEN_DOMAIN}
- healthcheck:
- test: ['CMD-SHELL', "node -e \"fetch('http://localhost:3002/').then(()=>process.exit(0)).catch(()=>process.exit(1))\""]
- interval: 15s
- timeout: 5s
- retries: 5
- start_period: 40s
- networks:
- - briven
- - dokploy-network
- labels:
- - 'briven_logs=true'
- - 'traefik.enable=true'
- - 'traefik.docker.network=dokploy-network'
- - 'traefik.http.routers.briven-docs.rule=Host(`docs.${BRIVEN_DOMAIN}`)'
- - 'traefik.http.routers.briven-docs.entrypoints=websecure'
- - 'traefik.http.routers.briven-docs.tls.certresolver=letsencrypt'
- - 'traefik.http.services.briven-docs.loadbalancer.server.port=3002'
- # status.${BRIVEN_DOMAIN} — same docs container; bare `/` rewrites to
- # /status. Other paths pass through (so /api/status/incidents.xml works).
- - 'traefik.http.routers.briven-status.rule=Host(`status.${BRIVEN_DOMAIN}`)'
- - 'traefik.http.routers.briven-status.entrypoints=websecure'
- - 'traefik.http.routers.briven-status.tls.certresolver=letsencrypt'
- - 'traefik.http.routers.briven-status.service=briven-docs'
- - 'traefik.http.routers.briven-status.middlewares=briven-status-rewrite'
- - 'traefik.http.middlewares.briven-status-rewrite.replacepathregex.regex=^/$$'
- - 'traefik.http.middlewares.briven-status-rewrite.replacepathregex.replacement=/status'
- volumes:
- postgres_data:
- doltgres_data:
- doltgres_backups:
- redis_data:
- minio_data:
- runtime_bundles:
- networks:
- briven:
- driver: bridge
- name: briven
- # Dokploy's ingress network — Traefik watches this for routing + TLS.
- # Routed services (api, realtime, web, docs, s3) attach to it in addition
- # to the internal `briven` network; DBs/redis/runtime stay internal-only.
- dokploy-network:
- external: true
|