diff --git a/.env.example b/.env.example index 8f1898d6a4..0938a650d8 100644 --- a/.env.example +++ b/.env.example @@ -63,10 +63,18 @@ DATABASE_URL='postgresql://postgres:postgres@localhost:5432/formbricks?schema=pu # Set explicitly to avoid confusion; override as needed when using docker-compose.dev.yml. HUB_API_KEY=dev-api-key HUB_API_URL=http://localhost:8080 -HUB_DATABASE_URL=postgresql://postgres:postgres@postgres:5432/postgres?sslmode=disable +HUB_DATABASE_URL=postgresql://postgres:postgres@postgres:5432/hub?sslmode=disable # Hub image tag used by docker-compose.dev.yml (hub + hub-migrate). Leave unset to use the # pinned default in the compose file; override here when testing a specific Hub release. -# HUB_IMAGE_TAG=0.2.0 +# HUB_IMAGE_TAG=0.3.0 + +# Hub embeddings are optional. Set a provider and model to enable semantic search embeddings in +# the Hub API and hub-worker. For provider-specific settings, see: +# https://hub.formbricks.com/reference/environment-variables/#embeddings +# Example with Google AI Studio: +# EMBEDDING_PROVIDER=google +# EMBEDDING_MODEL=gemini-embedding-001 +# EMBEDDING_PROVIDER_API_KEY= ########################### # CUBE ANALYTICS (XM V5) # diff --git a/charts/formbricks/README.md b/charts/formbricks/README.md index 92177fc161..03857b23d3 100644 --- a/charts/formbricks/README.md +++ b/charts/formbricks/README.md @@ -214,7 +214,7 @@ Autoscaling is opt-in for Hub API, Hub worker, and the embeddings runtime. If yo | hub.image.digest | string | `"sha256:14db7b3d285b6e9165b55693f9b83d08beff840a255fd77dd12882ee0a62f5cb"` | When set, takes precedence over tag (immutable pin). | | hub.image.pullPolicy | string | `"IfNotPresent"` | | | hub.image.repository | string | `"ghcr.io/formbricks/hub"` | | -| hub.image.tag | string | `"0.2.0"` | Fallback when digest is empty. | +| hub.image.tag | string | `"0.3.0"` | Fallback when digest is empty. | | hub.migration.activeDeadlineSeconds | int | `900` | | | hub.migration.backoffLimit | int | `3` | | | hub.migration.ttlSecondsAfterFinished | int | `300` | | diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 3f89cfeeef..c90d40ba7d 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -77,6 +77,21 @@ services: - /bin/sh - /usr/local/bin/rustfs-init.sh + # Create Hub's dedicated dev database before migrations run. Idempotent; runs on every compose up. + hub-db-create: + image: pgvector/pgvector:pg18 + restart: "no" + entrypoint: ["sh", "-c"] + command: + [ + 'if [ "$$(psql "$$POSTGRES_DATABASE_URL" -tAc "SELECT 1 FROM pg_database WHERE datname = ''hub''")" != "1" ]; then psql "$$POSTGRES_DATABASE_URL" -v ON_ERROR_STOP=1 -c "CREATE DATABASE hub"; fi', + ] + environment: + POSTGRES_DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres?sslmode=disable + depends_on: + postgres: + condition: service_healthy + # Run Hub DB migrations (goose + river) before the API starts. Idempotent; runs on every compose up. # Hub image pinned via HUB_IMAGE_TAG so docker does not silently reuse a stale :latest cache. # Keep hub, hub-migrate, and any future hub-worker on the same tag — they share one image and @@ -90,12 +105,12 @@ services: 'if [ -x /usr/local/bin/goose ] && [ -x /usr/local/bin/river ]; then /usr/local/bin/goose -dir /app/migrations postgres "$$DATABASE_URL" up && /usr/local/bin/river migrate-up --database-url "$$DATABASE_URL"; else echo ''Migration tools (goose/river) not in image.''; exit 1; fi', ] environment: - DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres?sslmode=disable + DATABASE_URL: ${HUB_DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/hub?sslmode=disable} depends_on: - postgres: - condition: service_healthy + hub-db-create: + condition: service_completed_successfully - # Formbricks Hub API (ghcr.io/formbricks/hub). Shares the same Postgres database as Formbricks by default. + # Formbricks Hub API (ghcr.io/formbricks/hub). Uses a dedicated local Hub database by default. hub: image: ghcr.io/formbricks/hub:${HUB_IMAGE_TAG:-0.3.0} depends_on: @@ -103,16 +118,41 @@ services: condition: service_completed_successfully ports: - "8080:8080" - environment: + environment: &hub-runtime-environment API_KEY: ${HUB_API_KEY:-dev-api-key} - DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres?sslmode=disable + DATABASE_URL: ${HUB_DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/hub?sslmode=disable} # Explicit Postgres env so migrations and any libpq fallback use the service host, not localhost PGHOST: postgres PGPORT: "5432" PGUSER: postgres PGPASSWORD: postgres - PGDATABASE: postgres + PGDATABASE: hub PGSSLMODE: disable + # Hub embeddings are disabled unless EMBEDDING_PROVIDER and EMBEDDING_MODEL are set. + EMBEDDING_PROVIDER: ${EMBEDDING_PROVIDER:-} + EMBEDDING_MODEL: ${EMBEDDING_MODEL:-} + EMBEDDING_PROVIDER_API_KEY: ${EMBEDDING_PROVIDER_API_KEY:-} + EMBEDDING_BASE_URL: ${EMBEDDING_BASE_URL:-} + EMBEDDING_MAX_CONCURRENT: ${EMBEDDING_MAX_CONCURRENT:-5} + EMBEDDING_MAX_ATTEMPTS: ${EMBEDDING_MAX_ATTEMPTS:-3} + EMBEDDING_NORMALIZE: ${EMBEDDING_NORMALIZE:-false} + EMBEDDING_GOOGLE_CLOUD_PROJECT: ${EMBEDDING_GOOGLE_CLOUD_PROJECT:-} + EMBEDDING_GOOGLE_CLOUD_LOCATION: ${EMBEDDING_GOOGLE_CLOUD_LOCATION:-} + GOOGLE_APPLICATION_CREDENTIALS: ${GOOGLE_APPLICATION_CREDENTIALS:-} + + # Hub worker processes async jobs enqueued by the API, including embeddings. + hub-worker: + image: ghcr.io/formbricks/hub:${HUB_IMAGE_TAG:-0.3.0} + depends_on: + hub-migrate: + condition: service_completed_successfully + postgres: + condition: service_healthy + entrypoint: ["/app/hub-worker"] + healthcheck: + disable: true + environment: + <<: *hub-runtime-environment cube: profiles: ["xm"] diff --git a/docker/README.md b/docker/README.md index 6868d67227..15c36e5e81 100644 --- a/docker/README.md +++ b/docker/README.md @@ -33,8 +33,8 @@ That's it! After running the command and providing the required information, vis The stack includes the [Formbricks Hub](https://github.com/formbricks/hub) API (`ghcr.io/formbricks/hub`) and can also run a bundled Cube.js service for XM Suite v5 analytics. Hub and Cube share the same database as Formbricks by default, and Cube is enabled through the optional Docker Compose `xm` profile. - **Migrations**: A `hub-migrate` service runs Hub's database migrations (goose + river) before the Hub API starts. It runs on every `docker compose up` and is idempotent. -- **Production** (`docker/docker-compose.yml`): Set `HUB_API_KEY` (required). `HUB_API_URL` defaults to `http://hub:8080` so the Formbricks app can reach Hub inside the compose network. To enable XM Suite v5 analytics, set `COMPOSE_PROFILES=xm` and `CUBEJS_API_SECRET`; `CUBEJS_API_URL` defaults to `http://cube:4000`. Cube JWT issuer/audience default to `formbricks-web` and `formbricks-cube`, and the bundled Cube service exposes only `meta,data` API scopes. Override `HUB_DATABASE_URL` and `CUBEJS_DB_*` only if Hub or Cube should use a separate database. The Hub image tracks `:latest` by default so `formbricks.sh update` advances Hub in lockstep with the app. `hub` and `hub-migrate` always resolve to the same image. To pin to an immutable reference, set `HUB_IMAGE_REF` in `docker/.env` to either a tag (e.g. `:0.2.0`) or a digest (e.g. `@sha256:14db7b3d...`). -- **Development** (`docker-compose.dev.yml`): Hub uses the same local Postgres database and `HUB_API_KEY` defaults to `dev-api-key`. Cube is behind the `xm` profile, `CUBEJS_API_URL` defaults to `http://localhost:4000`, and `pnpm dev:setup` generates `CUBEJS_API_SECRET` in the repo root `.env`. The Hub image is pinned to a semver tag (`hub` and `hub-migrate` share the same value); override `HUB_IMAGE_TAG` in the repo root `.env` to test a specific Hub release. +- **Production** (`docker/docker-compose.yml`): Set `HUB_API_KEY` (required). `HUB_API_URL` defaults to `http://hub:8080` so the Formbricks app can reach Hub inside the compose network. To enable XM Suite v5 analytics, set `COMPOSE_PROFILES=xm` and `CUBEJS_API_SECRET`; `CUBEJS_API_URL` defaults to `http://cube:4000`. Cube JWT issuer/audience default to `formbricks-web` and `formbricks-cube`, and the bundled Cube service exposes only `meta,data` API scopes. Override `HUB_DATABASE_URL` and `CUBEJS_DB_*` only if Hub or Cube should use a separate database. The Hub image tracks `:latest` by default so `formbricks.sh update` advances Hub in lockstep with the app. `hub` and `hub-migrate` always resolve to the same image. To pin to an immutable reference, set `HUB_IMAGE_REF` in `docker/.env` to either a tag (e.g. `:0.3.0`) or a digest (e.g. `@sha256:14db7b3d...`). +- **Development** (`docker-compose.dev.yml`): Hub uses a dedicated local `hub` database and `HUB_API_KEY` defaults to `dev-api-key`. The dev stack starts `hub` plus `hub-worker`; set `EMBEDDING_PROVIDER`, `EMBEDDING_MODEL`, and any provider credentials in the repo root `.env` to enable Hub embeddings locally. See the [Hub embeddings environment reference](https://hub.formbricks.com/reference/environment-variables/#embeddings) for provider-specific values. Cube is behind the `xm` profile, `CUBEJS_API_URL` defaults to `http://localhost:4000`, and `pnpm dev:setup` generates `CUBEJS_API_SECRET` in the repo root `.env`. The Hub image is pinned to a semver tag (`hub`, `hub-worker`, and `hub-migrate` share the same value); override `HUB_IMAGE_TAG` in the repo root `.env` to test a specific Hub release. In development, Hub is exposed locally on port **8080**. When the `xm` profile is enabled, Cube is exposed on **4000** (with the Cube playground on **4001**). In production Docker Compose, Hub stays internal to the compose network at `http://hub:8080`; Cube also stays internal at `http://cube:4000` when enabled.