initial commit — cassandra v0.1
Containerised macro-strategy dashboard: 4-panel web UI (indicators,
portfolio, flash news, AI strategic log), MariaDB store, hourly
ingestion jobs, OpenRouter-backed AI analysis.
Ports the four prototype scripts in the parent dir (market_pulse,
flash_news, trading212, strategic_log) into async services backed by a
persistent DB and served via FastAPI + Jinja2 + HTMX. APScheduler runs
as a separate compose service for crash-safety and easier restarts.
Portfolio composition + position names come live from Trading 212;
news per-ticker headlines reuse those names. Tone (NOVICE/INTERMEDIATE/
PRO) and analysis style (DRY/SPECULATIVE) are env-configurable and
stored on each log row so historical entries show what produced them.
Default model is deepseek/deepseek-v4-flash (overridable via env).
Light/dark theme toggle, sans-serif for prose surfaces, monospace for
data. Bearer-token auth, OpenRouter monthly cost cap, RSS feeds auto-
disabled on consecutive failures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:56:10 +01:00
|
|
|
# Cassandra — app + scheduler + MariaDB + daily backup sidecar.
|
|
|
|
|
# .env is mounted read-only; never bake secrets into the image.
|
|
|
|
|
|
|
|
|
|
services:
|
|
|
|
|
db:
|
|
|
|
|
image: mariadb:11
|
|
|
|
|
restart: unless-stopped
|
|
|
|
|
environment:
|
|
|
|
|
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD:-changeme-root}
|
|
|
|
|
MARIADB_DATABASE: ${MARIADB_DATABASE:-cassandra}
|
|
|
|
|
MARIADB_USER: ${MARIADB_USER:-cassandra}
|
|
|
|
|
MARIADB_PASSWORD: ${MARIADB_PASSWORD:-changeme}
|
|
|
|
|
volumes:
|
|
|
|
|
- db-data:/var/lib/mysql
|
|
|
|
|
- ./backup:/backup
|
|
|
|
|
healthcheck:
|
|
|
|
|
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
|
|
|
|
interval: 10s
|
|
|
|
|
timeout: 5s
|
|
|
|
|
retries: 10
|
|
|
|
|
|
2026-05-18 14:16:57 +01:00
|
|
|
redis:
|
|
|
|
|
image: redis:7-alpine
|
|
|
|
|
restart: unless-stopped
|
|
|
|
|
# No volume mount: this is a cache / scratch store. Persistence would
|
|
|
|
|
# undercut the "ephemeral pie" property — survival across restart is a
|
|
|
|
|
# bug, not a feature. AOF/RDB disabled via --save "" --appendonly no.
|
|
|
|
|
command: ["redis-server", "--save", "", "--appendonly", "no",
|
|
|
|
|
"--maxmemory", "128mb", "--maxmemory-policy", "allkeys-lru"]
|
|
|
|
|
healthcheck:
|
|
|
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
|
|
|
interval: 10s
|
|
|
|
|
timeout: 3s
|
|
|
|
|
retries: 5
|
|
|
|
|
|
initial commit — cassandra v0.1
Containerised macro-strategy dashboard: 4-panel web UI (indicators,
portfolio, flash news, AI strategic log), MariaDB store, hourly
ingestion jobs, OpenRouter-backed AI analysis.
Ports the four prototype scripts in the parent dir (market_pulse,
flash_news, trading212, strategic_log) into async services backed by a
persistent DB and served via FastAPI + Jinja2 + HTMX. APScheduler runs
as a separate compose service for crash-safety and easier restarts.
Portfolio composition + position names come live from Trading 212;
news per-ticker headlines reuse those names. Tone (NOVICE/INTERMEDIATE/
PRO) and analysis style (DRY/SPECULATIVE) are env-configurable and
stored on each log row so historical entries show what produced them.
Default model is deepseek/deepseek-v4-flash (overridable via env).
Light/dark theme toggle, sans-serif for prose surfaces, monospace for
data. Bearer-token auth, OpenRouter monthly cost cap, RSS feeds auto-
disabled on consecutive failures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:56:10 +01:00
|
|
|
app:
|
|
|
|
|
build: .
|
|
|
|
|
restart: unless-stopped
|
|
|
|
|
command: ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
|
|
|
|
|
env_file: .env
|
|
|
|
|
environment:
|
|
|
|
|
DATABASE_URL: mysql+aiomysql://${MARIADB_USER:-cassandra}:${MARIADB_PASSWORD:-changeme}@db:3306/${MARIADB_DATABASE:-cassandra}
|
2026-05-18 14:16:57 +01:00
|
|
|
REDIS_URL: redis://redis:6379/0
|
initial commit — cassandra v0.1
Containerised macro-strategy dashboard: 4-panel web UI (indicators,
portfolio, flash news, AI strategic log), MariaDB store, hourly
ingestion jobs, OpenRouter-backed AI analysis.
Ports the four prototype scripts in the parent dir (market_pulse,
flash_news, trading212, strategic_log) into async services backed by a
persistent DB and served via FastAPI + Jinja2 + HTMX. APScheduler runs
as a separate compose service for crash-safety and easier restarts.
Portfolio composition + position names come live from Trading 212;
news per-ticker headlines reuse those names. Tone (NOVICE/INTERMEDIATE/
PRO) and analysis style (DRY/SPECULATIVE) are env-configurable and
stored on each log row so historical entries show what produced them.
Default model is deepseek/deepseek-v4-flash (overridable via env).
Light/dark theme toggle, sans-serif for prose surfaces, monospace for
data. Bearer-token auth, OpenRouter monthly cost cap, RSS feeds auto-
disabled on consecutive failures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:56:10 +01:00
|
|
|
volumes:
|
|
|
|
|
- ./config:/app/config:ro
|
2026-05-25 12:49:27 +02:00
|
|
|
# Mount app code + migrations from the host so edits take effect
|
|
|
|
|
# on a plain `docker compose restart app` — no image rebuild.
|
|
|
|
|
# Image still bakes a copy at build time as a fallback.
|
|
|
|
|
- ./app:/app/app
|
|
|
|
|
- ./alembic:/app/alembic
|
|
|
|
|
- ./alembic.ini:/app/alembic.ini:ro
|
initial commit — cassandra v0.1
Containerised macro-strategy dashboard: 4-panel web UI (indicators,
portfolio, flash news, AI strategic log), MariaDB store, hourly
ingestion jobs, OpenRouter-backed AI analysis.
Ports the four prototype scripts in the parent dir (market_pulse,
flash_news, trading212, strategic_log) into async services backed by a
persistent DB and served via FastAPI + Jinja2 + HTMX. APScheduler runs
as a separate compose service for crash-safety and easier restarts.
Portfolio composition + position names come live from Trading 212;
news per-ticker headlines reuse those names. Tone (NOVICE/INTERMEDIATE/
PRO) and analysis style (DRY/SPECULATIVE) are env-configurable and
stored on each log row so historical entries show what produced them.
Default model is deepseek/deepseek-v4-flash (overridable via env).
Light/dark theme toggle, sans-serif for prose surfaces, monospace for
data. Bearer-token auth, OpenRouter monthly cost cap, RSS feeds auto-
disabled on consecutive failures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:56:10 +01:00
|
|
|
depends_on:
|
|
|
|
|
db:
|
|
|
|
|
condition: service_healthy
|
2026-05-18 14:16:57 +01:00
|
|
|
redis:
|
|
|
|
|
condition: service_healthy
|
2026-05-22 21:30:28 +01:00
|
|
|
# No host port by default — the local-dev override file adds one.
|
|
|
|
|
# See docker-compose.override.yml (dev) and docker-compose.prod.yml
|
|
|
|
|
# (VPS, NPM-fronted) for the two deployment modes.
|
initial commit — cassandra v0.1
Containerised macro-strategy dashboard: 4-panel web UI (indicators,
portfolio, flash news, AI strategic log), MariaDB store, hourly
ingestion jobs, OpenRouter-backed AI analysis.
Ports the four prototype scripts in the parent dir (market_pulse,
flash_news, trading212, strategic_log) into async services backed by a
persistent DB and served via FastAPI + Jinja2 + HTMX. APScheduler runs
as a separate compose service for crash-safety and easier restarts.
Portfolio composition + position names come live from Trading 212;
news per-ticker headlines reuse those names. Tone (NOVICE/INTERMEDIATE/
PRO) and analysis style (DRY/SPECULATIVE) are env-configurable and
stored on each log row so historical entries show what produced them.
Default model is deepseek/deepseek-v4-flash (overridable via env).
Light/dark theme toggle, sans-serif for prose surfaces, monospace for
data. Bearer-token auth, OpenRouter monthly cost cap, RSS feeds auto-
disabled on consecutive failures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:56:10 +01:00
|
|
|
|
|
|
|
|
scheduler:
|
|
|
|
|
build: .
|
|
|
|
|
restart: unless-stopped
|
|
|
|
|
command: ["python", "-m", "app.scheduler_main"]
|
|
|
|
|
env_file: .env
|
|
|
|
|
environment:
|
|
|
|
|
DATABASE_URL: mysql+aiomysql://${MARIADB_USER:-cassandra}:${MARIADB_PASSWORD:-changeme}@db:3306/${MARIADB_DATABASE:-cassandra}
|
2026-05-18 14:16:57 +01:00
|
|
|
REDIS_URL: redis://redis:6379/0
|
initial commit — cassandra v0.1
Containerised macro-strategy dashboard: 4-panel web UI (indicators,
portfolio, flash news, AI strategic log), MariaDB store, hourly
ingestion jobs, OpenRouter-backed AI analysis.
Ports the four prototype scripts in the parent dir (market_pulse,
flash_news, trading212, strategic_log) into async services backed by a
persistent DB and served via FastAPI + Jinja2 + HTMX. APScheduler runs
as a separate compose service for crash-safety and easier restarts.
Portfolio composition + position names come live from Trading 212;
news per-ticker headlines reuse those names. Tone (NOVICE/INTERMEDIATE/
PRO) and analysis style (DRY/SPECULATIVE) are env-configurable and
stored on each log row so historical entries show what produced them.
Default model is deepseek/deepseek-v4-flash (overridable via env).
Light/dark theme toggle, sans-serif for prose surfaces, monospace for
data. Bearer-token auth, OpenRouter monthly cost cap, RSS feeds auto-
disabled on consecutive failures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:56:10 +01:00
|
|
|
volumes:
|
|
|
|
|
- ./config:/app/config:ro
|
2026-05-25 12:49:27 +02:00
|
|
|
- ./app:/app/app
|
|
|
|
|
- ./alembic:/app/alembic
|
|
|
|
|
- ./alembic.ini:/app/alembic.ini:ro
|
initial commit — cassandra v0.1
Containerised macro-strategy dashboard: 4-panel web UI (indicators,
portfolio, flash news, AI strategic log), MariaDB store, hourly
ingestion jobs, OpenRouter-backed AI analysis.
Ports the four prototype scripts in the parent dir (market_pulse,
flash_news, trading212, strategic_log) into async services backed by a
persistent DB and served via FastAPI + Jinja2 + HTMX. APScheduler runs
as a separate compose service for crash-safety and easier restarts.
Portfolio composition + position names come live from Trading 212;
news per-ticker headlines reuse those names. Tone (NOVICE/INTERMEDIATE/
PRO) and analysis style (DRY/SPECULATIVE) are env-configurable and
stored on each log row so historical entries show what produced them.
Default model is deepseek/deepseek-v4-flash (overridable via env).
Light/dark theme toggle, sans-serif for prose surfaces, monospace for
data. Bearer-token auth, OpenRouter monthly cost cap, RSS feeds auto-
disabled on consecutive failures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:56:10 +01:00
|
|
|
depends_on:
|
|
|
|
|
db:
|
|
|
|
|
condition: service_healthy
|
2026-05-18 14:16:57 +01:00
|
|
|
redis:
|
|
|
|
|
condition: service_healthy
|
initial commit — cassandra v0.1
Containerised macro-strategy dashboard: 4-panel web UI (indicators,
portfolio, flash news, AI strategic log), MariaDB store, hourly
ingestion jobs, OpenRouter-backed AI analysis.
Ports the four prototype scripts in the parent dir (market_pulse,
flash_news, trading212, strategic_log) into async services backed by a
persistent DB and served via FastAPI + Jinja2 + HTMX. APScheduler runs
as a separate compose service for crash-safety and easier restarts.
Portfolio composition + position names come live from Trading 212;
news per-ticker headlines reuse those names. Tone (NOVICE/INTERMEDIATE/
PRO) and analysis style (DRY/SPECULATIVE) are env-configurable and
stored on each log row so historical entries show what produced them.
Default model is deepseek/deepseek-v4-flash (overridable via env).
Light/dark theme toggle, sans-serif for prose surfaces, monospace for
data. Bearer-token auth, OpenRouter monthly cost cap, RSS feeds auto-
disabled on consecutive failures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:56:10 +01:00
|
|
|
|
|
|
|
|
backup:
|
|
|
|
|
image: mariadb:11
|
|
|
|
|
restart: unless-stopped
|
|
|
|
|
environment:
|
|
|
|
|
MARIADB_HOST: db
|
|
|
|
|
MARIADB_USER: ${MARIADB_USER:-cassandra}
|
|
|
|
|
MARIADB_PASSWORD: ${MARIADB_PASSWORD:-changeme}
|
|
|
|
|
MARIADB_DATABASE: ${MARIADB_DATABASE:-cassandra}
|
|
|
|
|
entrypoint: ["/bin/sh", "-c"]
|
|
|
|
|
# Daily dump at 03:00 UTC; keeps last 14 days.
|
|
|
|
|
command: |
|
|
|
|
|
"while true; do
|
|
|
|
|
sleep $$((86400 - $$(date +%s) % 86400 + 10800));
|
|
|
|
|
f=/backup/cassandra-$$(date -u +%Y-%m-%d).sql.gz;
|
|
|
|
|
echo \"[backup] $$f\";
|
|
|
|
|
mariadb-dump -h $$MARIADB_HOST -u $$MARIADB_USER -p$$MARIADB_PASSWORD $$MARIADB_DATABASE | gzip > $$f || echo '[backup] FAILED';
|
|
|
|
|
find /backup -name 'cassandra-*.sql.gz' -mtime +14 -delete;
|
|
|
|
|
done"
|
|
|
|
|
volumes:
|
|
|
|
|
- ./backup:/backup
|
|
|
|
|
depends_on:
|
|
|
|
|
db:
|
|
|
|
|
condition: service_healthy
|
|
|
|
|
|
|
|
|
|
volumes:
|
|
|
|
|
db-data:
|