Ctrl K
ComunidadGuías…

docker-compose.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
services:
  postgres:
    image: postgres:14-alpine
    container_name: seneca-postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER:?POSTGRES_USER is required}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
      POSTGRES_DB: ${POSTGRES_DB:-finflow}
    ports:
      - "127.0.0.1:${POSTGRES_PORT:-5432}:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - finflow-network

  redis:
    image: redis:7-alpine
    container_name: seneca-redis
    restart: unless-stopped
    ports:
      - "127.0.0.1:${REDIS_PORT:-6379}:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - finflow-network

  backend:
    # Prebuilt images are published by CD for every release (`latest` tracks
    # the newest v* tag; set IMAGE_TAG to pin one). `docker compose pull`
    # then starts the stack without building anything locally.
    image: ghcr.io/stoic-budget/stoic-budget-backend:${IMAGE_TAG:-latest}
    build:
      context: ./backend
      dockerfile: Dockerfile
    container_name: seneca-backend
    ports:
      - "${BACKEND_PORT:-3001}:3001"
    env_file:
      - path: .env
        required: false
    environment:
      - NODE_ENV=production
      - RUN_MIGRATIONS=true
      - PORT=3001
      - FRONTEND_URL=${FRONTEND_URL:-http://localhost:3000}
      - APP_URL=${APP_URL:-http://localhost:3000}
      - APP_NAME=${APP_NAME:-Stoic Budget}
      - REGISTRATION_ENABLED=${REGISTRATION_ENABLED:-true}
      - DATABASE_URL=postgresql://${POSTGRES_USER:?POSTGRES_USER is required}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@postgres:5432/${POSTGRES_DB:-finflow}
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      # Both the cache and the statement-parsing queue read REDIS_URL. Without it
      # they fall back to localhost, which does not resolve inside the container.
      - REDIS_URL=redis://redis:6379
      - JWT_SECRET=${JWT_SECRET:?JWT_SECRET is required}
      - JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET:?JWT_REFRESH_SECRET is required}
      - INTEGRATIONS_ENCRYPTION_KEY=${INTEGRATIONS_ENCRYPTION_KEY:?INTEGRATIONS_ENCRYPTION_KEY is required}
      # Access-token lifetime intentionally left to the code default (30m,
      # see auth.service.ts). The long-lived session lives in the refresh token.
      - JWT_REFRESH_EXPIRES_IN=30d
      - LOG_LEVEL=info
    volumes:
      - backend_uploads:/app/uploads
      - update_requests:/app/update
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - finflow-network
    restart: unless-stopped

  frontend:
    image: ghcr.io/stoic-budget/stoic-budget-frontend:${IMAGE_TAG:-latest}
    build:
      context: ./frontend
      dockerfile: Dockerfile
      args:
        NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001/api/v1}
        NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
        NEXT_PUBLIC_APP_NAME: ${APP_NAME:-Stoic Budget}
        API_PROXY_TARGET: http://backend:3001
    container_name: seneca-frontend
    ports:
      - "${FRONTEND_PORT:-3000}:3000"
    environment:
      - NODE_ENV=production
      - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://localhost:3001/api/v1}
      - NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
      - NEXT_PUBLIC_APP_NAME=${APP_NAME:-Stoic Budget}
      - NEXT_PUBLIC_ENV=production
      - API_PROXY_TARGET=http://backend:3001
    depends_on:
      - backend
    networks:
      - finflow-network
    restart: unless-stopped

  # --- In-app updates (optional, off by default) -------------------------------
  # Lets an instance admin run the equivalent of `make upgrade` from
  # Settings -> Advanced. It drives Docker through the socket, which amounts to
  # root on the host, so it is opt-in: add COMPOSE_PROFILES=updater to .env.
  updater:
    image: docker:28-cli
    container_name: seneca-updater
    profiles: ["updater"]
    entrypoint: ["sh", "/updater.sh"]
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - .:/project
      - ./infra/updater/updater.sh:/updater.sh:ro
      - update_requests:/update
    networks:
      - finflow-network
    restart: unless-stopped

  # --- Receipt maps (optional, off by default) ---------------------------------
  # Self-hosted tiles and geocoding for the receipt location map:
  #   docker compose --profile maps --profile geocoder up -d
  # then set TILESERVER_URL=http://tileserver:8080 and GEOCODER_URL=http://nominatim:8080
  # for the backend. The first start imports MAP_PBF_URL: minutes for a small
  # country, hours for a large one, and several GB of disk either way.
  map-assets:
    image: alpine:3.22
    profiles: ["maps"]
    command: ["sh", "/scripts/prepare-assets.sh"]
    volumes:
      - ./infra/maps/prepare-assets.sh:/scripts/prepare-assets.sh:ro
      - ./infra/maps/tileserver-config.json:/scripts/tileserver-config.json:ro
      - map_data:/data
    restart: "no"

  map-tiles-init:
    image: ghcr.io/onthegomap/planetiler:0.10.2
    profiles: ["maps"]
    # Builds OpenMapTiles vector tiles once; later starts see the file and exit.
    entrypoint: ["sh", "-c"]
    command:
      - >-
        [ -s /data/region.mbtiles ] && echo "Tiles already built" ||
        exec java -cp @/app/jib-classpath-file com.onthegomap.planetiler.Main
        --download --download_dir=/data/sources --tmpdir=/data/tmp
        --osm_url="$${MAP_PBF_URL}" --output=/data/region.mbtiles
    environment:
      MAP_PBF_URL: ${MAP_PBF_URL:-https://download.geofabrik.de/asia/kazakhstan-latest.osm.pbf}
    volumes:
      - map_data:/data
    restart: "no"

  tileserver:
    image: maptiler/tileserver-gl:v5.6.0
    container_name: seneca-tileserver
    profiles: ["maps"]
    command: ["--config", "/data/config.json", "--port", "8080"]
    # No published port: the backend proxies tiles to signed-in users.
    volumes:
      - map_data:/data
    depends_on:
      map-assets:
        condition: service_completed_successfully
      map-tiles-init:
        condition: service_completed_successfully
    networks:
      finflow-network:
        aliases: [tileserver]
    restart: unless-stopped

  nominatim:
    image: mediagis/nominatim:5.3
    container_name: seneca-nominatim
    profiles: ["geocoder"]
    environment:
      PBF_URL: ${MAP_PBF_URL:-https://download.geofabrik.de/asia/kazakhstan-latest.osm.pbf}
      NOMINATIM_PASSWORD: ${NOMINATIM_PASSWORD:-nominatim}
    shm_size: 1gb
    # Imports the special phrases that let the backend search by kind of place.
    command: ["/seneca/start.sh"]
    volumes:
      - nominatim_data:/var/lib/postgresql/16/main
      - ./infra/nominatim:/seneca:ro
    networks:
      finflow-network:
        aliases: [nominatim]
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:
  backend_uploads:
  update_requests:
  map_data:
  nominatim_data:

networks:
  finflow-network:
    driver: bridge