- Rename Go module from github.com/cclohmar/ReceiptNext to NextExpense - Update all import paths across 7 Go source files - Update templates (titles, headings, branding) - Update static files (manifest.json, sw.js, CSS) - Update config (Makefile, install.sh, .env.example) - Update README with new name and URLs - Rename service file receiptnext.service -> nextexpense.service - Update install paths, service names, log paths in install.sh |
||
|---|---|---|
| contrib | ||
| internal | ||
| static | ||
| templates | ||
| .env.example | ||
| .gitignore | ||
| build-all.sh | ||
| go.mod | ||
| go.sum | ||
| install.sh | ||
| main.go | ||
| Makefile | ||
| README.md | ||
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
bash -c "$(curl -fsSL https://git.lohmar.co.uk/cclohmar/NextExpense/raw/branch/main/install.sh)"
Or from a local clone:
./install.sh
The installer will:
-
Clone the repo to
/opt/nextexpense/ -
Build the binary (pure Go, no CGO, no dependencies)
-
Ask which AI provider to use:
1) Google Gemini (cloud API, needs API key) 2) OpenAI / Compatible (OpenAI, Perplexity, Groq, etc.) -
Prompt for SMTP settings (for OTP emails and report delivery)
-
Create
/opt/nextexpense/.envwith all configuration -
Set up a systemd service that auto-starts on boot
-
Start NextExpense
Result: A fully configured, always-running expense tracker at http://YOUR_SERVER:8080.
🔄 Updating
bash /opt/nextexpense/install.sh -update
Update pulls the latest code, copies updated templates/static, rebuilds the binary, automatically backs up the database, and restarts the service.
🔧 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. Click "+ New" → name your event → set claim currency → enter a conversion sample
5. Click "Open" on the event
6. Tap "📷 Camera" or "📁 Upload" to add a receipt
7. AI extracts amount, merchant, category, date → form is pre-filled
8. Click "Save Expense"
9. Click "Submit Event" → enter recipient email → choose CSV or PDF
10. Report + receipt images ZIP are emailed → event auto-closes
11. Click "Reopen" to add more receipts
📡 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 |
Event list |
POST |
/events |
Create event |
GET |
/events/{id}/expenses |
View event + expenses |
PUT |
/events/{id}/reopen |
Reopen closed event |
POST |
/expenses/upload |
Upload receipt image/PDF |
POST |
/expenses |
Save expense |
GET |
/expenses/{id}/edit |
Get edit form |
PUT |
/expenses/{id} |
Update expense |
POST |
/events/{id}/file |
File report (CSV/PDF + images ZIP) |
🏗️ 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 (
#0F172Abase) - Rx favicon in emerald green
🗄️ Database
SQLite, auto-created on first run — 4 tables: users, auth_otps, 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 ❤️