# Changelog

All notable changes to this project are documented here.
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [2.2.0] — 2026-08-15

### Added
- Project-local `.venv` support in `api.php`'s Python resolution — checked before Homebrew/system Python, required for shared hosting where system-wide package installs aren't possible.
- `serialize_precision` fix in `api.php` so numeric fields (`price`, `change`, `fifty_two_week_high`, etc.) serialize as clean rounded values instead of full IEEE-754 float expansion (e.g. `305.93` instead of `305.93000000000000682...`).
- Admin section: `admin/config-check.php` (automated diagnostics for the shell_exec/venv/Python/network/permissions chain), `admin/test-quote.php` (manual `api.php` test tool with raw JSON + timing), `admin/docs-viewer.php` (renders project `.md` docs in-browser via `marked.js`).
- Navbar in `index.php` linking Home, Admin (dropdown), Docs, and a Help/FAQ modal covering index symbols, market-status meaning, change calculation, chart period granularity, and search-vs-watchlist behavior.
- `docs/ADMIN.md` documenting the admin tools and current (missing) auth status.

### Changed
- README setup instructions rewritten with real production deployment steps, including the `ensurepip`/broken-pip workaround needed on the shared host this was deployed to (build the venv against a newer Python found under a version-suffixed path, or bootstrap pip manually via `get-pip.py` if `ensurepip`'s bundled wheel is missing).

### Known issues
- Admin pages have no authentication yet — see `docs/ADMIN.md`. Deliberately deferred until the deployment pipeline itself was verified working; needs to be addressed before public deployment.

### Deployment notes (from initial production rollout)
- Confirmed working end-to-end: nginx → PHP-FPM → `shell_exec` → `.venv` (Python 3.12) → `yfinance` → Yahoo Finance → back through `api.php` to the browser.
- The server's default `python3` was 3.6 (EOL, incompatible with modern `yfinance`/`pandas`/`numpy`); a newer interpreter existed at `/usr/bin/python3.12` under a version-suffixed name.
- `python3.12 -m venv` initially failed because `ensurepip`'s bundled pip wheel was missing from the system Python install (`FileNotFoundError` on `pip-25.0.1-py3-none-any.whl`) — worked around with `venv --without-pip` + manually bootstrapping via `get-pip.py`.

## [2.1.0] — 2026-08-14

### Added
- Change (dollar and %) column, colored green/red, computed vs. previous close.
- 52 Week Range column (high/low from a full year of daily bars).
- Market open/closed badge in the header and per-row quote label (`Intraday` / `Close`).
- Chart period toggle (7D / 30D / 6mo / 1Y) in the chart modal, sliced client-side from a single cached year of daily data per symbol — no extra network round-trip when switching periods.
- `market_status` field in the `api.php` response: `{ "open": bool, "reason": string }`, computed from real US/Eastern time, weekday, and a fixed-date holiday list.
- Support for index symbols (`^DJI`, `^GSPC`, `^IXIC`) end-to-end.

### Changed
- `scraper.py` now fetches 1 year of daily history per ticker (previously 1 month), in a single `yfinance` call, and derives previous close, change, 52-week high/low, and the full chart series from that one dataset.
- Quote timestamp is now the actual date of the last data row returned by the source (`quote_date`), not the wall-clock time the request was made.
- `api.php` timezone is explicitly set to `America/New_York` so timestamps and market-hours logic are consistent regardless of server locale.

### Fixed
- Ticker sanitization regex in `api.php` (both the search/load path and `modify_watchlist`) stripped the leading `^` from index symbols before they reached `scraper.py`, causing `^DJI` / `^GSPC` / `^IXIC` to fail as "possibly delisted." Regex now allows `^` as a valid character.
- Malformed `<link>` tag in the frontend (`rel="stylesheet""`, invalid `</link>` closing tag).
- Dead `<script src="https://jsdelivr.net">` include that pointed at nothing.
- Broken "Direct Redirect" URLs (`https://yahoo.com` + symbol, with no path) now correctly point to `https://finance.yahoo.com/quote/{symbol}` and `https://www.google.com/finance/quote/{symbol}`.
- `bootstrap.Modal` was being called without Bootstrap's JS bundle ever being loaded — added the missing `<script>` tag so the chart modal actually opens.

### Known limitations
- 30D/6mo chart windows are sliced by trading days (21/126), not calendar days, so they're an approximation of a calendar month/half-year rather than exact.
- Market-hours check does not account for floating holidays (Memorial Day, Labor Day, Thanksgiving, Good Friday) or early-close half days.

## [2.0.0] — prior to this session

Initial version reviewed: single-file `api.php` router (CLI/web dual mode, `load_json` / `search` / `modify_watchlist` actions), `scraper.py` pulling 1 month of daily closes via `yfinance`, and `index.php` frontend with Bootstrap 5 + Chart.js, a system console log panel, and a 7-day line chart per symbol.
