AI-Powered Expense Tracker — Go + HTMX + SQLite
Find a file
2026-07-14 13:48:31 +00:00
contrib chore: rebrand ReceiptNext to NextExpense 2026-06-21 18:39:48 +00:00
internal feat: PDF — total claim in header, wider merchant column (52mm) 2026-07-14 13:48:31 +00:00
static feat: add month hierarchy, AI categories, and UI polish 2026-07-14 09:29:26 +00:00
templates fix: remove nested #receipt-form wrapper causing duplicate IDs on edit 2026-07-14 11:33:24 +00:00
.env.example chore: rebrand ReceiptNext to NextExpense 2026-06-21 18:39:48 +00:00
.gitignore fix: bump upload limit to 11MB, add .gitignore for build artifacts 2026-07-14 10:40:49 +00:00
build-all.sh chore: rename binary from receiptnext to app 2026-05-30 15:53:24 +00:00
go.mod chore: rebrand ReceiptNext to NextExpense 2026-06-21 18:39:48 +00:00
go.sum chore: resize receipt images on upload (max 2048px, JPEG 85%) to prevent SMTP attachment size rejections 2026-06-17 11:50:46 +00:00
install.sh chore: install.sh with --install/--update/--remove flags, help, update README 2026-07-14 10:09:50 +00:00
main.go fix: bump upload limit to 11MB, add .gitignore for build artifacts 2026-07-14 10:40:49 +00:00
Makefile chore: rebrand ReceiptNext to NextExpense 2026-06-21 18:39:48 +00:00
README.md fix: correct curl pipe syntax in README 2026-07-14 10:11:28 +00:00

NextExpense — AI-Powered Expense Tracker

A production-ready, mobile-first Progressive Web App (PWA) for expense management with passwordless OTP login, AI receipt extraction (Gemini / OpenAI-compatible), and CSV/PDF email reporting with receipt images.

Tech Stack: Go 1.23+ · HTMX · SQLite (pure Go) · Google Gemini / OpenAI · PWA


🚀 One-Command Install

curl -fsSL https://git.lohmar.co.uk/cclohmar/NextExpense/raw/branch/main/install.sh | bash -s -- --install

Or from a local clone:

./install.sh --install

Running without flags shows help:

./install.sh          # Show help
./install.sh --help   # Same

The installer will:

  1. Clone the repo to /opt/nextexpense/

  2. Build the binary (pure Go, no CGO, no dependencies)

  3. Ask which AI provider to use:

    1) Google Gemini  (cloud API, needs API key)
    2) OpenAI / Compatible  (OpenAI, Perplexity, Groq, etc.)
    
  4. Prompt for SMTP settings (for OTP emails and report delivery)

  5. Create /opt/nextexpense/.env with all configuration

  6. Set up a systemd service that auto-starts on boot

  7. Start NextExpense

Result: A fully configured, always-running expense tracker at http://YOUR_SERVER:8080.


🔄 Updating

./install.sh --update

Update pulls the latest code, copies updated templates/static, rebuilds the binary, automatically backs up the database, and restarts the service.

🗑️ Uninstalling

./install.sh --remove

Stops the service, removes the systemd unit, and deletes /opt/nextexpense/ (asks for confirmation).


🔧 Building from Source (install.sh does this automatically)

The installer automatically installs Go (if missing) and builds from source.
No pre-built binaries are distributed — building from source guarantees the latest code compiled for your exact platform.

Manual Build

git clone https://git.lohmar.co.uk/cclohmar/NextExpense.git
cd NextExpense

# Build for your current platform
CGO_ENABLED=0 go build -buildvcs=false -ldflags="-s -w" -o app .

# Cross-compile for any platform (no extra tools needed!)
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -buildvcs=false -ldflags="-s -w" -o app-linux-arm64 .
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -buildvcs=false -ldflags="-s -w" -o app-darwin-amd64 .
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -buildvcs=false -ldflags="-s -w" -o app-darwin-arm64 .

The binary is fully static — zero runtime dependencies, no CGO, no libc.


⚙️ Configuration

Configuration is via environment variables in .env. The install script builds this for you interactively.

Variable Required Default Description
PORT No 8080 HTTP server port
BASE_URL No http://localhost:8080 Public URL for email links
AI Provider
AI_PROVIDER No gemini gemini or openai
GEMINI_API_KEY For Gemini Google Gemini API key
OPENAI_API_KEY For OpenAI API key (omit for Ollama via OpenAI compat)
AI_MODEL For OpenAI gpt-4o-mini Model name
AI_BASE_URL For OpenAI https://api.openai.com/v1 API endpoint
SMTP
SMTP_HOST See note SMTP server hostname
SMTP_PORT See note 587 SMTP server port
SMTP_USER See note SMTP username
SMTP_PASS See note SMTP password

