Skip to content

feat: financial-event transaction deduplication engine#20

Open
alon710 wants to merge 13 commits into
Shaya16:mainfrom
alon710:alon710/transaction-dedup-engine
Open

feat: financial-event transaction deduplication engine#20
alon710 wants to merge 13 commits into
Shaya16:mainfrom
alon710:alon710/transaction-dedup-engine

Conversation

@alon710

@alon710 alon710 commented Jun 6, 2026

Copy link
Copy Markdown

Adds a Financial Event layer that groups duplicate cross-account representations of one real-world money movement (internal transfers, bank-side credit card bill payments, and ATM withdrawals) into auditable events with a canonical reporting row, confidence scoring, human-readable reasons, and lossless undo, generalizing the previous keyword-based kind-flipping into a tunable, reversible matching layer. The backend adds migration 022 (financial_events, event_members, match_settings, match_rules, additive transactions columns, a blocking index, and a spendable_transactions view), a pure unit-tested matching engine, the DB apply/list/confirm/reject layer, sync-flow wiring, and an events API; the UI adds a Transfer / Card payment badge on grouped transaction rows (en/he i18n), and a full design document is included under docs/. It stays backward compatible: the kind column, the existing exact dedup, and every reporting query are unchanged, and the migration produces zero reporting drift on upgrade. The full CI gate passes (format, typecheck, i18n, knip, react-doctor, 29 tests), and the matching DB lifecycle was separately verified end to end against the real code.

🤖 Generated with Claude Code

alon710 and others added 13 commits May 27, 2026 13:56
Adds a streaming /chat page that uses the same AI provider configured
for categorization (Claude or Ollama). The agent answers free-text
questions about the user's finances through tool calls that wrap
existing read-only DB queries (transactions, monthly summary, top
merchants, category breakdown). Page and sidebar entry are disabled
when no AI provider is configured.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Next.js 16 renames the Middleware file convention to Proxy. The build
emits a deprecation warning until the rename happens.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
refactor: rename middleware.ts to proxy.ts for Next.js 16
…endering

Adds persistent chat sessions backed by SQLite (migration 021), a session history
sidebar with rename and delete actions, AI-generated chat titles via a setChatTitle
tool, and markdown rendering for assistant responses using react-markdown.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(chat): AI chat agent with persistent sessions and tool-based data access
Bank-side credit card payments are tagged kind='transfer' by detectKind
but the transactions summary and list kind-filter used the raw
charged_amount sign, so transfers double-counted with individual card
line items in totals, top merchants, and the largest-expense widget.
Switch those queries to filter on kind, and backfill existing rows in a
new migration that reclassifies bank rows matching the credit-card
payment patterns.
…nting

fix(transactions): exclude credit card transfers from expense totals
* feat(ai): add Gemini as a third AI provider

Adds Google Gemini alongside Claude and Ollama for transaction
categorization. Uses @google/genai with gemini-2.5-flash and stores
the API key encrypted under provider-specific setting keys so it can
coexist with a Claude key. Wires the new option through the setup
wizard, settings page, factory, and i18n.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Add Gemini provider support

* refactor(ai): simplify Gemini provider changes

- always require a key on save and drop the leave-blank-to-keep-stored UX,
  removing the hasStoredKey helper, hasClaudeApiKey/hasGeminiApiKey flags,
  and the i18n hint pair this required
- extract shared parseCategorizationResponse used by ClaudeProvider and
  GeminiProvider
- merge ClaudeConfig and GeminiConfig in the setup wizard into a single
  ApiKeyConfig with a children slot for provider-specific extras
- dispatch friendlyAIError on the provider argument instead of cascading
  regex matches over raw error text
- drop redundant Gemini model whitelist checks in the factory and settings
  writer

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: pin PR target to upstream Shaya16/Spent

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: remove upstream PR target note from CLAUDE.md

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Adds .github/workflows/ci.yml that runs `bun run ci` on every PR + push
to main with fail-fast on five strict checks: Biome formatter, TypeScript,
@lingual/i18n-check (next-intl-recommended) for missing + orphan keys,
knip for dead code, react-compiler-healthcheck, and `bun test`.

Switches the toolchain to Bun: package-lock.json removed, bun.lock
committed, all `npm`/`node` shell-outs in scripts/ replaced with `bun`,
service installer cheat-sheets updated. Service templates (.plist,
.service, .vbs, .xml) unchanged since they invoke node + next directly.

Adds tooling configs (biome.jsonc, knip.json), a wrapper script for
i18n-check with documented dynamic-namespace and baseline-orphan
ignores, and one smoke test (src/server/lib/dedup.test.ts) so the test
gate is real. Applies a one-pass Biome formatter sweep across 110 files.

README, CLAUDE.md, and menubar/README.md updated to reflect bun
commands, new Requirements, CI badge, and the `bun run ci` workflow.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sync): show full provider error message in progress dialog

Truncating to 60 chars hid the actual failure reason. Wrap when the row
is in error state; keep truncation for non-error statuses.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(readme): refresh bank coverage, add chat feature, bump default model

Replaces the three-bank list with the full israeli-bank-scrapers roster
shipped enabled today. Documents the new /chat agent. Updates the
Claude default to claude-haiku-4-5-20251001 and refreshes the roadmap.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* fix(ai): support Gemini in chat and trim provider API keys

Gemini was wired into setup and categorization but never into the chat
model factory, so chat returned 400 "AI provider not configured" for
Gemini users. Add a gemini branch to createChatModel via @ai-sdk/google,
and trim Claude/Gemini keys before validating and saving.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(ui): point Star on GitHub link to alon710/Spent

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#13)

- i18n: serve every page under /en or /he via next-intl; the active
  locale comes from the URL plus the NEXT_LOCALE cookie (no database),
  defaulting to English. The proxy adds CSRF same-origin checks on /api.
- transactions: detect bank-side credit-card settlements, internal
  account-to-account transfers, and ATM withdrawals so they stop
  double-counting spend; add a "treat ATM withdrawals as transfers"
  setting.
- ui: add vertical spacing between sidebar items, plus broad pre-launch
  polish across components, docs, website, menubar, scripts, copy, and
  PWA icons/manifest.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Group duplicate cross-account representations of one real-world money
movement (internal transfers, bank-side credit card bill payments, ATM
withdrawals) into auditable Financial Events with a canonical row,
confidence scoring, human-readable match reasons, and lossless undo.
This generalizes the previous keyword-based kind-flipping into a tunable,
reversible matching layer while keeping the existing exact dedup, the
kind column, and every reporting query backward compatible.

Adds migration 022 (financial_events, event_members, match_settings,
match_rules, additive transactions columns, blocking index, and a
spendable_transactions view), a pure unit-tested matching engine, the
DB apply/list/confirm/reject layer, sync-flow wiring, an events API, a
transaction-list event badge, and a full design document.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant