Geopolitical and Macro Analyst for the upcoming big crisis of 2026 https://read.markets
Find a file
Giorgio Gilestro 652995feea ui: log panel bottom-aligns with portfolio via contain:size
Third attempt at fixing the dashboard's right-column alignment, this
time with the structural cause identified explicitly.

Previous attempts (a55168d, 8347c90) changed align-self on #log-panel
to control how the panel filled its grid area. They got the box
edges aligned, but the underlying problem was a different one:
CSS Grid auto-sizes each row by MAX(intrinsic content height across
items in that row). When the log content is taller than indicators +
portfolio combined, the grid grows rows 2-3 to fit it; portfolio
ends up in a stretched row with empty space below the actual content.

The fix is to stop the log's content from contributing to the grid
row sizing at all. `contain: size` on the log panel declares "my
contents do not affect my intrinsic size" — the grid then sizes rows
2-3 from indicators + portfolio alone, and the log stretches to
inhabit that combined height. A flex column inside the panel
(min-height: 0 on every level of the chain) lets .panel-body fill
the remaining height below the header and scroll instead of
overflowing.

The 1100px mobile breakpoint undoes the constraint: at that width
the grid restructures to a single column, the log no longer shares
a row with indicators + portfolio, and `contain: size` would just
collapse the panel to zero. There the log expands naturally and
page scroll handles it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 14:56:11 +02:00
alembic alembic: make migration chain SQLite-compatible (fresh upgrade) 2026-05-28 00:16:09 +02:00
app ui: log panel bottom-aligns with portfolio via contain:size 2026-05-29 14:56:11 +02:00
config add ECB Data Portal source; group-aware stale thresholds 2026-05-15 23:13:58 +01:00
docs docs: mobile responsiveness design spec 2026-05-28 18:30:42 +02:00
scripts scripts: one-off purge of unclean IndicatorSummary rows 2026-05-29 13:56:47 +02:00
tasks phase G: data minimisation + passwordless auth + DeepSeek-first LLM 2026-05-18 14:16:57 +01:00
tests review: gate strategic-log, portfolio, chat, and digest on reviewer 2026-05-29 14:40:04 +02: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 docs: mobile responsiveness design spec 2026-05-28 18:30:42 +02:00
alembic.ini initial commit — cassandra v0.1 2026-05-15 21:56:10 +01:00
docker-compose.override.yml sync: encrypted cloud backup for portfolios + settings UX rework 2026-05-23 16:15:54 +02:00
docker-compose.prod.yml deploy: uvicorn --proxy-headers so https stays https behind NPM 2026-05-22 21:47:48 +01:00
docker-compose.test.yml test: standalone test container, isolated from the live prod stack 2026-05-25 23:58:55 +02:00
docker-compose.yml deploy: mount app/ + alembic from host in base compose 2026-05-25 12:49:27 +02:00
Dockerfile deps: add requirements.lock for reproducible builds 2026-05-28 00:07:38 +02:00
pyproject.toml stripe: wire checkout, customer portal, and webhook for read.markets 2026-05-26 18:45:13 +02:00
README.md deploy: split compose into base (prod-ready) + dev override 2026-05-22 21:30:28 +01:00
requirements.lock deps: add requirements.lock for reproducible builds 2026-05-28 00:07:38 +02: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).