Commit graph

6 commits

Author SHA1 Message Date
83ffa7dbf8 admin: front console via NPM + add purge-test-users CLI
Networking: the superadmin console now mirrors `app` instead of a
loopback-only host port. Base compose drops the host port; the dev
override binds 127.0.0.1:8091; the prod overlay joins the `intranet`
network and listens on :80 with --proxy-headers so NPM can proxy it.

CLI: add `purge-test-users` (dry-run by default, --commit to delete,
--keep allow-list defaulting to the real accounts). Deletes child rows
explicitly (DB-agnostic) plus email-keyed OTPs, so smoke-test signups
that were pointed at prod can be cleaned repeatably instead of via
ad-hoc SQL. Covered by 6 new tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 18:54:26 +02:00
411094d7b8 admin: internal-only superadmin console (users, payments, DB stats)
New independent `admin` service (admin.main:app) on the same image, reusing
app.db/app.models read-only. Never runs migrations or the scheduler; issues
SELECTs only.

- Password-gated (ADMIN_CONSOLE_PASSWORD) with a 12h signed cookie; closed by
  default when the password is empty.
- Bound to 127.0.0.1:8091 (SSH-tunnel access); off the intranet/NPM network.
- Pages: overview stats, user list + search, per-user history/payment detail,
  DB usage (information_schema size + row estimates).
- Compose: base `admin` service (+prod DB-host override, test mount); Dockerfile
  bakes admin/ into runtime + test stages.
- Tests: tests/test_admin_console.py (auth, queries, page wiring) — 12 passing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:08:20 +02:00
71a2fc5b51 deploy: mount app/ + alembic from host in base compose
Lets a plain \`docker compose restart app\` pick up code edits without
an image rebuild. Image still bakes a copy at build time as a fallback.
Note: base compose is applied in prod too, so this affects the live
deploy — intentional, since this host edits live.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 12:49:27 +02:00
a50c5091c4 deploy: split compose into base (prod-ready) + dev override
Compose merges list-typed fields like \`ports\` by concatenation, so the
previous prod overlay couldn't clear the base file's host port binding;
the VPS app ended up listening on both port 80 (intranet) AND host port
8800 simultaneously.

Restructured to the conventional dev/prod split:
- docker-compose.yml: no host port — prod-ready by default
- docker-compose.override.yml: dev-only host port binding (auto-loaded
  by \`docker compose up\` locally, skipped when prod uses explicit -f)
- docker-compose.prod.yml: command-port 80 + intranet network only

Production invocation:
  docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:30:28 +01:00
6e7f57c6b2 phase G: data minimisation + passwordless auth + DeepSeek-first LLM
Server no longer holds portfolios. Holdings live in the browser
(localStorage); the server publishes an anonymous ticker_universe and a
gzipped /api/universe payload identical for every authenticated user, so
access patterns can't betray which tickers a user holds. AI commentary
is generated ephemerally from the browser-supplied pie and the cost
ledger row records no positions. Migrations 0009-0011 added the
universe table and dropped positions / portfolio_snapshots /
portfolios.

Authentication is now e-mail OTP only. Migration 0010 dropped
password_hash and email_verified (every active session is by
construction proof of email control). The /signup endpoint is gone;
signup and login share a single email-entry page. Email rendering is
HTML+plain-text multipart with a shared brand palette (app/branding.py)
asserted in sync with the CSS by a drift-detection test.

LLM provider defaults to DeepSeek-direct (cheaper, api.deepseek.com)
with OpenRouter as automatic fallback if DeepSeek fails. ai_log_job and
indicator_summary_job now iterate the two tones (NOVICE, INTERMEDIATE)
per cycle so the dashboard's tone toggle is instant; PROMPT_VERSION
bumped to 6 with an educational anti-TA / anti-gambling stance baked
into _CORE. NOVICE mode renders a curated glossary inline (CBOE VIX,
yield curve, HY OAS, etc.) with JS-positioned tooltips that survive
viewport edges and sticky bars. Model name and tokens hidden from the
user UI; still recorded in StrategicLog.model and AICall for admin.

Layout adds a sticky top nav, a sticky bottom markets bar (one chip per
exchange with status LED + headline index + 1d change), and
Phase H feedback reporting is queued in tasks/todo.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 14:16:57 +01:00
a10409c02b 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