PR3: static dashboard served by nginx / krypto-dca serve #3

Merged
DasAoD merged 3 commits from feature/frontend-dashboard into main 2026-08-28 16:53:48 +02:00
Owner

Dritter von vier PRs. Das statische Dashboard, das die PR2-API konsumiert.

Inhalt

  • web/: dependency-freies Dashboard, kein Build-Step
    • KPI-Kacheln: investiert, Cash, Bestandswert, Equity, PnL abs/%, vs. Buy&Hold
    • Wertentwicklungs-Chart (Chart.js, lokal in web/vendor/, MIT): Portfoliowert vs. eingezahlt vs. Buy&Hold, Umschalter 30/90/365 Tage
    • Bestände-Tabelle, paginierte Trade-Historie
    • Auto-Refresh alle 60 s, Light/Dark via prefers-color-scheme, reines fetch()
  • paths.resolve_web_dir(): findet web/ aus explizitem Pfad, KRYPTO_DCA_WEB_DIR, dem Source-Checkout oder /opt/krypto-dca-bot/web
  • api.create_app(): mountet web/ als StaticFiles nach den /api-Routen (die gewinnen immer). Dev: krypto-dca serve liefert damit alles same-origin unter einem Port (kein CORS). Prod: nginx serviert web/, der Mount liegt brach.
  • config: neues optionales [backend] web_dir
  • scripts/seed_demo.py: Dev-Tool (nicht im CLI), erzeugt eine synthetische paper-mode trading.db (seeded RNG, wöchentliche Käufe bis Spend-Budget, tägliche Kurse + Snapshots), damit lokal Daten da sind
  • Deploy: nginx-vhost umgebaut – root web/ von Platte + /api/ proxied auf 127.0.0.1:8787, eine Basic-Auth für beides
  • Docs: README (lokaler Dev-Walkthrough, PR3 als erledigt), SETUP.md Abschnitt 7 (Dashboard + nginx)

Bugfix (PR2-Code)

db.connect() bekommt ein optionales check_same_thread (Default True, unverändert fürs CLI); api.get_conn / api.health übergeben False. FastAPI führt die Cleanup einer Generator-Dependency u.U. in einem anderen Threadpool-Thread aus als das Öffnen → sqlite3.ProgrammingError bei parallelen Requests. Das Dashboard feuert drei Requests gleichzeitig, damit trat es zuverlässig auf.

Verifiziert

  • pytest → 36 passed (10 neu: static-Mount vs. /api, Assets ausgeliefert, app.js verdrahtet alle Endpunkte, resolve_web_dir, seed-DB treibt analytics.summarize/history, Buy-Stopp am Budget, Cross-Thread-Close)
  • End-to-End lokal: seed_demo.py → serve → Browser. Alle Endpunkte 200, auch unter parallelen Dreier-Bursts. KPIs, Chart (90/126 Punkte je Zeitraum), Bestände, Trade-Pagination und Zeitraum-Umschalter funktionieren.

Sicherheit

  • Frontend rein statisch, keine Secrets, kein State
  • API weiterhin nur 127.0.0.1, ausschließlich lesend; TLS + Auth komplett in nginx
  • Chart.js als einzige Frontend-Abhängigkeit, lokal vendored (kein CDN, kein npm auf dem VPS)

Co-authored-by: Claude claude@anthropic.com

