Using Docker Compose as Backend for Local Development

Part 1 β€” SoVisu+ development

This section explains how to use the Docker Compose stack strictly as a backend while running SoVisu+ locally (Next.js dev server) for frontend development.


🎯 Goal

Run all shared services (Neo4j, message bus, Keycloak, APIs, databases) in Docker, but run SoVisu+ on your host machine. To make this work, you must:

  1. Map the necessary service ports from containers to the host.
  2. Use a dedicated profile (e.g. sovisuplus-db) to start only SoVisu+ backend services.
  3. Point your local SoVisu+ to these services via env vars and /etc/hosts.

🧱 Required Hostnames

Add these entries to your /etc/hosts (if not already done in the main guide):

127.0.0.1 sovisuplus.local
127.0.0.1 keycloak.local

SoVisu+ uses ORCID OAuth, which requires valid hostnames even for sandbox keys.


πŸ”“ Open the Right Ports in Compose

You’ll run SoVisu+ locally, so your host needs to reach the containers. Make sure the following port mappings are enabled.

1) SoVisu+ database (docker/sovisuplus/sovisuplus.yaml)

Uncomment the ports section so Postgres is reachable from your host:

sovisuplus.yaml
services:
  svp-db:
    image: postgres:16
    container_name: svp-db
    restart: always
    environment:
      POSTGRES_USER: ${SVP_DB_USER}
      POSTGRES_PASSWORD: ${SVP_DB_PASSWORD}
      POSTGRES_DB: ${SVP_DB_NAME}
    expose:
      - 5432
    ports:
      - 5432:5432
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    networks:
      - svp-network
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -d ${SVP_DB_NAME} -U ${SVP_DB_USER}']
      interval: 1s
      timeout: 5s
      retries: 10
    command: ["postgres","-c","max_connections=200","-c","superuser_reserved_connections=3"]
    profiles:
      - sovisuplus
      - sovisuplus-db

  sovisuplus:
    image: crisalidesr/sovisuplus:latest
    container_name: sovisuplus
    ports:
      - 3000:3000
      - 3001:3001
    environment:
      - DB_NAME=${SVP_DB_NAME}
      - DB_USER=${SVP_DB_USER}
      - DB_PASSWORD=${SVP_DB_PASSWORD}
      - DB_HOST=svp-db
      - DB_PORT=5432
      - NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
      - AMQP_HOST=crisalid-bus
      - AMQP_PORT=${CRISALID_BUS_AMQP_PORT}
      - AMQP_USER=${CRISALID_BUS_USER}
      - AMQP_PASSWORD=${CRISALID_BUS_PASSWORD}
      - AMQP_QUEUE_NAME=${SVP_AMQP_QUEUE_NAME}
      - AMQP_EXCHANGE_NAME=${SVP_AMQP_EXCHANGE_NAME}
      - GRAPHQL_ENDPOINT_ENABLED=${GRAPHQL_ENDPOINT_ENABLED}
      - GRAPHQL_ENDPOINT_URL=http://apollo:${APOLLO_API_PORT}/graphql
      - GRAPHQL_API_KEY_ENABLED=${GRAPHQL_API_KEY_ENABLED}
      - KEYCLOAK_CLIENT_ID=sovisuplus
      - KEYCLOAK_CLIENT_SECRET=${SOVISUPLUS_KEYCLOAK_CLIENT_SECRET}
      - KEYCLOAK_ADDR=${KEYCLOAK_SCHEME}://${KEYCLOAK_HOST}:${KEYCLOAK_PORT}
      - KEYCLOAK_REALM=${KEYCLOAK_REALM}
      - APP_URL=${SOVISUPLUS_SCHEME}://${SOVISUPLUS_HOST}:${SOVISUPLUS_PORT}
      - ORCID_URL=${ORCID_URL}
      - ORCID_SCOPES=${ORCID_SCOPES}
      - ORCID_CLIENT_ID=${ORCID_CLIENT_ID}
      - ORCID_CLIENT_SECRET=${ORCID_CLIENT_SECRET}
      - SOVISUPLUS_HOST=${SOVISUPLUS_SCHEME}://${SOVISUPLUS_HOST}:${SOVISUPLUS_PORT}
    depends_on:
      svp-db:
        condition: service_healthy
      crisalid-bus:
        condition: service_healthy
    networks:
      - svp-network
      - crisalid-front
    profiles:
      - sovisuplus

networks:
  svp-network:
    driver: bridge
  crisalid-front:
    driver: bridge
services:
  svp-db:
    image: postgres:16
    container_name: svp-db
    restart: always
    environment:
      POSTGRES_USER: ${SVP_DB_USER}
      POSTGRES_PASSWORD: ${SVP_DB_PASSWORD}
      POSTGRES_DB: ${SVP_DB_NAME}
    expose:
      - 5432
    ports:
      - 5432:5432

2) Apollo API (docker/apollo/apollo.yaml)

Ensure the public mapping is present (it typically is already because Apollo graphql GUI is one of the main user interfaces):

