Geopolitical and Macro Analyst for the upcoming big crisis of 2026 https://read.markets
Find a file
Giorgio Gilestro 3932ef4048 deploy: prod uses container-FQDN for DATABASE_URL / REDIS_URL
The shared \`intranet\` Docker network has many other containers
aliased as \`db\` and \`redis\` (mastodon-db, mailman redis, etc.).
Docker's embedded DNS resolved those before our own services, sending
the app's MySQL connection to the wrong IP and crashing it in a restart
loop.

Switched both DATABASE_URL and REDIS_URL in the prod overlay to use
the project-prefixed container names (readmarkets-db-1,
readmarkets-redis-1), which are globally unique on the Docker daemon.
Applied to both app and scheduler.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:34:57 +01:00
alembic phase D milestones 1+2: referral system + paid-access gate 2026-05-21 23:25:35 +01:00
app brand: rename product to "Read the Markets" (read.markets) 2026-05-22 19:39:38 +01:00
config add ECB Data Portal source; group-aware stale thresholds 2026-05-15 23:13:58 +01:00
tasks phase G: data minimisation + passwordless auth + DeepSeek-first LLM 2026-05-18 14:16:57 +01:00
tests brand: rename product to "Read the Markets" (read.markets) 2026-05-22 19:39:38 +01:00
.dockerignore initial commit — cassandra v0.1 2026-05-15 21:56:10 +01:00
.env.example initial commit — cassandra v0.1 2026-05-15 21:56:10 +01:00
.gitignore initial commit — cassandra v0.1 2026-05-15 21:56:10 +01:00
alembic.ini initial commit — cassandra v0.1 2026-05-15 21:56:10 +01:00
docker-compose.override.yml deploy: split compose into base (prod-ready) + dev override 2026-05-22 21:30:28 +01:00
docker-compose.prod.yml deploy: prod uses container-FQDN for DATABASE_URL / REDIS_URL 2026-05-22 21:34:57 +01:00
docker-compose.yml deploy: split compose into base (prod-ready) + dev override 2026-05-22 21:30:28 +01:00
Dockerfile initial commit — cassandra v0.1 2026-05-15 21:56:10 +01:00
pyproject.toml phase G: data minimisation + passwordless auth + DeepSeek-first LLM 2026-05-18 14:16:57 +01:00
README.md deploy: split compose into base (prod-ready) + dev override 2026-05-22 21:30:28 +01:00

Read the Markets

Containerised macro-strategy dashboard — hourly market data, RSS news, Trading 212 portfolio, and an AI-generated strategic log written by Cassandra, the in-product seer. Read-only by design.

Production:

The Python package is still named cassandra and several internal identifiers (cookie names, advisory-lock keys, CASSANDRA_TOKEN env var, CSS filename) keep the legacy name on purpose — renaming them would invalidate live sessions / locks / configs for no user benefit. See app/branding.py for the brand single-source-of-truth.

Quick start (local dev)

cp .env.example .env       # fill in API keys; set CASSANDRA_TOKEN if exposing
docker compose up --build  # db + app + scheduler + daily backup sidecar
open http://localhost:8000/  # or whichever CASSANDRA_PORT you set

docker-compose.override.yml is auto-loaded and adds the host port binding so the app is reachable on localhost.

Production (VPS, NPM-fronted)

Always invoke with explicit -f flags — that way the dev override is skipped and the prod overlay (no host port, joins the external intranet Docker network, uvicorn on port 80) is applied:

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build

Point Nginx Proxy Manager at upstream readmarkets-app-1:80.

Architecture

  • app (FastAPI + Jinja2 + HTMX) — web dashboard on port 8000
  • scheduler (APScheduler) — hourly ingestion jobs (market, news, portfolio, AI log)
  • db (MariaDB 11) — quotes, headlines, portfolio snapshots, strategic logs, job runs
  • backup (sidecar) — daily mariadb-dump to ./backup/

See /home/gg/.claude/plans/ok-i-think-this-tidy-lake.md for the design plan.

Config

File Purpose
config/default.toml Universal data tables: indicator groups, RSS feeds, keyword presets
config/portfolio.toml User-specific portfolios (overrides default.toml)
.env Secrets and runtime knobs — mounted read-only into containers

Endpoints

  • GET / — dashboard
  • GET /portfolio/{name} — portfolio detail
  • GET /news — news feed
  • GET /log — strategic-log archive
  • GET /api/health — job status (last success / failure per job)

All authenticated routes require Authorization: Bearer $CASSANDRA_TOKEN if the env is set; if unset, the app is open (LAN-only mode).