Files
Multi_Swarm_Coevolutive/docker-compose.yml
T
Adriano Dal Pastro 436613bfde fix(traefik): sostituisci stripprefix con replacepathregex per evitare doppio root_path
Bug: la dashboard NiceGUI mostrava "Your browser does not support ES modules"
perche' le asset URL nell'HTML erano doppio-prefissate:
  /strategy_crypto_gui/strategy_crypto_gui/_nicegui/...

Root cause: il middleware traefik.stripprefix aggiunge automaticamente
X-Forwarded-Prefix header. uvicorn/Starlette legge il header e setta
root_path automaticamente, raddoppiando con quello passato esplicitamente
a ui.run(root_path="/strategy_crypto_gui").

Fix: traefik.replacepathregex strippa il prefix senza propagare il header.
uvicorn vede solo il root_path da ui.run -> asset prefissati una sola volta.

  - replacepathregex.regex=^/strategy_crypto_gui(/.*|$)
  - replacepathregex.replacement=$1

Verifica end-to-end:
- page: HTTP 200, asset prefix singolo
- /strategy_crypto_gui/_nicegui/3.12.0/static/socket.io.min.js: 200
- / (root): 404 (atteso)

NB: dopo cambio label, necessario `docker restart traefik-traefik-1` per
forzare refresh discovery (problema noto Traefik con label durante recreate
container nello stesso ciclo). Annotare per future modifiche middleware.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 19:10:18 +00:00

124 lines
4.9 KiB
YAML

# docker-compose.yml — Multi-Swarm Coevolutive
#
# Due servizi della strategia crypto, condividono la stessa immagine
# `multi-swarm-coevolutive:dev` buildata dal Dockerfile root (uv workspace):
#
# * strategy-crypto-paper — paper-trading runner long-running
# (scripts/run_paper_trading.py)
# * strategy-crypto-gui — NiceGUI dashboard esposta da Traefik su
# https://swarm.${DOMAIN_NAME:-tielogic.xyz}/strategy_crypto_gui
#
# Entrambi joinano la rete external `traefik` cosi' il client Cerbero
# risolve direttamente l'host `cerbero-mcp` (porta 9000) senza passare
# dal gateway pubblico ne' dal TLS.
#
# Pattern N strategie future: aggiungere strategy-<asset>-paper + strategy-<asset>-gui
# con PathPrefix(/strategy_<asset>_gui) e DASHBOARD_ROOT_PATH dedicato.
#
# Dati persistenti via bind mount dalla cartella del repo:
# ./data cache OHLCV intermedia
# ./series cache parquet per timeframe/symbol
# ./state contiene runs.db (GA) + strategy_crypto.db (paper) + WAL/SHM
# ./src/strategy_crypto/strategy_crypto/strategies JSON freezate (ro)
#
# Secrets (token Cerbero + OpenRouter): caricati da .env via env_file.
networks:
traefik:
external: true
x-swarm-env: &swarm-env
# Override: rotta interna verso cerbero-mcp (no TLS, no traefik hop)
CERBERO_BASE_URL: http://cerbero-mcp:9000
# Override: path container per persistenza
DATA_DIR: /app/data
SERIES_DIR: /app/series
# DB separati per dominio:
GA_DB_PATH: /app/state/runs.db
STRATEGY_CRYPTO_DB_PATH: /app/state/strategy_crypto.db
# Subpath sotto cui la dashboard NiceGUI e' esposta da Traefik.
# IMPORTANT: NON usare StripPrefix middleware con questo. NiceGUI/Starlette
# gestisce internamente il root_path su request path che ARRIVANO con prefix.
# StripPrefix causa doppio prefix negli asset URL (NiceGUI prefixa + uvicorn
# rilegge X-Forwarded-Prefix e prefixa di nuovo).
DASHBOARD_ROOT_PATH: /strategy_crypto_gui
services:
strategy-crypto-paper:
build:
context: .
dockerfile: Dockerfile
image: multi-swarm-coevolutive:dev
container_name: strategy-crypto-paper
restart: unless-stopped
networks: [traefik]
env_file: .env
environment:
<<: *swarm-env
volumes:
- ./data:/app/data
- ./series:/app/series
- ./state:/app/state
- ./src/strategy_crypto/strategy_crypto/strategies:/app/strategies:ro
# Niente HTTP da controllare: ci affidiamo a `restart: unless-stopped`
# e ai log per la liveness del runner.
command:
- python
- /app/scripts/run_paper_trading.py
- --name=${PAPER_RUN_NAME:-phase3-papertrade-prod}
- --initial-capital=${PAPER_INITIAL_CAPITAL:-1000}
- --fees-bp=${PAPER_FEES_BP:-5.0}
- --poll-seconds=${PAPER_POLL_SECONDS:-300}
- --lookback-bars=${PAPER_LOOKBACK_BARS:-500}
- --strategies-dir=/app/strategies
labels:
- com.centurylinklabs.watchtower.enable=true
strategy-crypto-gui:
image: multi-swarm-coevolutive:dev
build:
context: .
dockerfile: Dockerfile
container_name: strategy-crypto-gui
restart: unless-stopped
networks: [traefik]
env_file: .env
environment:
<<: *swarm-env
volumes:
# Dashboard legge entrambi i DB: state/ in read-only (WAL: vedi nota)
- ./state:/app/state:ro
- ./data:/app/data:ro
- ./series:/app/series:ro
entrypoint:
- python
- -m
- strategy_crypto.frontend.nicegui_app
command: []
healthcheck:
test:
- "CMD"
- "python"
- "-c"
- "import os, urllib.request; urllib.request.urlopen(f'http://localhost:{os.environ.get(\"SWARM_DASHBOARD_PORT\",\"8080\")}/', timeout=3).close()"
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
labels:
- traefik.enable=true
- traefik.docker.network=traefik
- "traefik.http.routers.strategy-crypto-gui.rule=Host(`swarm.${DOMAIN_NAME:-tielogic.xyz}`) && PathPrefix(`/strategy_crypto_gui`)"
- traefik.http.routers.strategy-crypto-gui.tls=true
- traefik.http.routers.strategy-crypto-gui.entrypoints=websecure
- traefik.http.routers.strategy-crypto-gui.tls.certresolver=mytlschallenge
- "traefik.http.services.strategy-crypto-gui.loadbalancer.server.port=${SWARM_DASHBOARD_PORT:-8080}"
# replacepathregex (NON stripprefix): strippa il prefix dalla request senza
# aggiungere X-Forwarded-Prefix header. uvicorn vede solo root_path da
# ui.run(root_path=...), quindi gli asset URL vengono prefissati una sola
# volta (no doppio prefix come succederebbe con stripprefix).
- "traefik.http.middlewares.strategy-crypto-replace.replacepathregex.regex=^/strategy_crypto_gui(/.*|$$)"
- "traefik.http.middlewares.strategy-crypto-replace.replacepathregex.replacement=$$1"
- "traefik.http.routers.strategy-crypto-gui.middlewares=strategy-crypto-replace"
- com.centurylinklabs.watchtower.enable=true