Document AI tool-use framework, receipt parse queue system, background
worker, bulk upload, ParseStatus enum, and updated AIReceiptParser flow
with tool-aware vs enriched-prompt paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change receipt storage to \TRUENAS\receipts, Kestrel port to 5005,
and add AI section with ModelsEndpoint and default ReceiptParsingModel.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Transactions page now defaults to last 30 days when no date filters are
set. ViewReceipt page adds collapsible raw LLM response payload on
parse logs for debugging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add error message alert for failed proposal applications. Derive AI
provider name from model prefix instead of separate config key.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split proposals into High Confidence / Needs Review tabs. Extract
proposal table into _ProposalTable partial view. Show rule status
(Create/Update/Exists) based on existing category mappings. Persist
proposals in hidden form field to survive app restarts. Add per-tab
select-all and improved error reporting on apply.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Categorizer now pre-fetches existing rules and includes matching rules
in prompts so the AI respects established mappings. Unified model
routing via CallModelAsync replaces separate provider branching.
Improved pattern instructions require exact transaction name substrings.
Add rule update support (RuleUpdated) when a pattern exists with a
different category.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ReceiptQueue page with tabbed dashboard (queued/completed/failed),
AJAX polling for live status updates, and per-receipt retry. Update
Receipts page with multi-file upload modal, file preview, upload
spinner, and bulk retry for failed parses.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ReceiptParseQueue (Channel-based singleton) and
ReceiptParseWorkerService (BackgroundService) for sequential receipt
parsing. Replaces fire-and-forget Task.Run with a proper queue.
ReceiptManager now enqueues uploaded receipts and supports bulk upload
via UploadManyUnmappedReceiptsAsync. Worker recovers pending items on
startup. Register IAIToolExecutor and IAIVisionClientResolver in DI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ParseStatus field to Receipt model with states: NotRequested,
Queued, Parsing, Completed, Failed. Includes indexed column and EF Core
migration for tracking receipt parse queue progress.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AIReceiptParser now routes to tool-aware or standard vision clients.
Tool-capable models (OpenAI, Claude, LlamaCpp) call search_categories,
search_transactions, and search_merchants during parsing. Ollama gets
pre-fetched DB context injected into the prompt. Adds suggestedCategory
and suggestedTransactionId fields with AI-driven transaction mapping.
Includes NullableLongConverter for resilient JSON deserialization and
restructured receipt prompt with strict field types.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add IAIToolAwareVisionClient interface and OpenAIToolUseHelper for
function-calling via /v1/chat/completions. OpenAI and LlamaCpp clients
now support multi-round tool calls, letting the AI query the database
during receipt image analysis.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce provider-agnostic tool definitions (AIToolRegistry) and an
executor (AIToolExecutor) that lets AI models query MoneyMap's database
during receipt parsing via search_categories, search_transactions, and
search_merchants tools. Includes an enriched-context fallback for
providers that don't support function calling (Ollama).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Store user-provided parsing notes in the database so they persist
across parsing attempts. Notes are displayed in Receipt Information
and pre-populated in the textarea for future parses.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Settings page for AI model selection with load status indicators
- Add ModelWarmupService to preload configured model on app startup
- Consolidate AI model config to single AI:ReceiptParsingModel setting
- Simplify ViewReceipt and AICategorizePreview to use Settings model
- Improve AI categorization confidence prompt for varied scores
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Simplify model dropdown to single flat list with local models first
- Show loaded/unloaded status with bullet indicators
- Remove separate Ollama:BaseUrl and LlamaCpp:BaseUrl configs
- All AI vision clients now use AI:ModelsEndpoint (default: athena.lan:11434)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enhance receipt parsing model selection:
- Fetch available models from LlamaCpp server dynamically
- Show loaded/unloaded status in model dropdown
- Persist selected model to appsettings.json
- Read default model from AI:ReceiptParsingModel config
- Inject LlamaCppVisionClient and IConfiguration dependencies
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Switch from cookie-based to session-based TempData to avoid
cookie size limits when storing AI categorization proposals.
Chain AddSessionStateTempDataProvider() to AddRazorPages().
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new card for AI categorization alongside rule-based:
- Rename existing section to "Rule-Based Categorization"
- Add "AI-Powered Categorization" section with provider badge
- Link to AICategorizePreview for AI category suggestions
- Display explanation of how AI categorization works
- Inject IConfiguration to read AI provider setting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add selection UI to Transactions page:
- Add checkbox column for selecting transactions
- Add sticky selection bar showing selected count
- Add Select All / Clear Selection controls
- Wire up form to send selected IDs to AICategorizePreview page
- Preserve row click navigation for unselected areas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enhance AI categorization with multi-provider support:
- Add configurable AI:CategorizationProvider setting (OpenAI/LlamaCpp)
- Add CallLlamaCppAsync() for local LLM categorization
- Improve prompt with existing categories for consistency
- Include additional transaction context (card, account, transfer info)
- Fix batch processing to avoid DbContext concurrency issues
- Add model parameter to interface methods
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add GetAvailableModelsAsync() to LlamaCppVisionClient that:
- Queries llama.cpp /v1/models endpoint for available models
- Filters out multimodal projector models (mmproj-*)
- Tracks loaded/unloaded status for each model
- Returns sorted list with loaded models first
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add new page that allows users to:
- Generate AI categorization suggestions for uncategorized transactions
- Review proposals with confidence levels before applying
- Select specific transactions from Transactions page for AI review
- Choose to create mapping rules for high-confidence matches
- Support both OpenAI and LlamaCpp providers with model selection
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Store only filename in database instead of full relative path.
GetReceiptPhysicalPath now combines config base path with filename.
AIReceiptParser uses ReceiptManager for consistent path resolution.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New page shows unmapped receipts with scored transaction candidates,
allowing manual mapping or bulk auto-map. Displays confidence scores
and match quality indicators. Also shows recently mapped receipts
for verification with unmap option.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace simple matching with weighted scoring algorithm (40% amount,
25% date, 35% merchant, 10% due date). Uses confidence thresholds:
- 85%+ auto-maps immediately
- 50-85% uses LLM to decide
- Below 50% returns candidates for manual review
Transactions can no longer match before receipt date since receipts
are issued at time of purchase.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add LlamaCppVisionClient and OllamaVisionClient for local AI inference
as alternatives to OpenAI and Claude. Includes text-only prompt support
for LLM-assisted receipt matching.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add documentation for:
- FinancialAuditService responsibilities and methods
- Audit flag types and severities
- /api/audit endpoint with query parameters and response
- Version bump to 1.4 with recent changes section
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Improves readability of percentage text when progress bar
is in warning state (80-99% of budget used).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prevents form submission with empty pattern, keeping modal open
for validation instead of closing and showing error after redirect.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Budget model with Weekly/Monthly/Yearly periods
- BudgetService for CRUD and spending calculations
- New /Budgets page for managing budgets
- Dashboard integration with progress bars
- Support for category-specific or total spending budgets
- Period boundaries calculated from budget start date
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add RunningBalance to SpendTrends model
- Calculate cumulative balance over 30 days
- Display as smooth filled line chart (neutral blue)
- Cleaner date labels (MMM d format)
- Better tooltip formatting with $ values
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Enable data-bs-theme="dark" on html element
- Update navbar to dark variant
- Replace text-dark links with text-body (theme-aware)
- Replace bg-white/bg-light with bg-body/bg-body-secondary
- Update sticky table headers to dark theme
- Fix Chart.js legend and axis colors for dark backgrounds
- Adjust focus ring color for better visibility on dark
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use environment variables in docker-compose for secrets/paths
- Add .env.example template for required variables
- Add .env to .gitignore to prevent secret exposure
- Add docker-build-and-push.cmd helper script
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add PageNumber and PageSize query parameters (default 25 per page)
- Implement server-side pagination with Skip/Take
- Display "Showing X-Y of Z" count in header
- Add Bootstrap pagination controls with sliding page window
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Dockerfile with multi-stage build for .NET 8
- Include ImageMagick dependencies for Magick.NET
- Add docker-compose.yml with volume mount for receipts
- Add .dockerignore to exclude build artifacts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Move the upload form from a card panel at the top of the page
to a modal triggered by an "Upload Receipt" button in the header.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add doughnut chart showing spending by category
- Fix search to use EF.Functions.Like for explicit case-insensitivity
- Include Chart.js CDN for chart rendering
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add AddMemoryCache() for TransactionCategorizer caching
- Register IPdfToImageConverter
- Register OpenAIVisionClient and ClaudeVisionClient with HttpClient
- Update AIReceiptParser registration to use scoped instead of HttpClient
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extract for better separation of concerns:
- Services/PdfToImageConverter.cs - PDF to image conversion using ImageMagick
- Services/AIVisionClient.cs - OpenAI and Claude vision API clients
- IAIVisionClient interface
- OpenAIVisionClient, ClaudeVisionClient implementations
AIReceiptParser now orchestrates using injected services.
Adds proper logging for auto-mapping operations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Move CategoryMapping class to Models/CategoryMapping.cs
- Add IMemoryCache with 10-minute TTL for category mappings
- Add InvalidateMappingsCache() method for cache invalidation
- Reduces repeated DB queries during bulk categorization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add ILogger for proper error logging
- Differentiate between HTTP, JSON parsing, and general errors
- Log errors with descriptive messages for debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- CardService.GetAllCardsWithStatsAsync: Use single query with Select projection
- AccountService.GetAccountDetailsAsync: Use single query with Select projection
- TransactionStatisticsService: Calculate stats at DB level, fix N+1 in GetCardStatsForAccountAsync
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added validation to prevent users from submitting the upload form without
selecting a file first. The preview button is now disabled by default and
only enables when a file is selected, improving user experience and
preventing empty form submissions.
Changes:
- Added IDs to file input and preview button
- Button starts in disabled state
- JavaScript listener enables button when file is selected
- Button disables again if file selection is cleared
Added wwwroot/receipts to compilation exclusions to prevent build warnings
and improve build performance. Receipt files are user-uploaded content and
should not be included in the build process.
Extracted all inline JavaScript from Razor pages into dedicated external
files for better code organization and browser caching:
- upload.js: transaction preview, pagination, form handling
- transactions.js: date range filters, Bootstrap tooltips
- edit-transaction.js: category/merchant dropdowns, copy functionality
- merchants.js: modal handling for merchant management
- category-mappings.js: modal handling for category rules
Updated all affected .cshtml files to reference external scripts instead
of inline script blocks. This improves maintainability, enables browser
caching, and provides better separation of concerns.
Removed unused using statements from page models and test files:
- Removed unused Microsoft.EntityFrameworkCore and MoneyMap.Data imports
- Removed redundant Xunit usings (already declared as global)
Fixes CS8019 and CS8933 hidden diagnostics.
Changed Receipt property from non-nullable (null!) to nullable (?) to properly
handle cases where receipt is not found. Fixes CS8601 null reference assignment
warning.
Removed async/await keywords from methods that don't perform any async
operations. The methods were triggering CS1998 warnings and running
synchronously despite being marked async.
Added validation to ensure messageContent is not null or whitespace before
deserializing JSON responses from OpenAI and Claude vision APIs. This fixes
CS8604 warnings about possible null reference arguments.
- Add hidden fields for immutable transaction properties to preserve values during form submission
- Make category field optional by removing validation for empty values
- Simplify category input handling by removing duplicate hidden field
- Clean up JavaScript by using proper element IDs instead of querySelector
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add auto-approve permissions for dotnet test, new, and add commands to support test-driven development workflow.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add unmap functionality to allow users to disassociate receipts from transactions without deleting them:
- ReceiptManager: Add UnmapReceiptAsync method
- Receipts page: Add OnPostUnmapAsync handler
- Receipts view: Add Unmap button for mapped receipts with confirmation dialog
This provides a non-destructive alternative to deleting receipts when they need to be remapped to different transactions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Document the expanded service layer architecture:
- Reorganize service layer diagram by functional groups (Core Transaction, Entity Management, Receipt, Reference & Dashboard)
- Add comprehensive documentation for AccountService, CardService, ReferenceDataService, and TransactionStatisticsService
- Update MerchantService documentation with new CRUD operations
- Document all DTOs and design patterns
Maintains architectural documentation consistency as the service layer continues to grow.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Refactor 7 PageModels to delegate business logic to services:
- AccountDetails: Use AccountService for account details retrieval
- Accounts: Use AccountService for listing and deletion
- Cards: Use CardService for listing and deletion
- EditTransaction: Use ReferenceDataService for dropdowns
- Merchants: Use MerchantService for CRUD operations
- Recategorize: Use ReferenceDataService and TransactionStatisticsService
- Transactions: Use ReferenceDataService and TransactionStatisticsService
Significantly simplifies PageModels (229 lines removed, 97 added) by extracting data access and business logic into testable services. Pages now focus solely on HTTP request/response handling.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extend MerchantService with additional operations:
- GetMerchantByIdAsync: Retrieve merchant with optional related data
- GetAllMerchantsWithStatsAsync: Get all merchants with transaction/mapping counts
- UpdateMerchantAsync: Update merchant name with duplicate validation
- DeleteMerchantAsync: Delete merchant (unlinks transactions and mappings)
Includes DTOs for merchant stats, update results, and delete results. Consolidates merchant management logic previously scattered across PageModels.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add four new services to extract business logic from PageModels:
- AccountService: Account retrieval, stats, and deletion with validation
- CardService: Card retrieval, stats, and deletion with validation
- ReferenceDataService: Centralized reference data for dropdowns (categories, merchants, cards, accounts)
- TransactionStatisticsService: Transaction statistics and aggregate calculations
All services follow the established service layer pattern with interfaces for DI and improved testability. Includes comprehensive DTOs for stats and validation results.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add auto-approve permissions for roslyn-bridge skill, curl commands, and dotnet build variants to improve Claude Code workflow efficiency.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Document TransactionService and ReceiptMatchingService in the architecture documentation, including their responsibilities, key methods, matching algorithms, and design patterns.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extract 140+ lines of receipt-to-transaction matching logic into ReceiptMatchingService. The PageModel now delegates matching to the service, simplifying the code and improving testability.
The matching algorithm (date filtering, merchant word-based scoring, amount tolerance) remains unchanged but is now centralized in a dedicated service.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace inline duplicate detection logic with TransactionService.IsDuplicateAsync(), consolidating duplicate checking into a single, testable service method. Removes duplicate IsDuplicate() method implementations from UploadModel.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add two new services to extract business logic from PageModels:
- TransactionService: Handles core transaction operations including duplicate detection, retrieval, and deletion
- ReceiptMatchingService: Implements intelligent receipt-to-transaction matching using date, merchant, and amount scoring
Both services follow the established service layer pattern with interfaces for dependency injection and improved testability.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add safer workflow for fixing incorrectly mapped receipts:
- Add OnPostUnmapReceiptAsync handler that sets TransactionId to null
- Add "Unmap" button (warning color) before Delete button
- Update Delete confirmation to emphasize PERMANENT deletion
- Unmap success message guides user to Receipts page
This prevents accidental loss of receipt files when users just want to remap them to a different transaction.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
Add Claude 3.5 Haiku and Sonnet as parsing options:
- Add Claude models to AI Model dropdown (Haiku for fast, Sonnet for best quality)
- Update OpenAIReceiptParser to detect provider based on model name (claude-* prefix)
- Add CallClaudeVisionAsync method using Anthropic Messages API
- Support ANTHROPIC_API_KEY environment variable or Anthropic:ApiKey config
- Parse logs now correctly show "Anthropic" or "OpenAI" as provider
- Both providers use the same prompt template and return structure
Users can now choose from 4 models:
- GPT-4o Mini (fast & cheap)
- GPT-4o (smarter)
- Claude 3.5 Haiku (fast)
- Claude 3.5 Sonnet (best quality)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major improvements to receipt parsing:
Voided Item Handling:
- Add Voided boolean field to ReceiptLineItem model and database
- Never skip any line items - include voided items with voided=true and lineTotal=0.00
- Strong parser hints: "CONTINUE reading", "do NOT stop parsing", "Read ENTIRE receipt"
- Ensures all items after void markers are captured
UPC/Barcode Extraction:
- Extract UPC codes (12-13 digits) and store in Sku field
- Enables price tracking over time even when descriptions change
Quantity Defaults:
- ALWAYS default to 1.0 for ALL retail products (groceries, goods, merchandise)
- Only use null for utility bills, service fees, or taxes
- Emphatic instructions: "MUST be 1.0", "do NOT leave it null"
- Prevents missing quantities on retail items
Model Selection:
- Add AI model dropdown in ViewReceipt UI (gpt-4o-mini vs gpt-4o)
- Update IReceiptParser interface to accept optional model parameter
- Pass selected model through to OpenAI API
- Store model name in parse logs for history tracking
- Allows using smarter model for complex receipts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Move hardcoded prompt from OpenAIReceiptParser.cs to Prompts/ReceiptParserPrompt.txt for easier maintenance and editing without recompilation. Add caching to LoadPromptTemplateAsync for performance. Configure .csproj to copy Prompts folder to output directory.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented word-based relevance scoring to intelligently sort transactions when multiple matches exist within the amount tolerance. The system now:
1. Splits receipt merchant name into words (handling spaces, dashes, underscores, dots)
2. Compares each word against transaction merchant name and transaction name
3. Scores based on matching word count (bidirectional substring matching)
4. Exact matches get highest priority (score 1000)
5. Word matches get scored (10 points per matching word)
6. Sorts by relevance score, then by date
Examples:
- Receipt "Duke Energy" matches "DUKE ENERGY CORPORATION" better than "WALMART"
- Receipt "McDonald's" matches "MCDONALD'S #12345" better than "BURGER KING"
- Receipt "Comcast" matches "COMCAST CABLE" better than "VERIZON"
This dramatically improves auto-mapping success rate and puts the most likely transaction at the top of the manual selection list.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed amount matching from a fixed ±$0.10 tolerance to a percentage-based ±10% tolerance. This dramatically narrows down the transaction list for manual mapping, often to just 1-2 transactions.
Changes:
- Manual mapping: Filters candidates to ±10% of receipt total
- Manual mapping: Green highlighting for very close matches (±2%)
- Auto-mapping: Uses same ±10% tolerance for filtering
- UI: Updated help text to explain the filtering
Example: A $100 receipt will only show transactions between $90-$110, making it much easier to find the correct match.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed bug where manual receipt mapping was only showing transactions near the due date instead of the full range from bill date to due date + 5 days. The issue was that we were taking only the top 100 most recent transactions before applying merchant relevance sorting, which cut off older transactions near the bill date.
Now the query retrieves ALL transactions within the date range (bill date to due date + 5), then sorts by merchant relevance and date. This ensures bills like electric bills show all transactions from the bill date through the payment date.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Receipts are now automatically parsed using OpenAI Vision API immediately after upload. The parsing runs in the background and triggers auto-mapping if successful. This streamlines the workflow - users just upload a receipt and it's automatically parsed and mapped to the matching transaction without any additional clicks.
The parsing happens asynchronously via Task.Run to not block the upload response. If parsing fails, the upload is still considered successful.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updated documentation to reflect v1.2 changes:
- Unmapped receipts with nullable TransactionId
- Duplicate detection with blocking modal
- Auto-mapping service with intelligent date range logic
- Due date support for bills (bill date to due date + 5 days)
- Enhanced manual mapping UI with transaction selector
- Transactions page improvements (search, filters, ID column)
- New Receipts page with comprehensive workflow
- Updated service layer, database schema, and workflows sections
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updated both auto-mapping and manual mapping logic to search for transactions from bill date to due date + 5 days. This accounts for auto-pay processing delays, weekends, and bank processing times when bills are auto-paid on the due date.
This fixes the issue where electric bills and other auto-paid utilities were missing their matching transactions because the payment posted a few days after the due date.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed "Upload CSV" from the main navigation menu and added an "Upload CSV" button to the Transactions page header. This makes CSV upload more contextual since it's primarily used when viewing/managing transactions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When opening the map receipt modal, the transaction list now automatically scrolls to center on the first green-highlighted amount match (if one exists). This makes it easier to quickly find and select the most likely matching transaction without having to manually scroll through the list.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Enhanced receipt parsing and mapping to support bills with due dates (like utility bills):
- Updated OpenAI prompt to extract due date from bills
- Added DueDate property to Receipt model with database migration
- Modified auto-mapping logic to use bill date to due date range when both dates are present
- For regular receipts without due dates, continues to use ±3 day window
- Updated manual mapping UI to display due dates and adjust date range explanation
- Receipt list now shows due dates in orange "Due:" text for clarity
This allows electric bills and similar documents with 20+ day payment windows to be properly matched to their payment transactions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added ID column as the first column in the transactions table to make it easy to reference transaction IDs when manually mapping receipts. The ID is displayed with a "#" prefix in a small, muted style.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed merchant filtering from exclusionary to relevance-based sorting.
This fixes the issue where transactions don't appear if the merchant
name doesn't exactly match.
Changes:
- Date range (±3 days) remains the primary hard filter
- Merchant name now sorts results by relevance instead of excluding
- Retrieves 100 candidates, sorts by match quality, returns top 50
- Case-insensitive matching using ToLower()
Relevance Scoring:
- Score 3: Exact match on merchant or transaction name
- Score 2: Partial match on merchant name (Contains)
- Score 1: Partial match on transaction name (Contains)
- Score 0: No match (still included if within date range)
Results sorted by: Match score → Date → ID
Benefits:
- McDonald's receipt will show all transactions in date range
- Best matches appear at top
- No transactions excluded due to name variations
- More forgiving for typos, abbreviations, etc.
- User can still see and select any transaction in date window
Example: Receipt says "McDonald's" but transaction says "MCDONALD'S #1234"
- Before: Excluded (no exact Contains match)
- After: Included, sorted to top (partial match score 2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed duplicate detection from informational alert to a modal dialog
that requires user decision before proceeding with upload.
Upload Flow Changes:
1. Initial upload detects duplicates and uploads temporarily
2. If duplicates found:
- Deletes the uploaded file
- Stores warnings and filename in TempData
- Redirects to show modal
3. Modal blocks with two options:
- Cancel: Don't upload (returns to page)
- Upload Anyway: Re-upload with confirmation flag
Modal Features:
- Non-dismissible (static backdrop, no keyboard close)
- Yellow warning header
- Table showing all potential duplicates with:
- Receipt ID and filename
- Upload timestamp
- Reason for match (hash/name+size)
- Transaction mapping status
- View button to compare
- Clear explanation of options
- Prompts user to re-select file for confirmed upload
Benefits:
- Prevents accidental duplicate uploads
- Forces user acknowledgment
- Provides context for decision-making
- Links to view existing receipts for comparison
- Better UX than passive alert banner
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed from using .ToHashSet() extension method (which may not be
available in some EF Core versions) to .ToListAsync() followed by
creating a HashSet from the list.
This ensures compatibility across different EF Core versions while
maintaining the same performance characteristics.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Enhanced the receipt mapping modal with intelligent transaction filtering
and a clean table-based selection interface.
Smart Filtering (per receipt):
- If receipt has a date: Show transactions within ±3 days
- If receipt has merchant: Filter by merchant name match
- Calculate amount matches (within $0.10 tolerance)
- Only show transactions without receipts
- Limit to 50 most recent matches
- Fallback to recent 50 transactions if no matches
UI Improvements:
- Replaced confusing listbox with formatted data table
- Proper column alignment with fixed widths
- Sticky header for scrollable table (max 400px height)
- Clickable rows with radio button selection
- Visual feedback:
- Green highlight for amount matches
- Blue highlight for selected row
- Hover effect on rows
- Context-aware helper text explaining filter criteria
- Shows which transactions match the receipt date range
Features:
- Click anywhere on row to select
- Radio buttons for explicit selection
- Hidden input field stores selected transaction ID
- Manual ID entry still available as fallback
- Clear visual indicators for best matches
This provides a much better UX for manual mapping by showing only
relevant transactions and making it easy to identify likely matches.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replaced the manual transaction ID input with a user-friendly
transaction selector dropdown in the map receipt modal.
Changes:
- Added RecentTransactions list to Receipts page model
- Load last 100 transactions without receipts for dropdown
- Updated modal dialog:
- Larger modal (modal-lg) for better visibility
- Multi-select dropdown showing formatted transaction details:
- Date | Amount | Name | (Merchant)
- Monospace font for aligned columns
- Size 10 to show multiple options at once
- Receipt info displayed in styled info box
- Manual ID input field as fallback option
- Link to Transactions page for finding IDs
- Two-way binding between selector and manual input
User Experience:
- Users can now visually browse and select transactions
- Transaction details are formatted for easy scanning
- Only shows transactions that don't already have receipts
- Fallback to manual ID entry for edge cases
- Receipt parsed data clearly displayed for comparison
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Renamed static factory method from 'MultipleMatches' to
'WithMultipleMatches' to avoid conflict with the 'MultipleMatches'
property in the same class.
This resolves the compilation error: "The type 'ReceiptAutoMapResult'
already contains a definition for 'MultipleMatches'".
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>