Geopolitical and Macro Analyst for the upcoming big crisis of 2026 https://read.markets
Find a file
Giorgio Gilestro 80e2ec53ac test: standalone test container, isolated from the live prod stack
Adds a `test` stage to the Dockerfile (prod deps + pytest + aiosqlite via
the `dev` extras, never shipped) and a docker-compose.test.yml that runs
it under its own Compose project name (`cassandra-test`). The project-name
isolation matters because this host runs prod — a wrong `compose up` would
otherwise recreate the live `app` container; namespaced project means the
test container can't touch any prod container/network/volume.

Tests use an in-memory aiosqlite DB (per tests/conftest.py) so the
container has no MariaDB / Redis dependency and nothing on the prod DB
is observed or mutated.

Also adds aiosqlite to dev extras — tests have always implicitly needed
it (the conftest pins DATABASE_URL to sqlite+aiosqlite:///:memory:); the
declaration was just missing.

Usage:
  docker compose -f docker-compose.test.yml run --rm test
  docker compose -f docker-compose.test.yml run --rm test pytest -k unsubscribe
2026-05-25 23:58:55 +02:00
alembic db: drop redundant user_id index on email_sends 2026-05-25 22:55:33 +02:00
app beta-launch: respect returning-user opt-out + show digest job in ops LEDs 2026-05-25 23:33:53 +02:00
config add ECB Data Portal source; group-aware stale thresholds 2026-05-15 23:13:58 +01:00
docs/superpowers docs: implementation plan for beta + paid-gap rollout 2026-05-25 18:28:39 +02:00
tasks phase G: data minimisation + passwordless auth + DeepSeek-first LLM 2026-05-18 14:16:57 +01:00
tests beta-launch: respect returning-user opt-out + show digest job in ops LEDs 2026-05-25 23:33:53 +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 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 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 test: standalone test container, isolated from the live prod stack 2026-05-25 23:58:55 +02:00
pyproject.toml test: standalone test container, isolated from the live prod stack 2026-05-25 23:58:55 +02: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).