Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<user>.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 `<meta>` 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
Expand Down
19 changes: 17 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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)*

---

Expand Down Expand Up @@ -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<the old run's version>/` 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://<user>.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 `<user>.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 `<meta>` 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).
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 &nbsp;·&nbsp; **Stack:** Vanilla JS, HTML, CSS &nbsp;·&nbsp; **Install:** None
**Version:** v2.0.3 &nbsp;·&nbsp; **Stack:** Vanilla JS, HTML, CSS &nbsp;·&nbsp; **Install:** None

---

Expand Down Expand Up @@ -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.*
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@
<div style="margin-top:auto">
<a class="nav" data-view="settings">⚙️ Settings</a>
<div class="footer">
<div style="color:var(--text-3);font-size:11px">v1.10.5 · FinLens</div>
<div style="color:var(--text-3);font-size:11px">v2.0.3 · FinLens</div>
</div>
</div>
</aside>
Expand Down
2 changes: 1 addition & 1 deletion js/views-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function _renderGeneralSettings(root) {
</select>
</div>
</div>
<div class="muted" style="font-size:11.5px;margin-top:14px">FinLens v1.10.5 ·${State.transactions.length} transactions loaded${State.lastRefresh?' · Refreshed '+dayjs(State.lastRefresh).format('MMM D, YYYY h:mm A'):''}</div>`;
<div class="muted" style="font-size:11.5px;margin-top:14px">FinLens v2.0.3 ·${State.transactions.length} transactions loaded${State.lastRefresh?' · Refreshed '+dayjs(State.lastRefresh).format('MMM D, YYYY h:mm A'):''}</div>`;
root.appendChild(displayCard);

/* ---- Anthropic API Key ---- */
Expand Down