# 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 ❤️*