257 lines
8 KiB
Markdown
257 lines
8 KiB
Markdown
# 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
|
|
curl -fsSL https://git.lohmar.co.uk/cclohmar/NextExpense/raw/branch/main/install.sh | bash -s -- --install
|
|
```
|
|
|
|
Or from a local clone:
|
|
|
|
```bash
|
|
./install.sh --install
|
|
```
|
|
|
|
Running without flags shows help:
|
|
|
|
```bash
|
|
./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
|
|
|
|
```bash
|
|
./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
|
|
|
|
```bash
|
|
./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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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 ❤️*
|