compose.yml 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. # briven — canonical self-host compose (build-from-source).
  2. #
  3. # Post ADR-0002 (docs/ADR/0002-converge-on-doltgres.md): the platform
  4. # runs on TWO database engines, on purpose:
  5. #
  6. # - control plane = DoltGres database briven_control (product line: all Doltgres).
  7. # sign-in, orgs, projects, billing, secrets, auth. drizzle migrations
  8. # run at api boot. NEVER points at DoltGres.
  9. # - data plane = DoltGres (dolthub/doltgresql), env BRIVEN_DATA_PLANE_URL.
  10. # Postgres-wire, accessed with the `pg` driver, one DATABASE per
  11. # customer project. Realtime polls DOLT_HASHOF('HEAD') (no LISTEN/NOTIFY).
  12. #
  13. # This file supersedes the two earlier conflicting composes:
  14. # - the old Dolt-MySQL build (dolthub/dolt-sql-server + BRIVEN_URL mysql) —
  15. # wrong engine, broke the api. REMOVED.
  16. # - the all-pgvector build (data plane as a 2nd Postgres DB) — wrong data
  17. # plane. REPLACED by the real DoltGres service below.
  18. #
  19. # Dokploy clones the repo and runs `docker compose build` against the local
  20. # Dockerfiles — no external registry, no GHCR, no docker.sock. Per
  21. # docs/DOCKER.md §7 / infra/CLAUDE.md: every long-running service caps its
  22. # log volume via the *briven-logging anchor; no watchtower, no docker_sd,
  23. # no registry polling on the host.
  24. #
  25. # Single-machine layout, ~25 concurrent customer projects. Past that, split
  26. # the control plane onto one host and the data plane (doltgres + minio) onto
  27. # another.
  28. #
  29. # Required env (drop a `.env` next to this file — see .env.example):
  30. #
  31. # BRIVEN_DOMAIN e.g. briven.example.com
  32. # BRIVEN_BETTER_AUTH_SECRET openssl rand -hex 32
  33. # BRIVEN_AUDIT_IP_PEPPER openssl rand -hex 32
  34. # BRIVEN_ENCRYPTION_KEY openssl rand -hex 32
  35. # BRIVEN_RUNTIME_SHARED_SECRET openssl rand -hex 32
  36. # BRIVEN_POSTGRES_PASSWORD control-plane Postgres superuser password
  37. # BRIVEN_DOLTGRES_PASSWORD data-plane DoltGres superuser password
  38. # BRIVEN_MINIO_ROOT_PASSWORD MinIO root / S3 secret key
  39. # (optional) BRIVEN_MITTERA_*, BRIVEN_*_CLIENT_ID/SECRET, BRIVEN_POLAR_*,
  40. # BRIVEN_OLLAMA_*, BRIVEN_MINIO_BUCKET/REGION, BRIVEN_OPEN_SIGNUPS
  41. #
  42. # After first boot:
  43. # 1. Create the first user via the magic-link flow on https://${BRIVEN_DOMAIN}
  44. # 2. Promote to admin in the control plane:
  45. # docker exec -it briven-postgres psql -U postgres -d briven_control \
  46. # -c "UPDATE users SET is_admin = true WHERE id = '...';"
  47. # 3. Create your first project via the dashboard (provisions a DoltGres DB).
  48. # Explicit project name so compose resources are deterministically `briven_*`
  49. # (containers already pin container_name: briven-*). Without this, the project
  50. # name defaults to the parent directory ("dokploy"), which would create
  51. # `dokploy_*` volumes — confusingly close to the Dokploy platform's own naming
  52. # and a trap for host-maintenance tooling. Build AND up must share this name.
  53. name: briven
  54. x-logging: &briven-logging
  55. driver: json-file
  56. options:
  57. max-size: '10m'
  58. max-file: '3'
  59. services:
  60. # ─── control plane ────────────────────────────────────────────────────
  61. postgres:
  62. image: pgvector/pgvector:pg17
  63. container_name: briven-postgres
  64. restart: unless-stopped
  65. logging: *briven-logging
  66. environment:
  67. POSTGRES_PASSWORD: ${BRIVEN_POSTGRES_PASSWORD}
  68. POSTGRES_DB: briven_control
  69. volumes:
  70. - postgres_data:/var/lib/postgresql/data
  71. # Control-plane init only: enables pgvector + pg_trgm on briven_control.
  72. # No data-plane DB is created here — the data plane is the doltgres
  73. # service, with a database per project (see ADR-0002).
  74. - ./postgres-init:/docker-entrypoint-initdb.d:ro
  75. healthcheck:
  76. test: ['CMD-SHELL', 'pg_isready -U postgres -d briven_control']
  77. interval: 10s
  78. timeout: 5s
  79. retries: 5
  80. start_period: 20s
  81. networks:
  82. - briven
  83. labels:
  84. - 'briven_logs=true'
  85. # ─── data plane ───────────────────────────────────────────────────────
  86. # DoltGres = Postgres-wire, git-for-data. Each customer project is its own
  87. # DATABASE here, created by the api over the `pg` driver. The default
  88. # superuser/database is `postgres`/`postgres` (DOLTGRES_* envs override the
  89. # password).
  90. #
  91. # IMAGE IS PINNED BY DIGEST, ON PURPOSE (2026-07-07 maintenance window):
  92. # `:latest` let a deploy silently swap the database engine under live data
  93. # (prime suspect in the 2026-07-07 auth.db outage). To upgrade the engine,
  94. # change the digest here deliberately, in its own reviewed deploy.
  95. #
  96. # DATA DIR IS /var/lib/doltgres — NO "ql". The mount below once pointed at
  97. # /var/lib/doltgresql (typo), so all real data lived in an anonymous volume
  98. # that a container recreation would orphan. Fixed 2026-07-07 (data migrated
  99. # into the named volume during the maintenance window). Never change this
  100. # path without checking `config.yaml` inside the volume.
  101. doltgres:
  102. image: dolthub/doltgresql@sha256:0483137d0309598d3b0c111dff85d565077bd91cb0524ce00bb832929d5d5ddc
  103. container_name: briven-doltgres
  104. restart: unless-stopped
  105. logging: *briven-logging
  106. environment:
  107. DOLTGRES_USER: postgres
  108. DOLTGRES_PASSWORD: ${BRIVEN_DOLTGRES_PASSWORD}
  109. volumes:
  110. - doltgres_data:/var/lib/doltgres
  111. # Dolt-native backups land here (written by the server itself); the
  112. # dolt-backup service triggers them. See that service for details.
  113. - doltgres_backups:/backups
  114. healthcheck:
  115. # pg_isready ships in the doltgresql image and needs no password.
  116. test: ['CMD-SHELL', 'pg_isready -h 127.0.0.1 -p 5432 -U postgres']
  117. interval: 10s
  118. timeout: 5s
  119. retries: 5
  120. start_period: 30s
  121. networks:
  122. - briven
  123. labels:
  124. - 'briven_logs=true'
  125. # ─── data-plane backup ──────────────────────────────────────────────────
  126. # REAL DoltGres backup (replaces the old placeholder sleep loop).
  127. #
  128. # Why NOT pg_dump: tested 2026-06-26 against dolthub/doltgresql:latest
  129. # (v0.56.6) — `pg_dump` aborts immediately with
  130. # "ERROR: SET TRANSACTION is not yet supported"
  131. # because pg_dump opens a REPEATABLE READ READ ONLY snapshot transaction
  132. # that DoltGres does not implement. So pg_dump CANNOT back up the data
  133. # plane. (The control plane is real Postgres and is dumped separately by
  134. # the host timers in infra/backups/.)
  135. #
  136. # What works (verified same day): Dolt's own backup, invoked over the
  137. # Postgres wire with `SELECT dolt_backup('sync-url', '<file-url>')`. It
  138. # writes a full, version-history-preserving Dolt archive (manifest +
  139. # .darc) — re-running it re-syncs in place, so one backup dir per database
  140. # already contains every commit (time-travel restore, not just a snapshot).
  141. #
  142. # This sidecar reuses the doltgresql image (it has `psql`), enumerates the
  143. # data-plane databases each run, and asks the doltgres SERVER to back each
  144. # one up into the shared `doltgres_backups` volume.
  145. #
  146. # OFF-SITE follow-up: mirroring the `doltgres_backups` volume to MinIO/B2/R2
  147. # is done today by the host systemd timers in infra/backups/ (mc-based, see
  148. # briven-backup.sh). Folding an `mc mirror /backups -> minio` step into this
  149. # service needs an image carrying both psql and mc; tracked as a follow-up.
  150. dolt-backup:
  151. # Pinned to the SAME digest as the doltgres service (2026-07-07 window) —
  152. # the sidecar's psql must always match the server's engine version.
  153. image: dolthub/doltgresql@sha256:0483137d0309598d3b0c111dff85d565077bd91cb0524ce00bb832929d5d5ddc
  154. container_name: briven-dolt-backup
  155. restart: unless-stopped
  156. logging: *briven-logging
  157. depends_on:
  158. doltgres:
  159. condition: service_healthy
  160. environment:
  161. PGHOST: doltgres
  162. PGPORT: '5432'
  163. PGUSER: postgres
  164. PGPASSWORD: ${BRIVEN_DOLTGRES_PASSWORD}
  165. BRIVEN_BACKUP_INTERVAL_SECONDS: ${BRIVEN_BACKUP_INTERVAL_SECONDS:-86400}
  166. volumes:
  167. - doltgres_backups:/backups
  168. # Read-only view of the server's data dir, ONLY so auth.db (the engine's
  169. # users/grants file — corrupted once on 2026-07-07, nothing backed it up)
  170. # can be snapshotted alongside the dolt backups below.
  171. - doltgres_data:/doltgres-data:ro
  172. entrypoint: ['/bin/sh', '-c']
  173. command:
  174. - |
  175. set -eu
  176. echo "dolt-backup: starting (interval=${BRIVEN_BACKUP_INTERVAL_SECONDS:-86400}s)"
  177. while true; do
  178. ts="$$(date -u +%Y-%m-%dT%H:%M:%SZ)"
  179. echo "[dolt-backup $$ts] enumerating data-plane databases"
  180. # All non-template databases on the doltgres server (one per project,
  181. # plus the default `postgres`). -tA = tuples only, unaligned.
  182. dbs="$$(psql -tA -d postgres -c \
  183. "SELECT datname FROM pg_database WHERE datname NOT IN ('template0','template1')")"
  184. for db in $$dbs; do
  185. echo "[dolt-backup $$ts] backing up $$db -> file:///backups/$$db"
  186. if psql -d "$$db" -c \
  187. "SELECT dolt_backup('sync-url', 'file:///backups/$$db');" >/dev/null; then
  188. echo "[dolt-backup $$ts] ok $$db"
  189. else
  190. echo "[dolt-backup $$ts] WARN backup failed for $$db"
  191. fi
  192. done
  193. # auth.db snapshot — tiny file, changes only on role/grant edits.
  194. # Keep the newest 14 copies (2 weeks at the daily default interval).
  195. if [ -f /doltgres-data/auth.db ]; then
  196. mkdir -p /backups/auth-db
  197. if cp /doltgres-data/auth.db "/backups/auth-db/auth.db.$$ts"; then
  198. echo "[dolt-backup $$ts] ok auth.db snapshot"
  199. ls -1t /backups/auth-db | tail -n +15 | while read -r old; do
  200. rm -f "/backups/auth-db/$$old"
  201. done
  202. else
  203. echo "[dolt-backup $$ts] WARN auth.db snapshot failed"
  204. fi
  205. else
  206. echo "[dolt-backup $$ts] WARN auth.db not found in data dir"
  207. fi
  208. echo "[dolt-backup $$ts] run complete; sleeping"
  209. sleep "$${BRIVEN_BACKUP_INTERVAL_SECONDS:-86400}"
  210. done
  211. networks:
  212. - briven
  213. labels:
  214. - 'briven_logs=true'
  215. # ─── shared infra ─────────────────────────────────────────────────────
  216. redis:
  217. image: redis:7.4-alpine
  218. container_name: briven-redis
  219. restart: unless-stopped
  220. logging: *briven-logging
  221. command: redis-server --appendonly yes
  222. volumes:
  223. - redis_data:/data
  224. healthcheck:
  225. test: ['CMD-SHELL', 'redis-cli ping | grep -q PONG']
  226. interval: 10s
  227. timeout: 5s
  228. retries: 5
  229. start_period: 10s
  230. networks:
  231. - briven
  232. labels:
  233. - 'briven_logs=true'
  234. minio:
  235. image: minio/minio:latest
  236. container_name: briven-minio
  237. restart: unless-stopped
  238. logging: *briven-logging
  239. command: server /data --console-address ':9001'
  240. environment:
  241. MINIO_ROOT_USER: briven
  242. MINIO_ROOT_PASSWORD: ${BRIVEN_MINIO_ROOT_PASSWORD}
  243. volumes:
  244. - minio_data:/data
  245. healthcheck:
  246. test: ['CMD-SHELL', 'curl -fsS http://localhost:9000/minio/health/live || exit 1']
  247. interval: 15s
  248. timeout: 5s
  249. retries: 5
  250. start_period: 20s
  251. networks:
  252. - briven
  253. - dokploy-network
  254. labels:
  255. - 'briven_logs=true'
  256. - 'traefik.enable=true'
  257. - 'traefik.docker.network=dokploy-network'
  258. # Public S3 endpoint — browsers PUT/GET with sigv4-presigned URLs the
  259. # api mints. The api also reaches MinIO internally at http://minio:9000.
  260. - 'traefik.http.routers.briven-s3.rule=Host(`s3.${BRIVEN_DOMAIN}`)'
  261. - 'traefik.http.routers.briven-s3.entrypoints=websecure'
  262. - 'traefik.http.routers.briven-s3.tls.certresolver=letsencrypt'
  263. - 'traefik.http.routers.briven-s3.service=briven-s3'
  264. - 'traefik.http.services.briven-s3.loadbalancer.server.port=9000'
  265. # One-shot bucket creator. `mc mb --ignore-existing` is idempotent, so this
  266. # runs every deploy and no-ops after the first. restart: 'no' = one-shot, so
  267. # per infra/CLAUDE.md it does NOT need the logging cap.
  268. minio-init:
  269. image: minio/mc:latest
  270. container_name: briven-minio-init
  271. depends_on:
  272. minio:
  273. condition: service_healthy
  274. entrypoint: >
  275. /bin/sh -c "
  276. until /usr/bin/mc alias set minio http://minio:9000 briven ${BRIVEN_MINIO_ROOT_PASSWORD} >/dev/null 2>&1; do
  277. echo 'waiting for minio...'; sleep 2;
  278. done;
  279. /usr/bin/mc mb --ignore-existing minio/${BRIVEN_MINIO_BUCKET:-briven};
  280. echo 'minio bucket ready: ${BRIVEN_MINIO_BUCKET:-briven}';
  281. "
  282. restart: 'no'
  283. networks:
  284. - briven
  285. # ─── application services ─────────────────────────────────────────────
  286. api:
  287. build:
  288. context: ../..
  289. dockerfile: apps/api/Dockerfile
  290. container_name: briven-api
  291. restart: unless-stopped
  292. logging: *briven-logging
  293. depends_on:
  294. postgres:
  295. condition: service_healthy
  296. doltgres:
  297. condition: service_healthy
  298. redis:
  299. condition: service_healthy
  300. environment:
  301. BRIVEN_ENV: production
  302. BRIVEN_API_PORT: '3001'
  303. BRIVEN_API_ORIGIN: https://api.${BRIVEN_DOMAIN}
  304. BRIVEN_WEB_ORIGIN: https://${BRIVEN_DOMAIN}
  305. BRIVEN_TRUSTED_ORIGINS: https://${BRIVEN_DOMAIN},https://api.${BRIVEN_DOMAIN}
  306. # Control plane — stock Postgres, postgres.js/drizzle.
  307. BRIVEN_DATABASE_URL: postgres://postgres:${BRIVEN_DOLTGRES_PASSWORD}@doltgres:5432/briven_control?sslmode=disable
  308. # Data plane — DoltGres, `pg` driver, database-per-project. The api
  309. # connects to the default `postgres` database and CREATEs per-project
  310. # databases on this server.
  311. BRIVEN_DATA_PLANE_URL: postgres://postgres:${BRIVEN_DOLTGRES_PASSWORD}@doltgres:5432/postgres?sslmode=disable
  312. BRIVEN_REDIS_URL: redis://redis:6379
  313. BRIVEN_RUNTIME_URL: http://runtime:3003
  314. # Without this the api falls back to localhost:3004 and can't reach
  315. # realtime — surfaces as realtime_stats_failed "Unable to connect".
  316. BRIVEN_REALTIME_URL: http://realtime:3004
  317. BRIVEN_RUNTIME_SHARED_SECRET: ${BRIVEN_RUNTIME_SHARED_SECRET}
  318. BRIVEN_BETTER_AUTH_SECRET: ${BRIVEN_BETTER_AUTH_SECRET}
  319. BRIVEN_AUDIT_IP_PEPPER: ${BRIVEN_AUDIT_IP_PEPPER}
  320. BRIVEN_ENCRYPTION_KEY: ${BRIVEN_ENCRYPTION_KEY}
  321. BRIVEN_MITTERA_API_URL: ${BRIVEN_MITTERA_API_URL:-}
  322. BRIVEN_MITTERA_API_KEY: ${BRIVEN_MITTERA_API_KEY:-}
  323. BRIVEN_MITTERA_WEBHOOK_SECRET: ${BRIVEN_MITTERA_WEBHOOK_SECRET:-}
  324. BRIVEN_GOOGLE_CLIENT_ID: ${BRIVEN_GOOGLE_CLIENT_ID:-}
  325. BRIVEN_GOOGLE_CLIENT_SECRET: ${BRIVEN_GOOGLE_CLIENT_SECRET:-}
  326. BRIVEN_GITHUB_CLIENT_ID: ${BRIVEN_GITHUB_CLIENT_ID:-}
  327. BRIVEN_GITHUB_CLIENT_SECRET: ${BRIVEN_GITHUB_CLIENT_SECRET:-}
  328. BRIVEN_KONNOS_CLIENT_ID: ${BRIVEN_KONNOS_CLIENT_ID:-}
  329. BRIVEN_KONNOS_CLIENT_SECRET: ${BRIVEN_KONNOS_CLIENT_SECRET:-}
  330. BRIVEN_KONNOS_ISSUER: ${BRIVEN_KONNOS_ISSUER:-https://code.konnos.org}
  331. BRIVEN_DISCORD_CLIENT_ID: ${BRIVEN_DISCORD_CLIENT_ID:-}
  332. BRIVEN_DISCORD_CLIENT_SECRET: ${BRIVEN_DISCORD_CLIENT_SECRET:-}
  333. BRIVEN_POLAR_API_BASE: ${BRIVEN_POLAR_API_BASE:-https://api.polar.sh}
  334. BRIVEN_POLAR_ACCESS_TOKEN: ${BRIVEN_POLAR_ACCESS_TOKEN:-}
  335. BRIVEN_POLAR_WEBHOOK_SECRET: ${BRIVEN_POLAR_WEBHOOK_SECRET:-}
  336. BRIVEN_POLAR_PRO_PRODUCT_ID: ${BRIVEN_POLAR_PRO_PRODUCT_ID:-}
  337. BRIVEN_POLAR_TEAM_PRODUCT_ID: ${BRIVEN_POLAR_TEAM_PRODUCT_ID:-}
  338. BRIVEN_DOMAIN: ${BRIVEN_DOMAIN}
  339. BRIVEN_OPEN_SIGNUPS: ${BRIVEN_OPEN_SIGNUPS:-false}
  340. BRIVEN_OLLAMA_URL: ${BRIVEN_OLLAMA_URL:-}
  341. BRIVEN_OLLAMA_API_KEY: ${BRIVEN_OLLAMA_API_KEY:-}
  342. BRIVEN_OLLAMA_MODEL: ${BRIVEN_OLLAMA_MODEL:-qwen2.5-coder:32b}
  343. BRIVEN_MINIO_ENDPOINT: http://minio:9000
  344. BRIVEN_MINIO_PUBLIC_ENDPOINT: https://s3.${BRIVEN_DOMAIN}
  345. BRIVEN_MINIO_ACCESS_KEY: briven
  346. BRIVEN_MINIO_SECRET_KEY: ${BRIVEN_MINIO_ROOT_PASSWORD}
  347. BRIVEN_MINIO_BUCKET: ${BRIVEN_MINIO_BUCKET:-briven}
  348. BRIVEN_MINIO_REGION: ${BRIVEN_MINIO_REGION:-us-east-1}
  349. healthcheck:
  350. # /info is documented to never 500 (apps/api/Dockerfile). bun ships in
  351. # the api image and has a built-in fetch.
  352. test: ['CMD-SHELL', "bun -e \"fetch('http://localhost:3001/info').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
  353. interval: 15s
  354. timeout: 5s
  355. retries: 5
  356. start_period: 40s
  357. networks:
  358. - briven
  359. - dokploy-network
  360. labels:
  361. - 'briven_logs=true'
  362. - 'traefik.enable=true'
  363. - 'traefik.docker.network=dokploy-network'
  364. - 'traefik.http.routers.briven-api.rule=Host(`api.${BRIVEN_DOMAIN}`)'
  365. - 'traefik.http.routers.briven-api.entrypoints=websecure'
  366. - 'traefik.http.routers.briven-api.tls.certresolver=letsencrypt'
  367. - 'traefik.http.routers.briven-api.service=briven-api'
  368. - 'traefik.http.services.briven-api.loadbalancer.server.port=3001'
  369. runtime:
  370. build:
  371. context: ../..
  372. dockerfile: apps/runtime/Dockerfile
  373. container_name: briven-runtime
  374. restart: unless-stopped
  375. logging: *briven-logging
  376. depends_on:
  377. api:
  378. condition: service_started
  379. doltgres:
  380. condition: service_healthy
  381. environment:
  382. BRIVEN_ENV: production
  383. BRIVEN_RUNTIME_PORT: '3003'
  384. BRIVEN_RUNTIME_SHARED_SECRET: ${BRIVEN_RUNTIME_SHARED_SECRET}
  385. BRIVEN_RUNTIME_EXECUTOR: deno
  386. BRIVEN_RUNTIME_BUNDLE_DIR: /var/lib/briven/bundles
  387. BRIVEN_API_INTERNAL_URL: http://api:3001
  388. # Data plane — DoltGres (the old BRIVEN_URL mysql:// was wrong, removed).
  389. BRIVEN_DATA_PLANE_URL: postgres://postgres:${BRIVEN_DOLTGRES_PASSWORD}@doltgres:5432/postgres?sslmode=disable
  390. volumes:
  391. - runtime_bundles:/var/lib/briven/bundles
  392. healthcheck:
  393. # Any HTTP response = process is up (port serving).
  394. test: ['CMD-SHELL', "bun -e \"fetch('http://localhost:3003/').then(()=>process.exit(0)).catch(()=>process.exit(1))\""]
  395. interval: 15s
  396. timeout: 5s
  397. retries: 5
  398. start_period: 40s
  399. networks:
  400. - briven
  401. labels:
  402. - 'briven_logs=true'
  403. realtime:
  404. build:
  405. context: ../..
  406. dockerfile: apps/realtime/Dockerfile
  407. container_name: briven-realtime
  408. restart: unless-stopped
  409. logging: *briven-logging
  410. depends_on:
  411. doltgres:
  412. condition: service_healthy
  413. environment:
  414. BRIVEN_ENV: production
  415. BRIVEN_REALTIME_PORT: '3004'
  416. BRIVEN_API_INTERNAL_URL: http://api:3001
  417. BRIVEN_RUNTIME_SHARED_SECRET: ${BRIVEN_RUNTIME_SHARED_SECRET}
  418. # Data plane — DoltGres. Realtime polls DOLT_HASHOF('HEAD') per project
  419. # (no LISTEN/NOTIFY on DoltGres). The old BRIVEN_URL mysql:// was wrong.
  420. BRIVEN_DATA_PLANE_URL: postgres://postgres:${BRIVEN_DOLTGRES_PASSWORD}@doltgres:5432/postgres?sslmode=disable
  421. BRIVEN_REALTIME_POLL_MS: '500'
  422. healthcheck:
  423. test: ['CMD-SHELL', "bun -e \"fetch('http://localhost:3004/').then(()=>process.exit(0)).catch(()=>process.exit(1))\""]
  424. interval: 15s
  425. timeout: 5s
  426. retries: 5
  427. start_period: 40s
  428. networks:
  429. - briven
  430. - dokploy-network
  431. labels:
  432. - 'briven_logs=true'
  433. - 'traefik.enable=true'
  434. - 'traefik.docker.network=dokploy-network'
  435. - 'traefik.http.routers.briven-realtime.rule=Host(`realtime.${BRIVEN_DOMAIN}`)'
  436. - 'traefik.http.routers.briven-realtime.entrypoints=websecure'
  437. - 'traefik.http.routers.briven-realtime.tls.certresolver=letsencrypt'
  438. - 'traefik.http.services.briven-realtime.loadbalancer.server.port=3004'
  439. web:
  440. build:
  441. context: ../..
  442. dockerfile: apps/web/Dockerfile
  443. container_name: briven-web
  444. restart: unless-stopped
  445. logging: *briven-logging
  446. depends_on:
  447. api:
  448. condition: service_started
  449. environment:
  450. BRIVEN_API_ORIGIN: https://api.${BRIVEN_DOMAIN}
  451. BRIVEN_WEB_ORIGIN: https://${BRIVEN_DOMAIN}
  452. NEXT_PUBLIC_BRIVEN_API_ORIGIN: https://api.${BRIVEN_DOMAIN}
  453. NEXT_PUBLIC_BRIVEN_HAS_GOOGLE_OAUTH: ${BRIVEN_GOOGLE_CLIENT_ID:+true}
  454. NEXT_PUBLIC_BRIVEN_HAS_GITHUB_OAUTH: ${BRIVEN_GITHUB_CLIENT_ID:+true}
  455. NEXT_PUBLIC_BRIVEN_HAS_KONNOS_OAUTH: ${BRIVEN_KONNOS_CLIENT_ID:+true}
  456. NEXT_PUBLIC_BRIVEN_HAS_DISCORD_OAUTH: ${BRIVEN_DISCORD_CLIENT_ID:+true}
  457. healthcheck:
  458. # web runs `next start` on node — use node's built-in fetch.
  459. test: ['CMD-SHELL', "node -e \"fetch('http://localhost:3000/').then(()=>process.exit(0)).catch(()=>process.exit(1))\""]
  460. interval: 15s
  461. timeout: 5s
  462. retries: 5
  463. start_period: 40s
  464. networks:
  465. - briven
  466. - dokploy-network
  467. labels:
  468. - 'briven_logs=true'
  469. - 'traefik.enable=true'
  470. - 'traefik.docker.network=dokploy-network'
  471. - 'traefik.http.routers.briven-web.rule=Host(`${BRIVEN_DOMAIN}`) || Host(`app.${BRIVEN_DOMAIN}`)'
  472. - 'traefik.http.routers.briven-web.entrypoints=websecure'
  473. - 'traefik.http.routers.briven-web.tls.certresolver=letsencrypt'
  474. - 'traefik.http.services.briven-web.loadbalancer.server.port=3000'
  475. docs:
  476. build:
  477. context: ../..
  478. dockerfile: apps/docs/Dockerfile
  479. container_name: briven-docs
  480. restart: unless-stopped
  481. logging: *briven-logging
  482. depends_on:
  483. api:
  484. condition: service_started
  485. environment:
  486. # Used by /status + /api/status/incidents.xml to read live incidents.
  487. BRIVEN_API_ORIGIN: https://api.${BRIVEN_DOMAIN}
  488. healthcheck:
  489. test: ['CMD-SHELL', "node -e \"fetch('http://localhost:3002/').then(()=>process.exit(0)).catch(()=>process.exit(1))\""]
  490. interval: 15s
  491. timeout: 5s
  492. retries: 5
  493. start_period: 40s
  494. networks:
  495. - briven
  496. - dokploy-network
  497. labels:
  498. - 'briven_logs=true'
  499. - 'traefik.enable=true'
  500. - 'traefik.docker.network=dokploy-network'
  501. - 'traefik.http.routers.briven-docs.rule=Host(`docs.${BRIVEN_DOMAIN}`)'
  502. - 'traefik.http.routers.briven-docs.entrypoints=websecure'
  503. - 'traefik.http.routers.briven-docs.tls.certresolver=letsencrypt'
  504. - 'traefik.http.services.briven-docs.loadbalancer.server.port=3002'
  505. # status.${BRIVEN_DOMAIN} — same docs container; bare `/` rewrites to
  506. # /status. Other paths pass through (so /api/status/incidents.xml works).
  507. - 'traefik.http.routers.briven-status.rule=Host(`status.${BRIVEN_DOMAIN}`)'
  508. - 'traefik.http.routers.briven-status.entrypoints=websecure'
  509. - 'traefik.http.routers.briven-status.tls.certresolver=letsencrypt'
  510. - 'traefik.http.routers.briven-status.service=briven-docs'
  511. - 'traefik.http.routers.briven-status.middlewares=briven-status-rewrite'
  512. - 'traefik.http.middlewares.briven-status-rewrite.replacepathregex.regex=^/$$'
  513. - 'traefik.http.middlewares.briven-status-rewrite.replacepathregex.replacement=/status'
  514. volumes:
  515. postgres_data:
  516. doltgres_data:
  517. doltgres_backups:
  518. redis_data:
  519. minio_data:
  520. runtime_bundles:
  521. networks:
  522. briven:
  523. driver: bridge
  524. name: briven
  525. # Dokploy's ingress network — Traefik watches this for routing + TLS.
  526. # Routed services (api, realtime, web, docs, s3) attach to it in addition
  527. # to the internal `briven` network; DBs/redis/runtime stay internal-only.
  528. dokploy-network:
  529. external: true