read.markets/app/services
Giorgio Gilestro f326b41a08 sync: encrypted cloud backup for portfolios + settings UX rework
Adds opt-in client-side-encrypted portfolio sync (paid). Browser
PBKDF2(PIN) → AES-GCM, server HKDF(pepper, user_id) outer wrap;
server stores opaque bytes only. Sliding-window rate limit on GET.

  - new portfolio_sync table (migration 0015)
  - POST/GET/DELETE /api/portfolio/sync + /status
  - app/services/portfolio_sync.py crypto + rate limit
  - app/routers/sync.py paid-gated
  - app/static/js/portfolio-sync.js WebCrypto wrapper
  - settings page: enable/disable + PIN modal
  - PORTFOLIO_SYNC_PEPPER setting (warn on startup if missing)

Settings + import rework:

  - /upload merged into /settings#import (legacy route 302s)
  - drop CSV → auto-parse → preview → Import only / Import & sync
  - nav slimmed to Dashboard / News / Log
  - Settings + Logout moved to a user dropdown
  - brand logo links to /

Collateral fixes:

  - settings 500: re-fetch User in current session before mutating
    referral_code (assign_code_if_missing was refreshing a User
    loaded in the auth dep's now-closed session)
  - csv_import: distinct error for unfunded T212 pies (all qty=0)
  - db.py: drop pool_pre_ping (aiomysql 0.3.2 incompat); pin
    isolation_level=READ COMMITTED to avoid gap-lock deadlocks
  - alembic env: disable_existing_loggers=False so in-process
    migrations don't silence uvicorn's loggers
  - docker-compose.override.yml: dev-only volume mount + --reload

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 16:15:54 +02:00
..
__init__.py initial commit — cassandra v0.1 2026-05-15 21:56:10 +01:00
access.py phase D milestones 1+2: referral system + paid-access gate 2026-05-21 23:25:35 +01:00
auth_service.py phase G: data minimisation + passwordless auth + DeepSeek-first LLM 2026-05-18 14:16:57 +01:00
cadence.py news: auto-tag headlines + market-aware cadence + filter UI 2026-05-21 23:25:03 +01:00
csv_import.py sync: encrypted cloud backup for portfolios + settings UX rework 2026-05-23 16:15:54 +02:00
email_service.py brand: rename product to "Read the Markets" (read.markets) 2026-05-22 19:39:38 +01:00
feeds_bootstrap.py initial commit — cassandra v0.1 2026-05-15 21:56:10 +01:00
fx.py phase G: data minimisation + passwordless auth + DeepSeek-first LLM 2026-05-18 14:16:57 +01:00
glossary.py phase G: data minimisation + passwordless auth + DeepSeek-first LLM 2026-05-18 14:16:57 +01:00
instrument_map.py phase B (1/4): CSV parser + InstrumentMap (T212 shortcode → Yahoo ticker) 2026-05-16 10:53:08 +01:00
market.py add ECB Data Portal source; group-aware stale thresholds 2026-05-15 23:13:58 +01:00
markets.py add Eurostat + UK ONS sources; valuation/bubble/economy/bonds groups; aggregate read; market-open header 2026-05-15 23:07:42 +01:00
news.py initial commit — cassandra v0.1 2026-05-15 21:56:10 +01:00
news_tagging.py news: auto-tag headlines + market-aware cadence + filter UI 2026-05-21 23:25:03 +01:00
openrouter.py brand: rename product to "Read the Markets" (read.markets) 2026-05-22 19:39:38 +01:00
otp_service.py phase G: data minimisation + passwordless auth + DeepSeek-first LLM 2026-05-18 14:16:57 +01:00
portfolio_analysis.py phase G: data minimisation + passwordless auth + DeepSeek-first LLM 2026-05-18 14:16:57 +01:00
portfolio_sync.py sync: encrypted cloud backup for portfolios + settings UX rework 2026-05-23 16:15:54 +02:00
referral_service.py sync: encrypted cloud backup for portfolios + settings UX rework 2026-05-23 16:15:54 +02:00
ticker_universe.py phase G: data minimisation + passwordless auth + DeepSeek-first LLM 2026-05-18 14:16:57 +01:00
trading212.py initial commit — cassandra v0.1 2026-05-15 21:56:10 +01:00