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:
- Map the necessary service ports from containers to the host.
- Use a dedicated profile (e.g.
sovisuplus-db) to start only SoVisu+ backend services. - 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.localSoVisu+ 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:
# Overriden by environment specific YAML configurations (e.g. docker-compose.dev.yaml)
# image: postgres:16
container_name: svp-db
restart: unless-stopped
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=400","-c","superuser_reserved_connections=3" ]
profiles:
- sovisuplus-db
sovisuplus:
# Overriden by environment specific YAML configurations (e.g. docker-compose.dev.yaml)
# image: crisalidesr/sovisuplus:latest
container_name: sovisuplus
restart: unless-stopped
ports:
- ${SVP_PORT:-3000}:3000
- ${SVP_WS_INTERNAL_PORT:-3001}:3001
environment:
- INIT_ROLES_ON_START=true
- RBAC_ROLES_FILE=/config/rbac.roles.yaml
- DB_HOST=${SVP_DB_HOST:-svp-db}
- DB_NAME=${SVP_DB_NAME}
- DB_USER=${SVP_DB_USER}
- DB_PASSWORD=${SVP_DB_PASSWORD}
- DB_PORT=5432
- APP_URL=${SOVISUPLUS_URL}
- NEXT_PUBLIC_BASE_URL=${SOVISUPLUS_URL}
- NEXT_PUBLIC_WS_SCHEME=${SVP_WS_SCHEME}
- NEXT_PUBLIC_WS_HOST=${SVP_WS_HOST}
- NEXT_PUBLIC_WS_PORT=${SVP_WS_PORT}
- NEXT_PUBLIC_WS_PATH=${SVP_WS_PATH}
- NEXTAUTH_URL=${SOVISUPLUS_URL}/api/auth
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- JWT_TOKEN_EXPIRATION_HOURS=${JWT_TOKEN_EXPIRATION_HOURS:-12}
- AMQP_HOST=${CRISALID_BUS_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_HOST:-apollo}:${APOLLO_API_PORT}/graphql
- GRAPHQL_API_KEY_ENABLED=${APOLLO_ENABLE_API_KEYS}
- GRAPHQL_API_KEY=${SOVISUPLUS_GRAPHQL_API_KEY}
- KEYCLOAK_CLIENT_ID=${SOVISUPLUS_KEYCLOAK_CLIENT_ID}
- KEYCLOAK_CLIENT_SECRET=${SOVISUPLUS_KEYCLOAK_CLIENT_SECRET}
- KEYCLOAK_PUBLIC_ADDR=${KEYCLOAK_SCHEME}://${KEYCLOAK_HOST}:${KEYCLOAK_PORT}
- KEYCLOAK_INTERNAL_ADDR=http://keycloak:8080
- KEYCLOAK_REALM=${KEYCLOAK_REALM}
- ORCID_URL=${ORCID_URL}
- ORCID_SCOPES=${ORCID_SCOPES}
- ORCID_CLIENT_ID=${ORCID_CLIENT_ID}
- ORCID_CLIENT_SECRET=${ORCID_CLIENT_SECRET}
- VOCABS_URL=${CRISALID_VOCAB_SEARCH_URL}
- NEXT_PUBLIC_AVAILABLE_VOCABS=${CRISALID_VOCAB_SEARCH_AVAILABLE_VOCABS:-jel,aat,acm,elsst,pactols,euroscivoc}
- PERSPECTIVE_ROLES_FILTER=${PERSPECTIVE_ROLES_FILTER}
- PUBLICATION_LIST_ROLES_FILTER=${PUBLICATION_LIST_ROLES_FILTER}
- DEFAULT_SELF_SCOPED_ROLES=${DEFAULT_SELF_SCOPED_ROLES}
- NEXT_PUBLIC_INSTITUTION_NAME=${INSTITUTION_NAME}
- FIELD_ENC_PRIMARY_KID=${FIELD_ENC_PRIMARY_KID}
- FIELD_ENC_KEYS_JSON=${FIELD_ENC_KEYS_JSON}
depends_on:
crisalid-bus:
condition: service_healthy
volumes:
- ./config:/config:ro
- ./theme:/custom-theme:ro
networks:
- svp-network
- crisalid-front
profiles:
- sovisuplus
networks:
svp-network:
driver: bridge
crisalid-front:
driver: bridgeservices:
svp-db:
image: postgres:16
container_name: svp-db
restart: unless-stopped
environment:
POSTGRES_USER: ${SVP_DB_USER}
POSTGRES_PASSWORD: ${SVP_DB_PASSWORD}
POSTGRES_DB: ${SVP_DB_NAME}
expose:
- 5432
ports:
- 5432:54322) 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:
# Overriden by environment specific YAML configurations (e.g. docker-compose.dev.yaml)
# image: crisalidesr/crisalid-apollo:latest
container_name: crisalid-apollo
restart: unless-stopped
ports:
- ${APOLLO_API_PORT}:4000
depends_on:
neo4j:
condition: service_healthy
environment:
# Overriden by environment specific YAML configurations (e.g. docker-compose.dev.yaml)
# - APP_ENV=DEV
- NEO4J_URI=bolt://${NEO4J_HOST}:${NEO4J_BOLT_PORT}
- NEO4J_USER=${NEO4J_USER}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
- ENABLE_API_KEYS=${APOLLO_ENABLE_API_KEYS}
- API_KEYS=${SOVISUPLUS_GRAPHQL_API_KEY}
networks:
- ikg-network
- crisalid-front
profiles:
- apollo
networks:
ikg-network:
driver: bridge
crisalid-front:
driver: bridgeservices:
apollo:
image: crisalidesr/crisalid-apollo:latest
ports:
- ${APOLLO_API_PORT}:4000Your 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:
# Overriden by environment specific YAML configurations (e.g. docker-compose.dev.yaml)
# image: rabbitmq:3-management
container_name: 'crisalid-bus'
restart: unless-stopped
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" # To connect app under development on host machine or from external server
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: bridgeservices:
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 listenerMake 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_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 ","author of introduction, etc. ","author of afterword, colophon, etc. ","author in quotations or text abstracts ","editor ","editor of compilation ","translator" ]
PUBLICATION_LIST_ROLES_FILTER=["analyst ","annotator ","author ","author in quotations or text abstracts ","author of afterword, colophon, etc. ","author of introduction, etc. ","cartographer ","commentator for written text ","compiler ","composer ","conceptor ","contributor ","curator ","degree committee member ","dissertant ","donor ","editor ","editor of compilation ","film director ","film editor ","former owner ","illustrator ","interviewee ","interviewer ","opponent ","organizer ","other ","photographer ","praeses ","production personnel ","project director ","publisher director ","rapporteur ","scientific advisor ","software developer ","sound designer ","speaker ","stage manager ","thesis advisor ","translator ","writer of accompanying material"]
ORCID_URL="https://sandbox.orcid.org"
APP_URL="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