# YNAB *Web-hosted admin dashboard that imports Amazon receipts from Gmail, matches and categorizes them (with AI), and updates YNAB — served at lucaslongo.com/ynab. The product focus is the hosted Gmail → YNAB flow plus unattended MCP automation.* ## Current focus - Safer Gmail receipt → YNAB charge matching (global assignment, unique amounts) (#578) ## Next up - [ ] Add fixtures when live Gmail emails fail to parse - [ ] Validate new matcher on a full production scan pass ## Last touched - 2026-07-10 — AI chain drops defunded gemini/openai; Claude shortcuts resolve to current models instead of retired ones (#640) - 2026-07-10 — Verified GMAIL_REFRESH_TOKEN: OAuth refresh + Gmail list Amazon OK; root .env synced from Secret Manager (#551) - 2026-07-10 — Doc audit: README caught up to the merged Scan Gmail UI and BRAIN.md as canonical memory; sentinel-string and lockfile invariants written down (#582) - 2026-07-10 — Safer global Gmail–Amazon charge matching #578 - 2026-07-09 — Re-authorized Gmail OAuth; local .env + Secret Manager + Cloud Run rebound (#551) - 2026-07-08 — Hardened transaction_review_state: zombie cleanup on sync/reset/review load, mutation matrix documented, tests, refs #509 - 2026-06-27 — Stopped the activity popover from being wiped after a Gmail scan: the post-scan reload now uses a quiet mode so the summary stays until dismissed (refs #375). - 2026-06-27 — Fixed the Gmail scan silently failing on production: the NDJSON parser swallowed server-sent errors; failures like an expired refresh token now surface in the activity log (refs #375). - 2026-06-21 — Added a dedicated resizable New memo column to the review table when Gmail scan data is present; the Memo column always renders plain YNAB text (refs #309). - 2026-06-21 — Replaced the pinned bottom scan strip with a closable activity popover and made its log human-readable by rewriting Gmail query syntax into plain language (refs #331). ## Blockers - Official Amazon export is async (1–3 days) ## Open questions ## Ideas - "Freeze" command to snapshot the DB before bulk operations - Surface all-time stats on fixes pushed back to YNAB ## Notes - **Web-hosted product** — canonical experience at `https://lucaslongo.com/ynab/` (blog admin login, GCS-persisted `ynab/ynab.db` via `src/gcs-persist.ts`). The monorepo dev mount at `http://localhost:3000/ynab/` is for developing/testing the web app (same code). Local SQLite files are only for dev sessions. - **Primary flow** — Gmail receipt import (Scan Gmail), amount/date matching, AI categorization against your own budget categories, rich memos, review, and push back to YNAB. - **Unattended sync** — scheduled Gmail MCP + YNAB MCP (`AMAZON-GMAIL-YNAB-SYNC.md`, `npm run mcp:ynab`). Stateless/direct to YNAB API (no SQLite). Legacy `ynab-sync` skill is deprecated — prefer MCP. - Legacy Mac tools (Playwright Amazon scrape, sweep scripts) are deprioritized; Gmail path is preferred. - Gmail OAuth (one-time): `npm run oauth:gmail` (listener on 127.0.0.1:8080). - Env: YNAB + Gmail + AI keys in monorepo root `.env`; production binds `YNAB_API_KEY` + `GMAIL_*` from Secret Manager. Every staged change is reversible (`pending_ynab_updates`). See `README.md`. - Dep changes here MUST regenerate projects/ynab/package-lock.json — the root Dockerfile runs `npm ci` in this dir on every site deploy and PR CI does not check sub-project lockfiles, so drift breaks the whole-site deploy (#347/#349).