|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +A Terminal User Interface (TUI) application for analyzing credit card statements. Built with Go and the Bubble Tea framework, it provides an interactive interface to browse statements and categorize transactions. Currently tested with HSBC Taiwan credit card statements. |
| 8 | + |
| 9 | +## Building and Running |
| 10 | + |
| 11 | +### Traditional Go Build |
| 12 | + |
| 13 | +```bash |
| 14 | +# Build the application |
| 15 | +go build -o statements |
| 16 | + |
| 17 | +# Run the application |
| 18 | +./statements <path-to-statementlist.json> |
| 19 | +``` |
| 20 | + |
| 21 | +### Nix Flakes |
| 22 | + |
| 23 | +The project includes a Nix flake for reproducible builds. Requires Nix with flakes enabled. |
| 24 | + |
| 25 | +```bash |
| 26 | +# Run directly |
| 27 | +nix run . -- <path-to-statementlist.json> |
| 28 | + |
| 29 | +# Build the application |
| 30 | +nix build |
| 31 | +./result/bin/statements <path-to-statementlist.json> |
| 32 | + |
| 33 | +# Enter development environment (provides Go 1.25, gopls, gotools, claude, git, jq) |
| 34 | +nix develop |
| 35 | + |
| 36 | +# Cross-platform builds |
| 37 | +nix build .#statements-linux-amd64 |
| 38 | +nix build .#statements-linux-arm64 |
| 39 | +nix build .#statements-darwin-amd64 |
| 40 | +nix build .#statements-darwin-arm64 |
| 41 | +nix build .#statements-windows-amd64 |
| 42 | +``` |
| 43 | + |
| 44 | +Note: The flake is configured to allow unfree packages (required for claude-code). |
| 45 | + |
| 46 | +## Architecture |
| 47 | + |
| 48 | +### Core Components |
| 49 | + |
| 50 | +The codebase is structured around three main files: |
| 51 | + |
| 52 | +- **types.go**: Defines the data model (`Transaction`, `Statement`, `CategorizedTransactions`) |
| 53 | +- **analyzer.go**: Transaction analysis logic including categorization, normalization, and data loading |
| 54 | +- **main.go**: TUI implementation using Bubble Tea framework (model, view, update pattern) |
| 55 | + |
| 56 | +### Data Flow |
| 57 | + |
| 58 | +1. JSON statements are loaded via `LoadStatements()` in analyzer.go |
| 59 | +2. Transactions are categorized by `CategorizeTransactions()` which: |
| 60 | + - Normalizes descriptions using `ToCDB()` (full-width to half-width character conversion) |
| 61 | + - Detects Apple Pay transactions and extracts card metadata |
| 62 | + - Categorizes transactions by type (Transport, Food, Shopping, Travel, Utilities, Other) |
| 63 | +3. The Bubble Tea model manages two views (Summary, Statements) with dual-panel layout |
| 64 | +4. The Statements view uses two Bubble Tea table components for navigation |
| 65 | + |
| 66 | +### Transaction Categorization System |
| 67 | + |
| 68 | +The categorization happens in two layers: |
| 69 | + |
| 70 | +1. **Payment Method Detection** (analyzer.go:124-159): Detects Apple Pay (`APE` prefix with card last 4 digits), PayPal, and foreign transaction fees |
| 71 | +2. **Merchant Category Detection** (analyzer.go:48-97): Uses prefix/substring matching to categorize by merchant type |
| 72 | + |
| 73 | +Each transaction gets: |
| 74 | +- A `NormalizedDescription` (half-width characters) |
| 75 | +- An `ApplePayCardLast4` field (if applicable) |
| 76 | +- A `Category` field (Transport/Food/Shopping/Travel/Utilities/Other) |
| 77 | + |
| 78 | +### View State Management |
| 79 | + |
| 80 | +The model tracks: |
| 81 | +- Current view mode (summary or statements) |
| 82 | +- Selected statement index |
| 83 | +- Sort mode (Date/Amount/Location/Category) |
| 84 | +- Category filter (All or specific category) |
| 85 | +- Focused table (statements or transactions) |
| 86 | + |
| 87 | +Key state update: `updateTransactionsTable()` (main.go:437-610) rebuilds the transaction table when: |
| 88 | +- Statement selection changes |
| 89 | +- Sort mode changes |
| 90 | +- Category filter changes |
| 91 | + |
| 92 | +### Foreign Transaction Fee Handling |
| 93 | + |
| 94 | +Foreign fees are aggregated and displayed as a single row per statement (main.go:446-462, 580-606). They are filtered out from regular transactions and summarized to avoid cluttering the transaction list. |
| 95 | + |
| 96 | +## Key Technical Details |
| 97 | + |
| 98 | +### Character Normalization |
| 99 | + |
| 100 | +The `ToCDB()` function (analyzer.go:24-38) converts full-width CJK characters to half-width for consistent string matching. This is critical for proper categorization of Chinese/Japanese merchant names. |
| 101 | + |
| 102 | +### Apple Pay Extraction |
| 103 | + |
| 104 | +Uses regex `^APE(\d{4})` to extract the last 4 digits of the card used for Apple Pay transactions. The clean description (without the APE prefix) is obtained via `GetCleanDescription()`. |
| 105 | + |
| 106 | +### Table Navigation |
| 107 | + |
| 108 | +Implements wrap-around navigation (main.go:256-312) - pressing up at the first item wraps to the last item, and vice versa. Also supports Home/End keys and Page Up/Down for quick navigation. |
| 109 | + |
| 110 | +### Dynamic Column Layout |
| 111 | + |
| 112 | +The transactions table adjusts columns based on the active category filter (main.go:502-523). When filtering by a specific category, the Category column is hidden to provide more space for the Description column. |
0 commit comments