Note: SMTP is optional — without it, OTP codes are logged to the server console for testing and reports cannot be emailed.


🚀 Usage

1. Start the Server

# If installed via systemd:
systemctl start nextexpense

# Or run directly:
./app

2. Open in Browser

Navigate to http://YOUR_SERVER:8080

3. Full Acceptance Flow

1. Enter your email → click "Send Verification Code"
2. Check your inbox (or server log) for the 6-digit OTP
3. Enter OTP → click "Verify Code"
4. Create a month (e.g. "July 2026") → click "Open"
5. Click "+ New" to add an event → set claim currency + conversion sample
6. Click "Open" on the event
7. Tap "📷 Camera" or "📁 Upload" to add a receipt
8. AI extracts amount, merchant, category, date → form is pre-filled
9. Click "Save Expense"
10. Back on the month view, click "Generate Monthly Report"
11. Monthly ZIP contains CSV + PDF report + all receipt images

📡 API Reference

Public

Method Path Description
GET / Landing page
POST /request-otp Request OTP code
POST /verify-otp Verify OTP and create session
POST /logout Clear session

Protected (requires session)

Method Path Description
GET /dashboard Month list
POST /months Create month
GET /months/{mid} View month + events
PUT /months/{mid} Update month
DELETE /months/{mid} Delete month
POST /months/{mid}/events Create event
PUT /months/{mid}/events/{eid} Update event
DELETE /months/{mid}/events/{eid} Delete event
GET /months/{mid}/events/{eid}/expenses View event + expenses
POST /months/{mid}/events/{eid}/generate Generate event report
POST /months/{mid}/generate Generate monthly report
POST /expenses/upload Upload receipt image/PDF
POST /expenses Save expense
GET /expenses/{id}/edit Get edit form
PUT /expenses/{id} Update expense
DELETE /expenses/{id} Delete expense

🏗️ Project Structure

/opt/nextexpense/
├── app                      # Compiled binary
├── .env                     # Configuration (optional)
├── backups/                 # Automatic DB backups (from -update)
├── templates/               # Go HTML templates
├── static/                  # CSS, icons, favicon, service worker
├── templates/               # Go HTML templates
├── static/                  # CSS, icons, favicon, service worker
│   ├── css/style.css
│   ├── favicon.svg          # Rx logo
│   ├── manifest.json
│   ├── sw.js
│   └── icons/
├── storage/                 # Uploaded receipt images (runtime)
├── install.sh               # Installer script
├── Makefile                 # Build targets
└── contrib/
    └── nextexpense.service  # Systemd service file

🧩 Features

🔐 Passwordless OTP Authentication

  • Email-based 6-digit code, 5-minute expiry
  • 3 failed attempts → 1-minute cooldown
  • HTTP-only session cookie, 24h TTL

🤖 AI Receipt Extraction

  • Google Gemini (default) — cloud vision API
  • OpenAI-compatible — works with OpenAI, Perplexity, Groq, Together AI, etc.
  • Supports: JPEG, PNG, WebP, HEIC, PDF (email receipts from Uber, etc.)

💱 Currency Conversion

  • Sample-based: enter a real receipt amount and what you were charged
  • System computes the rate automatically
  • Each expense stores original + converted amount

📧 Email Reporting

  • CSV or PDF report
  • Receipt images bundled as ZIP (expense-{event}-images.zip)
  • Filenames: expense-{event}-report.csv, expense-{event}-report.pdf
  • Item numbers match between report rows and ZIP images

📱 Progressive Web App

  • Installable on mobile home screen
  • Camera capture + gallery upload
  • Dark "Terminal Mint" theme (#0F172A base)
  • Rx favicon in emerald green

🗄️ Database

SQLite, auto-created on first run — 5 tables: users, auth_otps, months, events, expenses.


🔒 Security

Area Implementation
Sessions crypto/rand tokens, in-memory, 24h TTL
OTP crypto/rand codes, 5min expiry, lockout after 3 failures
Cookies HTTP-only, SameSite=Lax, path-restricted
SQL Parameterized queries everywhere
Uploads Magic byte validation, max 10MB, UUID filenames
Config .env is optional — app runs with defaults if absent

Built with Go, HTMX, SQLite and ❤️