AI-powered personal finance tracker built for the SFU Silly Hackerton 2026.
Upload a photo of your card statement and instantly see your expenses on a monthly calendar — powered by Google Gemini Vision AI.
- Upload one or multiple card statement photos at once
- Client-side image compression (5–10MB → ~1MB) before sending to AI
- Sequential processing with rate-limit protection between requests
- Google Gemini Vision reads dates, merchant names, and amounts automatically
- Supports TD Bank, RBC, BMO, Scotiabank, CIBC mobile app screenshots
- Strict prompt engineering ensures clean JSON output with zero hallucination (
temperature: 0) - Server-side API call — your API key is never exposed to the browser
- Every AI-parsed result goes through a review modal before saving
- Edit date, merchant, amount, type (expense/income), and category inline
- Delete individual rows you don't need
- Color-coded dots: 🔴 expense / 🟢 income
- Click any day to see transaction details
- Navigate months with previous/next arrows
- Monthly income vs expense totals
- Category breakdown with animated bar chart
- 12 spending categories across Fixed, Variable, and Others
- Detects your spending persona (The Foodie, The Retail Therapist, The Homebody, The Midnight Scroller, The Super Saver)
- Provides 3 key insights based on your actual data
- Recommends 3 actionable tips ranked by impact (High / Medium / Low)
- Estimates monthly savings potential
- Toggle between dark and light themes
- Platinum shimmer border effect on all cards
- Preference saved to localStorage
- All data saved to browser LocalStorage
- Persists across sessions with no backend or database needed
- Safe hydration prevents data wipe on page refresh
| Type | Categories |
|---|---|
| Fixed | Housing & Utilities, Insurance & Taxes, Telecom & Subscriptions, Loans & Debts |
| Variable | Food & Dining, Transportation, Shopping & Lifestyle, Culture & Leisure, Medical & Health, Gifts & Events |
| Others | Savings & Invest, Uncategorized |
git clone https://github.com/YOUR_USERNAME/expense-tracker.git
cd expense-tracker
npm installGet a free key at https://aistudio.google.com
cp .env.local.example .env.local
# Open .env.local and add:
# GEMINI_API_KEY=your_key_herenpm run dev
# Open http://localhost:3000Add GEMINI_API_KEY in Vercel → Settings → Environment Variables.
Your app will be live at a public URL — works on mobile browser with no app install needed.
| Layer | Tech |
|---|---|
| Framework | Next.js 14 (App Router) |
| Styling | Tailwind CSS |
| AI Vision | Google Gemini Vision (gemini-3.1-flash-image-preview) |
| AI Analysis | Google Gemini (gemini-3-pro-image-preview) |
| Image Compression | browser-image-compression |
| State Management | React Context + useReducer |
| Storage | Browser LocalStorage |
| Icons | Lucide React |
expense-tracker/
├── app/
│ ├── api/
│ │ ├── parse/route.js # Gemini Vision — image → transactions
│ │ └── analyze/route.js # Gemini — spending persona + recommendations
│ ├── layout.jsx # Theme + Transaction providers
│ ├── page.jsx # Main page
│ └── globals.css # Platinum shimmer effects
│
├── components/
│ ├── calendar/
│ │ ├── CalendarGrid.jsx # Monthly calendar grid
│ │ ├── DayCell.jsx # Individual day cell with dots + amount
│ │ ├── DayDetail.jsx # Transaction list for selected day
│ │ └── MonthSummary.jsx # Income/expense totals + category bar chart
│ ├── upload/
│ │ ├── UploadButton.jsx # Multi-file upload with progress bar
│ │ └── ReviewModal.jsx # AI result review + edit before saving
│ ├── shared/
│ │ ├── Button.jsx
│ │ ├── Modal.jsx
│ │ └── Badge.jsx # Category badge with color
│ └── analysis/
│ └── SpendingAnalysis.jsx # AI persona + recommendations UI
│
├── hooks/
│ ├── useTransactions.js # Selectors + monthly summary logic
│ └── useImageUpload.js # Compression + sequential multi-upload
│
├── services/
│ └── gemini.js # Prompt engineering (strict JSON output)
│
├── store/
│ ├── transactionStore.js # Global state with safe hydration
│ └── themeStore.js # Dark/light mode with localStorage
│
└── utils/
├── constants.js # Categories, colors, emoji, aliases
├── dateFormatter.js # Local timezone-safe date helpers
└── storage.js # LocalStorage read/write
| Bug | Fix |
|---|---|
| Data wiped on page refresh | hydrated ref prevents initial empty state save |
isToday wrong by 1 day |
Switched from UTC toISOString() to local date string |
Amounts showing as 97.39999... |
formatDollar() rounds all floats to 2 decimals |
| Category fallback mismatch | Unified "Other" → "Uncategorized" everywhere |
| Float accumulation in review form | Math.round() on all amount inputs |
No app install needed. Just open the URL on your phone browser:
- Tap Upload Card Statement
- Take a photo or pick from your gallery
- Review and confirm the parsed transactions
- See them on your calendar instantly