Dritter von vier PRs. Das statische Dashboard, das die PR2-API konsumiert. ## Inhalt - **`web/`**: dependency-freies Dashboard, kein Build-Step - KPI-Kacheln: investiert, Cash, Bestandswert, Equity, PnL abs/%, vs. Buy&Hold - Wertentwicklungs-Chart (Chart.js, lokal in `web/vendor/`, MIT): Portfoliowert vs. eingezahlt vs. Buy&Hold, Umschalter 30/90/365 Tage - Bestände-Tabelle, paginierte Trade-Historie - Auto-Refresh alle 60 s, Light/Dark via `prefers-color-scheme`, reines `fetch()` - **`paths.resolve_web_dir()`**: findet `web/` aus explizitem Pfad, `KRYPTO_DCA_WEB_DIR`, dem Source-Checkout oder `/opt/krypto-dca-bot/web` - **`api.create_app()`**: mountet `web/` als `StaticFiles` **nach** den `/api`-Routen (die gewinnen immer). Dev: `krypto-dca serve` liefert damit alles same-origin unter einem Port (kein CORS). Prod: nginx serviert `web/`, der Mount liegt brach. - **`config`**: neues optionales `[backend] web_dir` - **`scripts/seed_demo.py`**: Dev-Tool (nicht im CLI), erzeugt eine synthetische paper-mode `trading.db` (seeded RNG, wöchentliche Käufe bis Spend-Budget, tägliche Kurse + Snapshots), damit lokal Daten da sind - **Deploy**: nginx-vhost umgebaut &ndash; `root web/` von Platte + `/api/` proxied auf `127.0.0.1:8787`, eine Basic-Auth für beides - **Docs**: README (lokaler Dev-Walkthrough, PR3 als erledigt), SETUP.md Abschnitt 7 (Dashboard + nginx) ## Bugfix (PR2-Code) `db.connect()` bekommt ein optionales `check_same_thread` (Default `True`, unverändert fürs CLI); `api.get_conn` / `api.health` übergeben `False`. FastAPI führt die Cleanup einer Generator-Dependency u.U. in einem anderen Threadpool-Thread aus als das Öffnen &rarr; `sqlite3.ProgrammingError` bei parallelen Requests. Das Dashboard feuert drei Requests gleichzeitig, damit trat es zuverlässig auf. ## Verifiziert - `pytest` &rarr; 36 passed (10 neu: static-Mount vs. `/api`, Assets ausgeliefert, `app.js` verdrahtet alle Endpunkte, `resolve_web_dir`, seed-DB treibt `analytics.summarize`/`history`, Buy-Stopp am Budget, Cross-Thread-Close) - End-to-End lokal: `seed_demo.py` &rarr; `serve` &rarr; Browser. Alle Endpunkte 200, auch unter parallelen Dreier-Bursts. KPIs, Chart (90/126 Punkte je Zeitraum), Bestände, Trade-Pagination und Zeitraum-Umschalter funktionieren. ## Sicherheit - Frontend rein statisch, keine Secrets, kein State - API weiterhin nur `127.0.0.1`, ausschließlich lesend; TLS + Auth komplett in nginx - Chart.js als einzige Frontend-Abhängigkeit, lokal vendored (kein CDN, kein npm auf dem VPS) Co-authored-by: Claude <claude@anthropic.com>
- FastAPI runs sync endpoints in a threadpool and may run a generator
  dependency's cleanup on a different thread than the one that opened the
  connection, which raised sqlite3.ProgrammingError under concurrent requests
- add an opt-in check_same_thread kwarg (default True, unchanged for the CLI)
  and pass False from api.get_conn / api.health
- regression test: a connection opened on one thread closes cleanly on another

Co-authored-by: Claude <claude@anthropic.com>
- web/: plain HTML/CSS/JS dashboard, no build step; KPI cards, Chart.js
  (vendored) value chart with 30/90/365-day toggle, holdings table, paginated
  trade history, 60s auto-refresh, light/dark
- paths.resolve_web_dir(): locate web/ from an explicit path, KRYPTO_DCA_WEB_DIR,
  the source checkout, or /opt/krypto-dca-bot/web
- api.create_app(): mount web/ as StaticFiles after the /api routes so the API
  always wins; production still serves web/ via nginx
- config: new optional [backend] web_dir

Co-authored-by: Claude <claude@anthropic.com>
- scripts/seed_demo.py: dev-only generator for a synthetic paper-mode trading.db
  (seeded RNG, weekly buys until a spend budget, daily prices + snapshots) so the
  dashboard has data locally
- tests: static mount wins over /api, assets served, app.js wires every endpoint,
  seeded DB drives analytics.summarize/history, buying stops at the budget
- nginx vhost: serve web/ from disk, proxy /api/ to the backend, one auth
- README + SETUP: local dev walkthrough, PR3 marked done, nginx static section

Co-authored-by: Claude <claude@anthropic.com>
DasAoD merged commit aabb1f5c31 into main 2026-08-28 16:53:48 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
DasAoD/krypto-dca-bot!3
No description provided.