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>
The previous commit had the model changes but the database wasn't
properly migrated. This commit adds the missing migrations to make
TransactionId nullable in the Receipts table.
Changes:
- Updated MoneyMapContext to make Transaction relationship optional
for Receipt (IsRequired(false))
- Created additional migrations to properly handle:
- Making TransactionId column nullable
- Updating the unique index to handle NULL values with WHERE clause
- Applied all migrations to database successfully
The Receipts page should now work correctly for uploading unmapped
receipts without a TransactionId.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add explicit column type configuration for Confidence field to avoid
SQL Server truncation warnings. Use decimal(5,4) to store values from
0.0000 to 1.0000 with 4 decimal places of precision.
Also add MaxLength constraint for CreatedBy field.
Migration applied successfully to database.
🤖 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>
Model Changes:
- Add Card.AccountId (nullable FK to Account)
- Add Card.Nickname field for friendly names
- Add Card.DisplayLabel computed property
- Add Account.Cards navigation property
- Add Account.DisplayLabel computed property
DbContext Updates:
- Configure Card → Account relationship (optional, restrict delete)
- Add index on Card.AccountId
- Set Card.Owner as required
Migration:
- Add LinkCardsToAccounts migration
- Adds AccountId and Nickname columns to Cards table
- Creates FK constraint from Cards to Accounts
This properly models the real-world relationship where payment cards
are linked to bank accounts (e.g., a Visa card draws from a checking
account, or a credit card is paid from a savings account).
🤖 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>