# docker-compose.yml
services:
  mongodb:
    image: mongo:7
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_USER}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
    volumes:
      - mongo-data:/data/db        # data survives container restarts
    networks: [app]

  backend:
    build: ./backend
    environment:
      SPRING_DATA_MONGODB_URI: mongodb://${MONGO_USER}:${MONGO_PASSWORD}@mongodb:27017/app?authSource=admin
      OPENAI_API_KEY: ${OPENAI_API_KEY}
    depends_on: [mongodb]
    ports: ["8080:8080"]
    networks: [app]

  frontend:
    build: ./client
    depends_on: [backend]
    ports: ["4173:4173"]
    networks: [app]

volumes:
  mongo-data:

networks:
  app:

Put the secrets in a .env file next to the compose file (and in .gitignore); Compose substitutes the ${...} values automatically. Inside the network, the backend reaches MongoDB at the host name mongodb, the service name. MongoDB isn’t published to the host at all.