Sign inSign up

marlussantiago/support-agent:latest

Manifest digest

sha256:11fd48bd73c899d5bcb4a7728810dbe7ae910e20f0db9e1fe799080bacefe38a

Last pushed

10 days by marlussantiago

Type

Compose

Manifest digest

sha256:11fd48bd73c899d5bcb4a7728810dbe7ae910e20f0db9e1fe799080bacefe38a

Compose file content

# Stack completa (publicada como artefato OCI no Docker Hub — ver scripts/publish.sh).
# ESTE ARQUIVO É PÚBLICO: nenhum segredo aqui. Segredos vêm só do .env (veja .env.example);
# os obrigatórios usam ${VAR:?} e o compose recusa subir sem eles.
# GLPI de teste (local): docker-compose.glpi.yml.

# Ambiente do Chatwoot (idêntico para web e worker)
x-chatwoot-env: &chatwoot-env
  NODE_ENV: production
  RAILS_ENV: production
  INSTALLATION_ENV: docker
  FRONTEND_URL: ${CHATWOOT_FRONTEND_URL:-http://localhost:3001}
  SECRET_KEY_BASE: ${CHATWOOT_SECRET_KEY_BASE:?defina CHATWOOT_SECRET_KEY_BASE no .env (openssl rand -hex 64)}
  DEFAULT_LOCALE: ${CHATWOOT_DEFAULT_LOCALE:-pt_BR}
  ENABLE_ACCOUNT_SIGNUP: ${CHATWOOT_ENABLE_ACCOUNT_SIGNUP:-true}
  # TLS é terminado no nginx; o Rails recebe HTTP + X-Forwarded-Proto
  FORCE_SSL: "false"
  RAILS_MAX_THREADS: ${CHATWOOT_RAILS_MAX_THREADS:-5}
  RAILS_LOG_TO_STDOUT: "true"
  LOG_LEVEL: ${CHATWOOT_LOG_LEVEL:-info}
  ACTIVE_STORAGE_SERVICE: local
  SAFE_FETCH_ALLOW_PRIVATE_NETWORK: "true"
  # Limite do widget (5 aberturas/hora por IP sem conversa). Em dev, "false" evita o 429 ao recarregar a página
  ENABLE_RACK_ATTACK_WIDGET_API: ${CHATWOOT_RACK_ATTACK_WIDGET:-true}
  # Banco (local: support-db; externo: DB_HOST + role com search_path no schema do Chatwoot)
  POSTGRES_HOST: ${DB_HOST:-support-db}
  POSTGRES_PORT: ${DB_PORT:-5432}
  POSTGRES_USERNAME: ${CHATWOOT_DB_USER:-${POSTGRES_USER:-support_user}}
  POSTGRES_PASSWORD: ${CHATWOOT_DB_PASSWORD:-${POSTGRES_PASSWORD:-support_pass}}
  POSTGRES_DATABASE: ${CHATWOOT_DB_NAME:-chatwoot_production}
  # Redis (db 1; a Support API usa o db 0)
  REDIS_URL: redis://support-redis:6379/1
  REDIS_PASSWORD: ${REDIS_PASSWORD:-}
  # E-mail (convites, recuperação de senha, notificações).
  # Sem SMTP_ADDRESS o Chatwoot usa sendmail, que não existe no container: nenhum e-mail sai.
  MAILER_SENDER_EMAIL: ${CHATWOOT_MAILER_SENDER_EMAIL:-Suporte <suporte@localhost>}
  SMTP_ADDRESS: ${SMTP_ADDRESS:-}
  SMTP_PORT: ${SMTP_PORT:-587}
  SMTP_DOMAIN: ${SMTP_DOMAIN:-}
  SMTP_USERNAME: ${SMTP_USERNAME:-}
  SMTP_PASSWORD: ${SMTP_PASSWORD:-}
  SMTP_AUTHENTICATION: ${SMTP_AUTHENTICATION:-login}
  SMTP_ENABLE_STARTTLS_AUTO: ${SMTP_ENABLE_STARTTLS_AUTO:-true}

services:

  # ----------------------------------------------------
  # Nginx: única porta pública (80 -> 443). Roteia por subdomínio:
  #   CHATWOOT_DOMAIN  Chatwoot  (+ /tascom-api/ Theme Studio, /tascom-painel/ Dashboard App)
  #   API_DOMAIN       Support API
  #   MONITOR_DOMAIN   Monitor   (opcional; exige MONITOR_TOKEN)
  #   GLPI_DOMAIN      GLPI de teste (opcional)
  # ----------------------------------------------------
  nginx:
    image: marlussantiago/support-nginx:latest
    build:
      context: ./nginx
    container_name: support-nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    environment:
      CHATWOOT_DOMAIN: ${CHATWOOT_DOMAIN:-chat.localhost}
      API_DOMAIN: ${API_DOMAIN:-api.localhost}
      MONITOR_DOMAIN: ${MONITOR_DOMAIN:-}
      GLPI_DOMAIN: ${GLPI_DOMAIN:-}
      CERT_NAME: ${CERT_NAME:-support}
    volumes:
      - certbot_conf:/etc/letsencrypt:ro
      - certbot_www:/var/www/certbot:ro
    depends_on:
      - chatwoot
      - api
      - dashboard-app
      - theme-studio
      - monitor
    networks:
      - internal-net

  # ----------------------------------------------------
  # Certbot (Let's Encrypt automático): na subida emite/expande o certificado para
  # os domínios públicos acima (desafio HTTP pelo nginx na porta 80) e renova a cada 12h.
  # O nginx detecta o certificado novo em até 1 min e recarrega sozinho.
  # Requer: DNS dos domínios apontando para o servidor, portas 80/443 abertas e LETSENCRYPT_EMAIL.
  # ----------------------------------------------------
  certbot:
    image: marlussantiago/support-certbot:latest
    build:
      context: ./certbot
    container_name: support-certbot
    restart: unless-stopped
    environment:
      CHATWOOT_DOMAIN: ${CHATWOOT_DOMAIN:-chat.localhost}
      API_DOMAIN: ${API_DOMAIN:-api.localhost}
      MONITOR_DOMAIN: ${MONITOR_DOMAIN:-}
      GLPI_DOMAIN: ${GLPI_DOMAIN:-}
      LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL:-}
      LETSENCRYPT_STAGING: ${LETSENCRYPT_STAGING:-0}
      CERT_NAME: ${CERT_NAME:-support}
    volumes:
      - certbot_conf:/etc/letsencrypt
      - certbot_www:/var/www/certbot
    depends_on:
      - nginx
    networks:
      - internal-net

  api:
    image: marlussantiago/support-api:latest
    build:
      context: ./api
    container_name: glpi-api
    restart: unless-stopped
    ports:
      - target: 3100
        published: "${API_PORT:-3100}"
        host_ip: 127.0.0.1
    environment:
      NODE_ENV: production
      PORT: 3100
      LOG_LEVEL: ${LOG_LEVEL:-info}
      # GLPI (produção: GLPI externo; teste: docker-compose.glpi.yml)
      GLPI_URL: ${GLPI_URL:-http://glpi:80/apirest.php}
      GLPI_WEB_URL: ${GLPI_WEB_URL:-http://localhost:8080}
      GLPI_APP_TOKEN: ${GLPI_APP_TOKEN:-}
      GLPI_USERNAME: ${GLPI_USERNAME:-glpi}
      GLPI_PASSWORD: ${GLPI_PASSWORD:-}
      GLPI_USER_TOKEN: ${GLPI_USER_TOKEN:-}
      # Persistência
      DATABASE_URL: postgresql://${API_DB_USER:-${POSTGRES_USER:-support_user}}:${API_DB_PASSWORD:-${POSTGRES_PASSWORD:-support_pass}}@${DB_HOST:-support-db}:${DB_PORT:-5432}/${POSTGRES_DB:-support_db}?schema=${API_DB_SCHEMA:-public}
      # Banco do Chatwoot (a API lê/atualiza conversas direto), com a mesma role do Chatwoot
      CHATWOOT_DATABASE_URL: postgresql://${CHATWOOT_DB_USER:-${POSTGRES_USER:-support_user}}:${CHATWOOT_DB_PASSWORD:-${POSTGRES_PASSWORD:-support_pass}}@${DB_HOST:-support-db}:${DB_PORT:-5432}/${CHATWOOT_DB_NAME:-chatwoot_production}
      REDIS_HOST: support-redis
      REDIS_PORT: 6379
      REDIS_PASSWORD: ${REDIS_PASSWORD:-}
      # Chatwoot
      CHATWOOT_BASE_URL: ${CHATWOOT_BASE_URL:-http://chatwoot:3000}
      CHATWOOT_API_TOKEN: ${CHATWOOT_API_TOKEN:-}
      CHATWOOT_WEBHOOK_SECRET: ${CHATWOOT_WEBHOOK_SECRET:-}
      CHATWOOT_DB_NAME: ${CHATWOOT_DB_NAME:-chatwoot_production}
      CHATWOOT_SUPPORT_INBOX_ID: ${CHATWOOT_SUPPORT_INBOX_ID:-1}
      DISABLE_SIGNATURE_VERIFICATION: ${DISABLE_SIGNATURE_VERIFICATION:-false}
      TRANSCRIPT_INCLUDE_PRIVATE_NOTES: ${TRANSCRIPT_INCLUDE_PRIVATE_NOTES:-false}
      # Chave do Dashboard App do Chatwoot
      DASHBOARD_APP_KEY: ${DASHBOARD_APP_KEY:?defina DASHBOARD_APP_KEY no .env (openssl rand -hex 24)}
    depends_on:
      support-db:
        condition: service_healthy
        required: false
      support-redis:
        condition: service_healthy
    networks:
      - internal-net

  # ----------------------------------------------------
  # PostgreSQL local da Support API (v2) e do Chatwoot (profile "local-db").
  # Com banco externo (DB_HOST), tire "local-db" do COMPOSE_PROFILES.
  # ----------------------------------------------------
  support-db:
    image: pgvector/pgvector:pg16
    container_name: support-postgres
    restart: unless-stopped
    profiles: ["local-db"]
    ports:
      - target: 5432
        published: "${POSTGRES_PORT:-5434}"
        host_ip: 127.0.0.1
    # Credenciais só são aplicadas na criação do volume support_pgdata
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-support_user}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-support_pass}
      POSTGRES_DB: ${POSTGRES_DB:-support_db}
    volumes:
      - support_pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-support_user} -d ${POSTGRES_DB:-support_db}"]
      interval: 5s
      timeout: 5s
      retries: 10
    networks:
      - internal-net

  # ----------------------------------------------------
  # Redis para Filas Assíncronas (BullMQ) e Chatwoot
  # ----------------------------------------------------
  support-redis:
    image: redis:7-alpine
    container_name: support-redis
    restart: unless-stopped
    ports:
      - target: 6379
        published: "${REDIS_PORT:-6380}"
        host_ip: 127.0.0.1
    environment:
      REDIS_PASSWORD: ${REDIS_PASSWORD:-}
    # Exige senha apenas quando REDIS_PASSWORD estiver definido
    command: ["sh", "-c", "exec redis-server $${REDIS_PASSWORD:+--requirepass \"$$REDIS_PASSWORD\"}"]
    volumes:
      - support_redisdata:/data
    healthcheck:
      test: ["CMD-SHELL", "redis-cli $${REDIS_PASSWORD:+-a \"$$REDIS_PASSWORD\" --no-auth-warning} ping | grep -q PONG"]
      interval: 5s
      timeout: 5s
      retries: 10
    networks:
      - internal-net

  # ----------------------------------------------------
  # Chatwoot Web & API (Atendimento Omnichannel N1)
  # ----------------------------------------------------
  chatwoot:
    image: chatwoot/chatwoot:latest
    container_name: chatwoot-web
    restart: unless-stopped
    ports:
      - target: 3000
        published: "${CHATWOOT_PORT:-3001}"
        host_ip: 127.0.0.1
    environment: *chatwoot-env
    entrypoint: docker/entrypoints/rails.sh
    # db:chatwoot_prepare é idempotente: cria o banco + seed na primeira subida
    # (volume vazio) e apenas aplica migrations pendentes nas seguintes.
    command: ["sh", "-c", "bundle exec rails db:chatwoot_prepare && exec bundle exec rails s -p 3000 -b 0.0.0.0"]
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3000/api"]
      interval: 10s
      timeout: 5s
      start_period: 180s
      retries: 30
    depends_on:
      support-db:
        condition: service_healthy
        required: false
      support-redis:
        condition: service_healthy
      # O theme-studio cria o volume tascom_theme com dono "node" (precisa subir antes)
      theme-studio:
        condition: service_started
    volumes:
      - chatwoot_data:/app/storage
      # Tema Tascom (loader.js, theme.css, studio.html, logos), gravado pelo theme-studio
      - tascom_theme:/app/public/tascom:ro
    networks:
      - internal-net

  # ----------------------------------------------------
  # Chatwoot Worker (Processamento em segundo plano)
  # ----------------------------------------------------
  chatwoot-worker:
    image: chatwoot/chatwoot:latest
    container_name: chatwoot-worker
    restart: unless-stopped
    environment: *chatwoot-env
    entrypoint: docker/entrypoints/rails.sh
    command: ["bundle", "exec", "sidekiq", "-C", "config/sidekiq.yml"]
    depends_on:
      chatwoot:
        condition: service_healthy
      support-db:
        condition: service_healthy
        required: false
      support-redis:
        condition: service_healthy
    volumes:
      - chatwoot_data:/app/storage
    networks:
      - internal-net

  # ----------------------------------------------------
  # Dashboard App "Chamados GLPI" (aba dentro da conversa do Chatwoot)
  # Só a tela: repassa as chamadas para /dashboard-app/api da Support API.
  # URL no Chatwoot: https://<CHATWOOT_DOMAIN>/tascom-painel/dashboard-app?key=<DASHBOARD_APP_KEY>
  # ----------------------------------------------------
  dashboard-app:
    image: marlussantiago/support-dashboard-app:latest
    build:
      context: ./dashboard-app
    container_name: tascom-dashboard-app
    restart: unless-stopped
    ports:
      - target: 8080
        published: "${DASHBOARD_APP_PORT:-3015}"
        host_ip: 127.0.0.1
    environment:
      BACKEND_URL: http://api:3100/dashboard-app/api
      BACKEND_TIMEOUT: 120
    depends_on:
      - api
    networks:
      - internal-net

  # ----------------------------------------------------
  # Theme Studio (tema, marca e scripts do painel do Chatwoot)
  # Página: https://<CHATWOOT_DOMAIN>/tascom/studio.html  — API: /tascom-api/ (nginx)
  # ----------------------------------------------------
  theme-studio:
    image: marlussantiago/support-theme-studio:latest
    build:
      context: ./theme-studio
    container_name: tascom-theme-studio
    restart: unless-stopped
    ports:
      - target: 3014
        published: "${STUDIO_PORT:-3014}"
        host_ip: 127.0.0.1
    environment:
      PORT: 3014
      # Origem do Chatwoot autorizada a chamar a API (via nginx é mesma origem)
      ALLOWED_ORIGIN: ${CHATWOOT_FRONTEND_URL:-http://localhost:3001}
      STUDIO_TOKEN: ${STUDIO_TOKEN:?defina STUDIO_TOKEN no .env (openssl rand -hex 24)}
      # Mesmo banco/Redis do Chatwoot (installation_configs + cache GlobalConfig)
      POSTGRES_HOST: ${DB_HOST:-support-db}
      POSTGRES_PORT: ${DB_PORT:-5432}
      POSTGRES_DATABASE: ${CHATWOOT_DB_NAME:-chatwoot_production}
      POSTGRES_USERNAME: ${CHATWOOT_DB_USER:-${POSTGRES_USER:-support_user}}
      POSTGRES_PASSWORD: ${CHATWOOT_DB_PASSWORD:-${POSTGRES_PASSWORD:-support_pass}}
      REDIS_URL: redis://support-redis:6379/1
      REDIS_PASSWORD: ${REDIS_PASSWORD:-}
    volumes:
      - tascom_theme:/data
    depends_on:
      support-db:
        condition: service_healthy
        required: false
      support-redis:
        condition: service_healthy
    networks:
      - internal-net

  # ----------------------------------------------------
  # Monitor (painel de saúde de todo o ambiente + /metrics Prometheus)
  # Painel: https://<MONITOR_DOMAIN> (nginx, com MONITOR_TOKEN) ou http://localhost:${MONITOR_PORT:-3016}
  # Lê o Docker pelo socket (read-only)
  # ----------------------------------------------------
  monitor:
    image: marlussantiago/support-monitor:latest
    build:
      context: ./monitor
    container_name: support-monitor
    restart: unless-stopped
    ports:
      - target: 3016
        published: "${MONITOR_PORT:-3016}"
        host_ip: 127.0.0.1
    environment:
      MONITOR_ENV_NAME: ${MONITOR_ENV_NAME:-local}
      MONITOR_TOKEN: ${MONITOR_TOKEN:-}
      MONITOR_WEBHOOK_URL: ${MONITOR_WEBHOOK_URL:-}
      MONITOR_ALERT_DEGRADED: ${MONITOR_ALERT_DEGRADED:-false}
      MONITOR_INTERVAL: ${MONITOR_INTERVAL:-15}
      MONITOR_FAIL_THRESHOLD: ${MONITOR_FAIL_THRESHOLD:-2}
      MONITOR_TLS_ALLOW_SELF_SIGNED: ${MONITOR_TLS_ALLOW_SELF_SIGNED:-false}
      MONITOR_EXPECTED_SERVICES: ${MONITOR_EXPECTED_SERVICES:-nginx,certbot,api,chatwoot,chatwoot-worker,dashboard-app,theme-studio,support-redis,monitor}
      # Borda HTTPS: verifica nginx -> app e o certificado de cada domínio
      CHATWOOT_DOMAIN: ${CHATWOOT_DOMAIN:-chat.localhost}
      API_DOMAIN: ${API_DOMAIN:-api.localhost}
      MONITOR_DOMAIN: ${MONITOR_DOMAIN:-}
      GLPI_DOMAIN: ${GLPI_DOMAIN:-}
      # Banco (role com pg_monitor + SELECT nas tabelas de negócio; ver .env.example)
      PG_HOST: ${DB_HOST:-support-db}
      PG_PORT: ${DB_PORT:-5432}
      PG_USER: ${MONITOR_DB_USER:-${POSTGRES_USER:-support_user}}
      PG_PASSWORD: ${MONITOR_DB_PASSWORD:-${POSTGRES_PASSWORD:-support_pass}}
      API_DB_NAME: ${POSTGRES_DB:-support_db}
      API_DB_SCHEMA: ${API_DB_SCHEMA:-public}
      CHATWOOT_DB_NAME: ${CHATWOOT_DB_NAME:-chatwoot_production}
      CHATWOOT_DB_SCHEMA: ${CHATWOOT_DB_SCHEMA:-public}
      REDIS_HOST: support-redis
      REDIS_PORT: 6379
      REDIS_PASSWORD: ${REDIS_PASSWORD:-}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - monitor_data:/data
    networks:
      - internal-net

volumes:
  tascom_theme:
  support_pgdata:
  support_redisdata:
  chatwoot_data:
  certbot_conf:
  certbot_www:
  monitor_data:

networks:
  internal-net:
    driver: bridge
services:
  api:
    image: docker.io/marlussantiago/support-api:latest@sha256:86727fd96b0a46f8e54d8650aca98d350aa7776b046e93cf7910bfe30092e82c
  certbot:
    image: docker.io/marlussantiago/support-certbot:latest@sha256:77e5cd9a38089fa0c4caf983f321de5bbc53115443c925a8c88fb5f7a7b528a3
  chatwoot:
    image: docker.io/chatwoot/chatwoot:latest@sha256:a4b7eea7353a9b585d0f29f2c57c7549710db961b119f7f1561b2fe964f48f65
  chatwoot-worker:
    image: docker.io/chatwoot/chatwoot:latest@sha256:a4b7eea7353a9b585d0f29f2c57c7549710db961b119f7f1561b2fe964f48f65
  dashboard-app:
    image: docker.io/marlussantiago/support-dashboard-app:latest@sha256:e22bf4b8ddbdfb1a7aa63c754e52f90b3f6b8c2a626be65f47314ca77dce9063
  monitor:
    image: docker.io/marlussantiago/support-monitor:latest@sha256:34376d8a686eb06185759dc7c21c42928a94a93c77eeaa1e3feb418b33903ab6
  nginx:
    image: docker.io/marlussantiago/support-nginx:latest@sha256:59a5de3285af6b23227f0f1747b4cf6a68d122aac56e18b5053f9229d948cafb
  support-db:
    image: docker.io/pgvector/pgvector:pg16@sha256:7b822b0aac60967beb1ea5e576b8602c94c300a157d187f385ae3e0da199b90a
  support-redis:
    image: docker.io/library/redis:7-alpine@sha256:858f009f9709ce576febc734aa78b8f6d624b82571f9ddb6bda4377c833b3499
  theme-studio:
    image: docker.io/marlussantiago/support-theme-studio:latest@sha256:0460aaa72a1d8e65d1742dd025165f0e05807881c2679f0912d00fba12e21d80

Docker commands

docker compose -f oci://marlussantiago/support-agent:latest up

Use the above command to pull and run the Compose file. Learn more⁠.

Images used

Image + 1 more

Redis is the world’s fastest data platform for caching, vector search, and NoSQL databases.


Pulls

1B+

Stars

13624

Last Updated

2 days

Image

Open-source vector similarity search for Postgres


Pulls

100M+

Stars

112

Last Updated

23 days

Image

The modern, open source, self-hosted customer support platform. Alternative to Intercom and Zendesk.


Pulls

10M+

Stars

109

Last Updated

about 11 hours

Image


Pulls

167

Stars

0

Last Updated

10 days

Image


Pulls

157

Stars

0

Last Updated

10 days

Image


Pulls

151

Stars

0

Last Updated

10 days

Image


Pulls

147

Stars

0

Last Updated

10 days

Image


Pulls

135

Stars

0

Last Updated

10 days

Image


Pulls

130

Stars

0

Last Updated

10 days