apollo.yaml
services:
  apollo:
    image: crisalidesr/crisalid-apollo:latest
    ports:
      - ${APOLLO_API_PORT}:4000
    depends_on:
      neo4j:
        condition: service_healthy
    environment:
      - APP_ENV=DEV
      - NEO4J_URI=bolt://neo4j:${NEO4J_BOLT_PORT}
      - ENABLE_API_KEYS=${APOLLO_ENABLE_API_KEYS}
    networks:
      - ikg-network
      - crisalid-front
    profiles:
      - apollo
networks:
  ikg-network:
    driver: bridge
  crisalid-front:
    driver: bridge
services:
  apollo:
    image: crisalidesr/crisalid-apollo:latest
    ports:
      - ${APOLLO_API_PORT}:4000

Your local SoVisu+ will call http://localhost:${APOLLO_API_PORT} (GraphQL endpoint /graphql).

3) CRISalid Bus / RabbitMQ (docker/crisalid-bus/crisalid-bus.yaml)

Only the management UI port is exposed by default, but you can uncomment the AMQP port to allow external tools to connect:

crisalid-bus.yaml
services:
  crisalid-bus:
    image: rabbitmq:3-management
    container_name: 'crisalid-bus'
    environment:
      - RABBITMQ_DEFAULT_USER=${CRISALID_BUS_USER}
      - RABBITMQ_DEFAULT_PASS=${CRISALID_BUS_PASSWORD}
      - RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS=-rabbit load_definitions "${CRISALID_BUS_DEFINITIONS_FILE}"
    ports:
      - "${CRISALID_BUS_HTTP_PORT}:15672"
      - "${CRISALID_BUS_AMQP_PORT}:5672"
    expose:
      - "${CRISALID_BUS_AMQP_PORT}"
    volumes:
      - ./rabbitmq-data:/var/lib/rabbitmq
      - ./rabbitmq-logs/:/var/log/rabbitmq
      - ./definitions.json:${CRISALID_BUS_DEFINITIONS_FILE}:ro
    healthcheck:
      test: rabbitmq-diagnostics check_port_connectivity
      interval: 1s
      timeout: 3s
      retries: 30
    networks:
      - crisalid-front
      - crisalid-back
    profiles:
      - crisalid-bus
networks:
  crisalid-front:
    driver: bridge
  crisalid-back:
    driver: bridge
services:
  crisalid-bus:
    image: rabbitmq:3-management
    container_name: 'crisalid-bus'
    environment:
      - RABBITMQ_DEFAULT_USER=${CRISALID_BUS_USER}
      - RABBITMQ_DEFAULT_PASS=${CRISALID_BUS_PASSWORD}
      - RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS=-rabbit load_definitions "${CRISALID_BUS_DEFINITIONS_FILE}"
    ports:
      - "${CRISALID_BUS_HTTP_PORT}:15672"
      - "${CRISALID_BUS_AMQP_PORT}:5672"
    expose:
      - "${CRISALID_BUS_AMQP_PORT}"

🧩 Use the Backend-Only Profile

Replace the sovisuplus profile with sovisuplus-db, which starts the DB and related services but not the SoVisu+ container itself.

Example command:

docker compose \
  --profile cdb \
  --profile neo4j \
  --profile apollo \
  --profile crisalid-bus \
  --profile harvester \
  --profile ikg \
  --profile keycloak \
  --profile sovisuplus-db \
  up --remove-orphans

▢️ Run SoVisu+ Locally

Start your Next.js app on the host as usual (e.g., in the SoVisu+ repo):

npm run dev # for the main web gui
npm run dev:listener # for the backend listener

Make sure your local env points to the Docker services. Typical variables (names vary by project):


NEXT_PUBLIC_SUPPORTED_LOCALES="fr,en"

DATABASE_URL="postgresql://sovisuplus:sovisuplus_password@localhost:5432/sovisuplus?schema=public"

KEYCLOAK_CLIENT_ID="sovisuplus"
KEYCLOAK_CLIENT_SECRET="use-the-same-secret-as-in-docker-compose"
KEYCLOAK_ISSUER="http://keycloak.local:8080/realms/crisalid-inst"
NEXTAUTH_URL="http://sovisuplus.local:3000/api/auth"
NEXTAUTH_SECRET="use-a-secure-random-secret"

AMQP_USER="crisalid_bus_user"
AMQP_PASSWORD="use-the-same-password-as-in-docker-compose"
AMQP_HOST="localhost"
AMQP_PORT="5672"
AMQP_QUEUE_NAME="sovisuplus"
AMQP_EXCHANGE_NAME="graph"

GRAPHQL_ENDPOINT_ENABLED="true"
GRAPHQL_ENDPOINT_URL="http://localhost:4000/graphql"
GRAPHQL_API_KEY_ENABLED="false"
GRAPHQL_API_KEY="not-needed-in-dev"

PERSPECTIVES_ROLES_FILTER="author"
PUBLICATION_LIST_ROLES_FILTER="author"

ORCID_URL="https://sandbox.orcid.org"
SOVISUPLUS_HOST="http://sovisuplus.local:3000"
ORCID_SCOPES="/person/update"
ORCID_CLIENT_ID="use-the-same-client-id--provided-by-orcid-as-in-docker-compose"
ORCID_CLIENT_SECRET="use-the-same-client-secret-provided-by-orcid-as-in-docker-compose"

Visit SoVisu+ at:

http://sovisuplus.local:3000