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>