refactor(gui): split dashboard in core (GA) + strategy_crypto (paper)

- NEW src/multi_swarm_core/multi_swarm_core/dashboard/ con theme.py + data.py + nicegui_app.py
- theme.py condiviso (CSS + colors + _apply_theme + _json_to_html + _build_header parametrico)
- core GUI: pagine /, /convergence, /genomes — legge SOLO runs.db
- strategy GUI slim: solo /, legge SOLO strategy_crypto.db — importa theme dal core
- Aggiunto nicegui+plotly al core pyproject (uv.lock rigenerato)
- docker-compose: nuovo servizio multi-swarm-core-gui su /multi_swarm_core_gui
  (Traefik PathPrefix + replacepathregex, NO stripprefix per evitare doppio root_path)
- .env.example: DASHBOARD_ROOT_PATH ora per-servizio

Pattern: ogni modulo possiede la sua GUI, ogni GUI legge solo il proprio DB.
N strategie future = duplica lo scheletro strategy_crypto/frontend/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-05-15 19:23:12 +00:00
parent 436613bfde
commit a43157cd44
10 changed files with 1092 additions and 904 deletions
+45 -10
View File
@@ -1,12 +1,14 @@
# docker-compose.yml — Multi-Swarm Coevolutive
#
# Due servizi della strategia crypto, condividono la stessa immagine
# Tre 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
# * 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
# * multi-swarm-core-gui — NiceGUI dashboard GA esposta su
# https://swarm.${DOMAIN_NAME:-tielogic.xyz}/multi_swarm_core_gui
#
# Entrambi joinano la rete external `traefik` cosi' il client Cerbero
# risolve direttamente l'host `cerbero-mcp` (porta 9000) senza passare
@@ -36,12 +38,11 @@ x-swarm-env: &swarm-env
# 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.
# DASHBOARD_ROOT_PATH e' ora per-servizio (vedi environment blocks sotto).
# 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:
@@ -85,11 +86,10 @@ services:
env_file: .env
environment:
<<: *swarm-env
DASHBOARD_ROOT_PATH: /strategy_crypto_gui
volumes:
# Dashboard legge entrambi i DB: state/ in read-only (WAL: vedi nota)
# Dashboard legge solo strategy_crypto.db: state/ in read-only (WAL: vedi nota)
- ./state:/app/state:ro
- ./data:/app/data:ro
- ./series:/app/series:ro
entrypoint:
- python
- -m
@@ -121,3 +121,38 @@ services:
- "traefik.http.middlewares.strategy-crypto-replace.replacepathregex.replacement=$$1"
- "traefik.http.routers.strategy-crypto-gui.middlewares=strategy-crypto-replace"
- com.centurylinklabs.watchtower.enable=true
multi-swarm-core-gui:
image: multi-swarm-coevolutive:dev
build:
context: .
dockerfile: Dockerfile
container_name: multi-swarm-core-gui
restart: unless-stopped
networks: [traefik]
env_file: .env
environment:
<<: *swarm-env
DASHBOARD_ROOT_PATH: /multi_swarm_core_gui
volumes:
- ./state:/app/state:ro
entrypoint: [python, -m, multi_swarm_core.dashboard.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.multi-swarm-core-gui.rule=Host(`swarm.${DOMAIN_NAME:-tielogic.xyz}`) && PathPrefix(`/multi_swarm_core_gui`)"
- traefik.http.routers.multi-swarm-core-gui.tls=true
- traefik.http.routers.multi-swarm-core-gui.entrypoints=websecure
- traefik.http.routers.multi-swarm-core-gui.tls.certresolver=mytlschallenge
- "traefik.http.services.multi-swarm-core-gui.loadbalancer.server.port=${SWARM_DASHBOARD_PORT:-8080}"
- "traefik.http.middlewares.multi-swarm-core-replace.replacepathregex.regex=^/multi_swarm_core_gui(/.*|$$)"
- "traefik.http.middlewares.multi-swarm-core-replace.replacepathregex.replacement=$$1"
- "traefik.http.routers.multi-swarm-core-gui.middlewares=multi-swarm-core-replace"
- com.centurylinklabs.watchtower.enable=true