Rename to reflect multi-provider support (OpenAI + Anthropic):
- Rename Services/OpenAIReceiptParser.cs to Services/AIReceiptParser.cs
- Update class name from OpenAIReceiptParser to AIReceiptParser
- Update DI registration in Program.cs
The parser now supports both OpenAI and Anthropic models, so the more generic name better reflects its capabilities.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This refactors the merchant field from a simple string column to a normalized
entity with proper foreign key relationships:
**Database Changes:**
- Created Merchant entity/table with unique Name constraint
- Replaced Transaction.Merchant (string) with Transaction.MerchantId (FK)
- Replaced CategoryMapping.Merchant (string) with CategoryMapping.MerchantId (FK)
- Added proper foreign key constraints with SET NULL on delete
- Added indexes on MerchantId columns for performance
**Backend Changes:**
- Created MerchantService for finding/creating merchants
- Updated CategorizationResult to return MerchantId instead of merchant name
- Modified TransactionCategorizer to return MerchantId from pattern matches
- Updated Upload, Recategorize, and CategoryMappings to use merchant service
- Updated OpenAIReceiptParser to create/link merchants from parsed receipts
- Registered IMerchantService in dependency injection
**UI Changes:**
- Updated CategoryMappings UI to handle merchant entities (display as Merchant.Name)
- Updated Transactions page merchant filter to query by merchant entity
- Modified category mapping add/edit/import to create merchants on-the-fly
- Updated JavaScript to pass merchant names for edit modal
**Migration:**
- ConvertMerchantToEntity migration handles schema conversion
- Drops old string columns and creates new FK relationships
- All existing merchant data is lost (acceptable for this refactoring)
**Benefits:**
- Database normalization - merchants stored once, referenced many times
- Referential integrity with foreign keys
- Easier merchant management (rename once, updates everywhere)
- Foundation for future merchant features (logos, categories, etc.)
- Improved query performance with proper indexes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This feature enables easy filtering and identification of transactions by merchant name:
- Added Merchant column to Transaction model (nullable, max 100 chars)
- Added Merchant field to CategoryMapping model
- Modified ITransactionCategorizer to return CategorizationResult (category + merchant)
- Updated auto-categorization logic to assign merchant from category mappings
- Updated category mappings UI to include merchant field in add/edit forms
- Added merchant filter dropdown to transactions page with full pagination support
- Updated receipt parser to set transaction merchant from parsed receipt data
- Created two database migrations for the schema changes
- Updated helper methods to support merchant names in default mappings
Benefits:
- Consistent merchant naming across variant patterns (e.g., "Walmart" for all "WAL-MART*" patterns)
- Easy filtering by merchant on transactions page
- No CSV changes required - merchant is derived from category mapping patterns
- Receipt parsing can also populate merchant field automatically
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Optimize duplicate detection to only query existing transactions within the date range of the uploaded CSV file (plus 1-day buffer). This prevents loading the entire transaction history into memory when checking duplicates.
For example, uploading 2800 transactions from Jan-Mar 2024 will now only load existing transactions from that period rather than all historical transactions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Improve performance when uploading thousands of transactions by loading all existing transactions into memory once for duplicate detection, rather than running individual database queries for each transaction. This reduces database calls from O(n) to O(1) for n transactions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed the card resolution logic to check transaction memos first
before falling back to the CSV filename. This enables per-transaction
card detection when account CSVs contain card identifiers in memos
(e.g., "usbank.com.2765").
Also prioritize card matches over account matches in TryResolveByLast4
to ensure cards are correctly identified even when they share the same
last4 digits as their linked account.
This fixes the issue where card dropdowns showed "none / direct debit"
even when card information was present in transaction memos.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Schema Changes:
- Add Account model (Institution, AccountType enum, Last4, Owner, Nickname)
- Add Transfer model for tracking money movement between accounts
- Update Transaction to support both CardId and AccountId (nullable FKs)
- Rename Transaction.CardLast4 → Last4 (works for both cards and accounts)
- Add PaymentMethodLabel computed property to Transaction
- Create EF Core migration: SplitCardsAndAccounts
Data Model Improvements:
- Accounts: Checking, Savings, Other types
- Transfers: Source/Destination accounts, optional link to original transaction
- Transactions can now link to either a Card OR an Account
- Transfer categories excluded from spending reports via TransactionFilters
UI Pages:
- Add Accounts.cshtml - List all bank accounts with transaction counts
- Add EditAccount.cshtml - Create/edit bank accounts
- Add Accounts link to navigation
- Update all references from CardLast4 to Last4
Service Layer Updates:
- Update CardResolutionResult to use nullable CardId and renamed Last4
- Update TransactionKey record to include AccountId
- Update IsDuplicate check to include both CardId and AccountId
- Update all PaymentMethodLabel usage across pages
This architecture allows proper separation of credit cards from bank
accounts and enables tracking of transfers between accounts without
double-counting in spending reports.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>