diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..4c81277 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,60 @@ +name: Deploy to GitHub Pages + +# Publishes the app on every push to master (i.e. after a PR is merged), or by +# hand from the Actions tab. Pull requests never deploy. +# +# Before the first run: Settings → Pages → Build and deployment → Source: +# "GitHub Actions". Without it, this workflow fails at the deploy step. +on: + push: + branches: [master] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +# One deploy at a time; a newer push waits rather than cancelling a deploy mid-way. +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + name: Build site + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + # Publish only what the app needs. docs/, CLAUDE.md, tests and CI files + # stay in the repo but are not served. + - name: Assemble site + run: | + mkdir -p _site + cp index.html _site/ + cp -r js samples _site/ + touch _site/.nojekyll + echo "Published files:" && find _site -type f | sort + - name: Refuse to publish data files + run: | + if find _site -iname 'finlens-state*.json' -o -iname 'finlens-export-*' -o -path '*/data/*' | grep -q .; then + echo "::error::A data or backup file is in the site folder. Nothing was published." + exit 1 + fi + - uses: actions/configure-pages@v5 + - uses: actions/upload-pages-artifact@v3 + with: + path: _site + + deploy: + name: Deploy + needs: build + runs-on: ubuntu-latest + timeout-minutes: 10 + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index a41488d..ccbfd87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). --- +## [2.0.3] — 2026-11-04 + +### Technical — Hosting +- **Deploy to GitHub Pages** (`.github/workflows/pages.yml`). On every push to `master` (after a merge), or by hand from the Actions tab, the app is published as static files to `https://gitluis.github.io/finlens/` (later, the custom domain). Pull requests never deploy. Nothing in the app changes. + - **Only the app is published:** `index.html`, `js/` and `samples/`. `docs/`, `CLAUDE.md`, tests and CI files aren't served. The build refuses to publish if a `finlens-state*.json`, export or `data/` file is in the site folder. + - **Before the first run:** Settings → Pages → Source: **GitHub Actions**. +- **CLAUDE.md §23 Hosting (new):** what's served, the one-site-per-origin rule (all of an account's Pages sites share `.github.io`, so publish no other Pages site until FinLens has its own domain), custom-domain setup, and the Pages limits (no custom headers, so CSP stays a `` tag). +- Part of the **v2.0 — Public launch** milestone. Left open on purpose until the rename and custom domain are ready. + +--- + ## [1.10.5] — 2026-11-02 ### Fixed diff --git a/CLAUDE.md b/CLAUDE.md index d895c1b..80ff1c3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -59,7 +59,7 @@ Until then, this section is the rule. FinLens is a **single-origin, zero-build, vanilla JavaScript personal finance dashboard** that runs entirely in the browser. There is no server, no npm, no bundler, no framework, and no TypeScript. The entry point is `index.html`; everything else is a plain `.js` file in the `js/` folder. -**Current version:** v1.10.5 (updated in `index.html` footer, `README.md`, and `CHANGELOG.md` on every release). +**Current version:** v2.0.3 (updated in `index.html` footer, `README.md`, and `CHANGELOG.md` on every release). **What it does:** Imports CSV exports from Ally Bank (Checking + Savings) and Chase credit cards, parses and normalizes them into a unified transaction model, and renders a multi-tab financial dashboard with budgeting, debt tracking, savings forecasting, investment planning, and Claude-powered AI analysis. @@ -798,7 +798,7 @@ Multiple Chase card files can be loaded simultaneously. Each gets a unique `acco --- -*Last updated: v1.10.5 — 2026-11-02 (no section changes: Import Logs race fix; v1.10.4: §8, §13 single `~` is literal; §21 excerpts escape `~`; v1.10.3: §13 refusals; §21 declined runs; v1.10.2: §13 summary states its dates; §21 per-month derivations; v1.10.1: §13 `AI_MAX_TOKENS`, thinking and cut-off answers; v1.10.0: §21 AI Eval added; §13 `callClaude()` raw mode; v1.9.6: §14 folder access lasts until the last tab closes, not one page load; v1.9.5: §7 chart guard; v1.9.4: views-db.js changelog reads CRLF checkouts; v1.9.3: §14 folder permission: re-request on click, Reconnect banner, browser copy wins; v1.9.2: §0 branch, PR and approval workflow added; v1.9.1: §4.5 rehydrate transactions loaded from JSON; v1.9.0: §20 Data & Reset added; v1.8.1: §10 re-upload dedup rewritten for the occurrence-suffix fix; v1.8.0: AI Analysis restored with API-key and output hardening; `renderMarkdown()` added; `samples/` added; §1–3, §13, §14, §17 corrected to match the code)* +*Last updated: v2.0.3 — 2026-11-04 (§23 Hosting added; v1.10.5 — 2026-11-02: no section changes: Import Logs race fix; v1.10.4: §8, §13 single `~` is literal; §21 excerpts escape `~`; v1.10.3: §13 refusals; §21 declined runs; v1.10.2: §13 summary states its dates; §21 per-month derivations; v1.10.1: §13 `AI_MAX_TOKENS`, thinking and cut-off answers; v1.10.0: §21 AI Eval added; §13 `callClaude()` raw mode; v1.9.6: §14 folder access lasts until the last tab closes, not one page load; v1.9.5: §7 chart guard; v1.9.4: views-db.js changelog reads CRLF checkouts; v1.9.3: §14 folder permission: re-request on click, Reconnect banner, browser copy wins; v1.9.2: §0 branch, PR and approval workflow added; v1.9.1: §4.5 rehydrate transactions loaded from JSON; v1.9.0: §20 Data & Reset added; v1.8.1: §10 re-upload dedup rewritten for the occurrence-suffix fix; v1.8.0: AI Analysis restored with API-key and output hardening; `renderMarkdown()` added; `samples/` added; §1–3, §13, §14, §17 corrected to match the code)* --- @@ -883,3 +883,18 @@ A developer-only view (`showView('ai-eval')`) that measures how well AI Analysis - **Publishing a new run:** move the current `docs/EVAL.md` and `docs/eval-results.json` to `docs/eval-runs/v/` unchanged except for a one-line "Archived" banner, its JSON link label, and relative links the move would break (`eval-runs/vX/…` becomes `../vX/…`). Put the new results JSON in `docs/`, generate EVAL.md by loading it in the view (**Load results JSON** → **Download EVAL.md**), then add the hand-written sections before *Method*: the **Runs** table (one column per run: `max_tokens`, cut-off answers, tokens, figures, grounded, derived, traceable, unsupported), what changed between runs, and *Changes made after the run*. Keep README's Evaluation numbers in step. - **Changing the matcher after a run:** fix only bugs against the method EVAL.md states. Record each fix in EVAL.md's "Changes made after the run" with before and after numbers. Never add a rule just because it raises the score on answers you've already seen. - **Classification** (`classifyText()`): grounded → explicit equation (a wrong one is a math error) → standard derivations (`_candidates()`, each with context keys) → restatements, correct equations and same-line arithmetic on anchored figures → forecast (the 12-month prediction prompt only) or unsupported. When adding a derivation, give it context keys; check the chance-match rate in the report doesn't rise noticeably — it is the matcher's false-positive rate and is published alongside the headline. + +--- + +## 23. Hosting (GitHub Pages) + +> §23, not §22: the redesign stack (#16–#51) adds §22 Migrations. + +FinLens is published as static files by `.github/workflows/pages.yml` on every push to `master`. Pull requests never deploy. + +- **What's served:** `index.html`, `js/` and `samples/` only. `docs/`, `CLAUDE.md`, tests and CI files stay in the repo but aren't published. The build refuses to publish if a `finlens-state*.json`, export or `data/` file ends up in the site folder. +- **Nothing about the data changes.** Pages only serves the code. Transactions, settings and the API key stay in the visitor's browser and folder, as in §4.5 and §14. +- **One site per origin.** Browsers keep IndexedDB and localStorage per origin (scheme + host + port), not per path. All Pages project sites of one account share `https://.github.io`, so any other repo published there could read FinLens's data. Until FinLens has its own domain, **publish no other Pages site from this account**. +- **Custom domain:** set it on this repo (Settings → Pages), not on a `.github.io` user-site repo, and verify it in the account settings. With an Actions deploy no `CNAME` file is needed. Moving to a new domain is a new origin, so browser data starts empty there: users reconnect their folder or re-import once. +- **No custom headers.** Pages can't send HTTP headers, so the Content Security Policy must stay a `` tag, and `frame-ancestors` (which only works as a header) isn't available. +- **The File System Access API works there**, because Pages is served over HTTPS (a secure context). diff --git a/README.md b/README.md index 1cd3fc5..4201e68 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > A zero-install, browser-native finance dashboard. Drop in your bank CSVs, get instant clarity on your money. -**Version:** v1.10.5  ·  **Stack:** Vanilla JS, HTML, CSS  ·  **Install:** None +**Version:** v2.0.3  ·  **Stack:** Vanilla JS, HTML, CSS  ·  **Install:** None --- @@ -260,4 +260,4 @@ See [CHANGELOG.md](CHANGELOG.md) for the full release history. --- -*FinLens v1.10.5 — Built for one person's finances, designed to be useful for anyone's.* +*FinLens v2.0.3 — Built for one person's finances, designed to be useful for anyone's.* diff --git a/index.html b/index.html index ee48405..e5e2b5c 100644 --- a/index.html +++ b/index.html @@ -326,7 +326,7 @@
⚙️ Settings
diff --git a/js/views-settings.js b/js/views-settings.js index 6f7d389..548313e 100644 --- a/js/views-settings.js +++ b/js/views-settings.js @@ -49,7 +49,7 @@ function _renderGeneralSettings(root) { -
FinLens v1.10.5 ·${State.transactions.length} transactions loaded${State.lastRefresh?' · Refreshed '+dayjs(State.lastRefresh).format('MMM D, YYYY h:mm A'):''}
`; +
FinLens v2.0.3 ·${State.transactions.length} transactions loaded${State.lastRefresh?' · Refreshed '+dayjs(State.lastRefresh).format('MMM D, YYYY h:mm A'):''}
`; root.appendChild(displayCard); /* ---- Anthropic API Key ---- */