diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 41c6eab..381a156 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -193,6 +193,32 @@ Implement dated dividend events and a provenance-validated PIT score provider be --- +## Session 2026-08-27 — Single-container Docker packaging (verified + pushed) + +**Branch:** main · **HEAD:** f9b8cd1 (pushed) + +### Completed this session (verified + pushed) +- **Dockerfile**: `python:3.11-slim` + nginx. Serves the PREBUILT `frontend/dist` SPA (committed bundle, no node/npm in the image), reverse-proxies `/api` → `127.0.0.1:5000`, `VOLUME [/app/backend/data]` for persistence (factor vintages, dividend ledger, forward runs, prices), HEALTHCHECK on `/api/v1/dashboard/summary`, exposes :80. +- **deploy/nginx.conf**: SPA fallback + `/api` proxy + gzip. +- **deploy/entrypoint.sh**: starts Flask (`HOST=0.0.0.0:5000`) + nginx in foreground, forwards INT/TERM. +- **docker-compose.yml**: service `set50`, port `8080:80`, volume `./backend/data`, healthcheck. +- **.dockerignore** (excludes .git/.venv/backend/data/node_modules/docs) + **.gitignore** now tracks `frontend/dist/` (prebuilt bundle); `backend/data/` stays untracked. + +### Verified +- Backend runtime: `test_client GET /api/v1/dashboard/summary` → 200 (the HEALTHCHECK path). +- `sh -n deploy/entrypoint.sh`, compose YAML parses, all Dockerfile-referenced files exist on remote `origin/main`. + +### Honest caveat +- **No local docker on this machine** → the image itself was NOT built/run here. The first real build happens on EasyPanel (or any docker host). If the build fails there, the most likely causes are env-var / volume mapping, which the compose file already covers for self-host. + +### Exact next action (user-side) +1. On EasyPanel create a service from this repo (build type **Dockerfile** — not Nixpacks). +2. Mount a **persistent volume** at `/app/backend/data` (or set `DATA_DIR` env to a mounted path) so the dividend ledger / factor vintages / forward runs survive redeploys. +3. Publish port **80** (default). Add a webhook in Gitea → EasyPanel deploy URL on push to `main` (Gitea Webhook, not Gitea Actions — no managed runners). +4. Optional: set `DIVIDEND_REFRESH_COOLDOWN_SECONDS` / `REFRESH_INTERVAL_SECONDS`. + +--- + ## Session 2026-08-27 — Auto-refresh dated dividend ledger (verified + pushed) **Branch:** main · **HEAD:** 03195dc (pushed) diff --git a/docs/engineering-log.md b/docs/engineering-log.md index 992f244..faaf6de 100644 --- a/docs/engineering-log.md +++ b/docs/engineering-log.md @@ -105,3 +105,4 @@ - Factor-learning validation gate (2026-08-27, commit `ae814c3`): closed the P4 "no auto-apply" loop — `weight_learning.py` now splits a chronological IC series into train + holdout via `apply_validation_gate`, and a factor is `validated=True` only when total sample >= 12, each window >= its min, train & holdout IC both beat baseline (BASELINE_IC=0) and agree in sign, and pooled |t| > 1.0. `apply_weight_update` keeps the weight unchanged for any unvalidated factor (no auto-apply); only validated factors move. `learn_momentum_gated` wired into `/api/v1/learning/momentum`, surfacing `ic_train`/`ic_holdout`/`validated`/`gate_notes`. Full backend **286 passed** (was 280). Live probe: momentum validated=false, gate_note "IC not above baseline (0.0711/-0.1143)" — weight unchanged. - Real dated dividend-history collector (2026-08-27, commit `f9973e8`): `siamchart.py` gained `parse_dividend_history`/`fetch_dividend_history` (reads the "ประวัติการปันผล" ex-date + DPS table per stock-info page); `dividend_ledger.py` gained `populate_dated_dividends` (registers dated rows, estimate=False). `POST /api/v1/dividends/update` fetches all snapshot symbols and persists a dated ledger at `data/dividends/ledger.json`; `use_ledger` backtests prefer the dated ledger (`dividend_method=dated_ledger`) and fall back to DPS estimates when unpopulated. Full backend **292 passed** (was 286). Live network fetch: 49/49 symbols, 1410 dated payments; use_ledger → `dated_ledger`. Note: this sandbox HAS outbound network (curl/https to siamchart 200) — contrary to earlier assumption. - Auto-refresh dated dividend ledger (2026-08-27, commit `03195dc`): `AppDataScheduler` now calls `_maybe_refresh_dated_dividends()` in `refresh_all` — a cooldown-gated (default 6h) fetch of real dated dividend history into `data/dividends/ledger.json`, so the ledger stays fresh without manual `/api/v1/dividends/update` and without hammering the source every tick. `DIVIDEND_REFRESH_COOLDOWN_SECONDS` env toggle. Full backend **294 passed** (was 292). +- Single-container Docker packaging (2026-08-27, commit `f9b8cd1`): added `Dockerfile` (python:3.11-slim + nginx; serves the PREBUILT `frontend/dist` SPA, proxies `/api` → 127.0.0.1:5000, `VOLUME /app/backend/data`, HEALTHCHECK on /api/v1/dashboard/summary, exposes :80), `deploy/nginx.conf`, `deploy/entrypoint.sh` (Flask HOST=0.0.0.0:5000 + nginx foreground), `docker-compose.yml` (port 8080:80, volume `./backend/data`), `.dockerignore`, and `.gitignore` now tracks `frontend/dist/` (prebuilt bundle required by the image; `backend/data/` stays untracked). Backend runtime verified (test_client `/api/v1/dashboard/summary` = 200). No local docker on this machine so the image itself must build on EasyPanel.